Обработка потомков родительско-дочерних отношений с использованием Linq to XML - PullRequest
1 голос
/ 26 мая 2011

Я новичок, пытаюсь выучить 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();
    }
}

}

Не думаю, что я хочу List<Index> внутри моего класса DocMetaData. Я хочу избавиться от аспекта «один ко многим» элементов INDEX в DOCUMENT и назначить свойства, как показано в классе DocMetaData. Я не могу понять, как обращаться с этими детьми!

-------- РЕДАКТИРОВАНИЕ-ОБНОВЛЕНИЕ ---- 27 мая 2011 г. ----------------------

Внесены следующие изменения, приведшие к ошибке компиляции; исследовали ошибку и попытались изменить порядок использования директив, но пока не смогли обойти это:

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

Ответы [ 2 ]

2 голосов
/ 26 мая 2011

Вы, вероятно, хотите получить элементы INDEX, а затем использовать Where и First, чтобы получить тот, который вам нужен.

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
}

Обратите внимание, что это вызовет исключение, если нет индексаэлемент с правильным атрибутом.Если вы хотите игнорировать свойства, для которых нет соответствующего индекса, я бы перетащил код выбора в его собственный метод, использовал FirstOrDefault и выполнял соответствующие проверки на ноль перед назначением.

0 голосов
/ 26 мая 2011

Секрет кроется в SelectMany.Вот запись в блоге, которая поможет вам разобраться в проблеме.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...