【问题标题】:Handling the children of a parent-child relationship using Linq to XML使用 Linq to XML 处理父子关系的子代
【发布时间】:2011-06-01 10:10:40
【问题描述】:

我是新尝试学习 LINQ to XML 并且遇到了“孩子”的问题。我有一个关于文档信息的 XML 文件;每个文档都有一些 INDEX 元素,就像在这个 sn-p 中一样:

<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&lt;Index&gt;。我想摆脱 DOCUMENT 中 INDEX 元素的一对多方面并分配属性,如 DocMetaData 类中所示。我无法理解如何处理这些孩子!

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

进行了以下导致编译错误的更改;已经研究了这个错误并尝试了一些使用指令的重新安排,但到目前为止无法通过这个:

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

【问题讨论】:

    标签: c# xml linq linq-to-xml


    【解决方案1】:

    您可能想要获取 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,并在分配之前进行适当的空检查。

    【讨论】:

    • 吉迪恩 - 感谢您的帮助。我尝试了你的建议,现在我得到了一个令人费解的编译错误。请查看我对问题的编辑更新。
    • @John Galt:我使用了错误的功能。我应该使用d.Elements 而不是d.Element
    • Gideon - 我进行了更改(现在读作上面的 d.Elements),但现在我在 .First() 之后的 .Attribute("value").Value 上出现编译错误。编译器在 .Attribute 和消息状态下有弯曲的错误行:错误 1 ​​'char' 不包含 'Attribute' 的定义,并且找不到接受类型为 'char' 的第一个参数的扩展方法 'Attribute'(您是否缺少使用指令还是程序集引用?) C:\ProjectsVS2010\ConsoleApplication_LINQ\ConsoleApplication1\Program.cs 33 36 ConsoleApplication1
    • @John Galt:这就是我不使用编译器的结果。答案已更新以立即编译。
    • Gideon - 非常感谢您在这方面的帮助。学习 LINQ-to-XML 的最佳地点在哪里?我一直在努力研究 Jon Skeet 的书:C# in Depth,但我认为我需要一些更容易“获得”的东西。
    【解决方案2】:

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

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

    【讨论】:

    • 我认为这与 SelectMany 有点相反 - 我们使用将子属性扁平化为集合,但 OP 确实希望将集合传播到离散的子属性中。
    • @Kirk,你说的 OP 是什么意思?
    • @John - OP 表示原始海报。 urbandictionary.com/define.php?term=op
    猜你喜欢
    • 1970-01-01
    • 2011-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-05
    • 2016-02-15
    • 1970-01-01
    相关资源
    最近更新 更多