使用 Linq to XML 处理父子关系的子项

发布于 2024-11-09 21:47:09 字数 4205 浏览 3 评论 0原文

我是新尝试学习 LINQ to XML 的人,但在“孩子”方面遇到了麻烦。我有一个有关文档信息的 XML 文件;每个文档都有一定数量的 INDEX 元素,如以下代码段所示:

<DOCUMENTCOLLECTION>
<DOCUMENT>
<FILE filename="Z:\Consulting\ConverterRun4\B0000001\Submission\D003688171.0001.tif" outputpath="Z:\Consulting\ConverterRun4\B0000001\Submission"/>
<ANNOTATION filename=""/>
<INDEX name="CAN(idmDocCustom4)" value=""/>
<INDEX name="Comment(idmComment)" value="GENERAL CORRESPONDENCE 11-6-96 TO 10-29-"/>
<INDEX name="DiagnosticID(idmDocCustom5)" value="983958-0006.MDB-2155504"/>
<INDEX name="Document Class(idmDocType)" value="Submission"/>
<INDEX name="Original File Name(idmDocOriginalFile)" value="40410.TIF"/>
<INDEX name="Title(idmName)" value="1997-12"/>
<FOLDER name="/Accreditation/NCACIHE/1997-12"/>
</DOCUMENT>
<DOCUMENT>

我只需要 INDEX 元素中的一些值 - 那些具有以下名称属性的值:

Comment(idmComment)
Document Class(idmDocType)
Title(idmName)

这是我迄今为止在测试中得到的:

namespace ConsoleApplication1
{
class DocMetaData
{
    public string Comment { get; set; }
    public string DocClass { get; set; }
    public string Title { get; set; }
    public string Folder { get; set; }
    public string File { get; set; }
}
class Program
{
     static void Main(string[] args)
    {
        XDocument xmlDoc = XDocument.Load(@"convert.B0000001.Submission.xml");
        List<DocMetaData> docList = 
        (from d in xmlDoc.Descendants("DOCUMENT")
            select new DocMetaData
            {
                Folder = d.Element("FOLDER").Attribute("name").Value,
                File = d.Element("FILE").Attribute("filename").Value,
        // need Comment, DocClass, Title from d.Element("INDEX").Attribute("name")
            }
        ).ToList<DocMetaData>();

        foreach (var c in docList)
        {
            Console.WriteLine("File name = {0}", c.File);
            Console.WriteLine("\t" + "Folder = {0}", c.Folder);
        }
        Console.ReadLine();
    }
}

}

我不认为我想要我的 DocMetaData 类中的 List 。我想摆脱 DOCUMENT 中 INDEX 元素的一对多方面,并分配属性,如 DocMetaData 类中所示。我实在不知道该如何对待这些孩子!

--------编辑更新----2011 年 5 月 27 日 ----------------------

进行了以下更改,导致编译错误;已经研究了该错误并尝试了一些 using 指令的重新排列,但到目前为止无法解决这个问题:

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Linq;
using System.Xml.XPath;
using System.Linq;
namespace ConsoleApplication1
{
class DocMetaData
{
    public string Comment { get; set; }
    public string DocClass { get; set; }
    public string Title { get; set; }
    public string Folder { get; set; }
    public string File { get; set; }
}
class Program
{
static void Main(string[] args)
    {
        XDocument xmlDoc = XDocument.Load(@"convert.B0000001.Submission.xml");
        List<DocMetaData> docList = 
            (from d in xmlDoc.Descendants("DOCUMENT")
                select new DocMetaData
                {
                    Folder = d.Element("FOLDER").Attribute("name").Value,
                    File = d.Element("FILE").Attribute("filename").Value,
                    Comment = d.Element("INDEX")
                              .Where(i => i.Attribute("name") == "Comment(idmComment)")
                              .First()
                            .Attribute("value").Value
                }
            ).ToList<DocMetaData>();
        foreach (var c in docList)
        {
            Console.WriteLine("File name = {0}", c.File);
            Console.WriteLine("\t" + "Folder = {0}", c.Folder);
            Console.WriteLine("\t\t" + "Comment = {0}", c.Comment);
        }
        Console.ReadLine();
    }

这是错误(注意:我有 System.Xml.Linq 作为参考,并且还有一个 using 指令):

Error   1   'System.Xml.Linq.XElement' does not contain a definition for 'Where' and no   extension method 'Where' accepting a first argument of type 'System.Xml.Linq.XElement' could be found (are you missing a using directive or an assembly reference?)   C:\ProjectsVS2010\ConsoleApplication_LINQ\ConsoleApplication1\Program.cs    31  37  ConsoleApplication1

I am new trying to learn LINQ to XML and having trouble with "children". I have an XML file of info about documents; each document has some number of INDEX elements as in this snippet:

<DOCUMENTCOLLECTION>
<DOCUMENT>
<FILE filename="Z:\Consulting\ConverterRun4\B0000001\Submission\D003688171.0001.tif" outputpath="Z:\Consulting\ConverterRun4\B0000001\Submission"/>
<ANNOTATION filename=""/>
<INDEX name="CAN(idmDocCustom4)" value=""/>
<INDEX name="Comment(idmComment)" value="GENERAL CORRESPONDENCE 11-6-96 TO 10-29-"/>
<INDEX name="DiagnosticID(idmDocCustom5)" value="983958-0006.MDB-2155504"/>
<INDEX name="Document Class(idmDocType)" value="Submission"/>
<INDEX name="Original File Name(idmDocOriginalFile)" value="40410.TIF"/>
<INDEX name="Title(idmName)" value="1997-12"/>
<FOLDER name="/Accreditation/NCACIHE/1997-12"/>
</DOCUMENT>
<DOCUMENT>

I only need a few values from the INDEX elements - those with name attributes of:

Comment(idmComment)
Document Class(idmDocType)
Title(idmName)

This is what I have so far in my testing:

namespace ConsoleApplication1
{
class DocMetaData
{
    public string Comment { get; set; }
    public string DocClass { get; set; }
    public string Title { get; set; }
    public string Folder { get; set; }
    public string File { get; set; }
}
class Program
{
     static void Main(string[] args)
    {
        XDocument xmlDoc = XDocument.Load(@"convert.B0000001.Submission.xml");
        List<DocMetaData> docList = 
        (from d in xmlDoc.Descendants("DOCUMENT")
            select new DocMetaData
            {
                Folder = d.Element("FOLDER").Attribute("name").Value,
                File = d.Element("FILE").Attribute("filename").Value,
        // need Comment, DocClass, Title from d.Element("INDEX").Attribute("name")
            }
        ).ToList<DocMetaData>();

        foreach (var c in docList)
        {
            Console.WriteLine("File name = {0}", c.File);
            Console.WriteLine("\t" + "Folder = {0}", c.Folder);
        }
        Console.ReadLine();
    }
}

}

I don't think I want a List<Index> inside my DocMetaData class. I want to get rid of the one-to-many aspect of the INDEX elements within DOCUMENT and assign properties as shown in the DocMetaData class. I can't get my head around how to handle these children!

--------EDIT-UPDATE----27 May 2011 ----------------------

Made the following change which caused compile error; have researched the error and tried some rearrangement of using directives but so far unable to get past this:

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Linq;
using System.Xml.XPath;
using System.Linq;
namespace ConsoleApplication1
{
class DocMetaData
{
    public string Comment { get; set; }
    public string DocClass { get; set; }
    public string Title { get; set; }
    public string Folder { get; set; }
    public string File { get; set; }
}
class Program
{
static void Main(string[] args)
    {
        XDocument xmlDoc = XDocument.Load(@"convert.B0000001.Submission.xml");
        List<DocMetaData> docList = 
            (from d in xmlDoc.Descendants("DOCUMENT")
                select new DocMetaData
                {
                    Folder = d.Element("FOLDER").Attribute("name").Value,
                    File = d.Element("FILE").Attribute("filename").Value,
                    Comment = d.Element("INDEX")
                              .Where(i => i.Attribute("name") == "Comment(idmComment)")
                              .First()
                            .Attribute("value").Value
                }
            ).ToList<DocMetaData>();
        foreach (var c in docList)
        {
            Console.WriteLine("File name = {0}", c.File);
            Console.WriteLine("\t" + "Folder = {0}", c.Folder);
            Console.WriteLine("\t\t" + "Comment = {0}", c.Comment);
        }
        Console.ReadLine();
    }

Here is the error (NOTE: I have System.Xml.Linq as a Reference and a using directive for it also):

Error   1   'System.Xml.Linq.XElement' does not contain a definition for 'Where' and no   extension method 'Where' accepting a first argument of type 'System.Xml.Linq.XElement' could be found (are you missing a using directive or an assembly reference?)   C:\ProjectsVS2010\ConsoleApplication_LINQ\ConsoleApplication1\Program.cs    31  37  ConsoleApplication1

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

执笔绘流年 2024-11-16 21:47:09

您可能想要获取 INDEX 元素,然后使用 WhereFirst 获取所需的元素。

select new DocMetaData
{
    Folder = d.Element("FOLDER").Attribute("name").Value,
    File = d.Element("FILE").Attribute("filename").Value,
    Comment = d.Elements("INDEX")
               .Where(i => i.Attribute("name").Value == "Comment(idmComment)")
               .First()
               .Attribute("value").Value
    //similarly for other index elements
}

请注意,如果不存在具有正确属性的 INDEX 元素,这将引发异常。如果您想忽略没有相应索引的属性,我会将选择代码拉入其自己的方法中,使用 FirstOrDefault ,并在分配之前执行适当的 null 检查。

You probably want to get the INDEX elements and then use Where and First to get the one you want.

select new DocMetaData
{
    Folder = d.Element("FOLDER").Attribute("name").Value,
    File = d.Element("FILE").Attribute("filename").Value,
    Comment = d.Elements("INDEX")
               .Where(i => i.Attribute("name").Value == "Comment(idmComment)")
               .First()
               .Attribute("value").Value
    //similarly for other index elements
}

Note that this will throw an exception if there is not an INDEX element with the right attribute. If you want to ignore properties for which there is not a corresponding index, I would pull the select code into its own method, use FirstOrDefault, and do the appropriate null checks before assigning.

翻身的咸鱼 2024-11-16 21:47:09

秘密就在于 SelectMany。这是一篇博客文章,可以帮助您解决这个问题。

http:// craigwatson1962.wordpress.com/2010/11/04/linq-to-xml-using-let-yield-return-and-selectmany/

The secret lies in SelectMany. Here is a blog post that will help you wrap your head around the problem.

http://craigwatson1962.wordpress.com/2010/11/04/linq-to-xml-using-let-yield-return-and-selectmany/

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文