Найти подэлементы, которые отличаются в двух коллекциях в Linq - PullRequest
1 голос
/ 16 августа 2011

Как мне сделать запрос Linq для этого?

У меня есть два xml документа, doc1.xml и doc2.xml.Как я могу найти для каждого элемента "file" в doc1, где doc2 имеет элемент "file" с точно таким же атрибутом "path", но любой дочерний элемент "link" этого "файла" в doc1 имеет атрибут "absolutepath", которыйНЕ совпадает с одним или несколькими атрибутами "absolutepath" в соответствующем элементе "file" в doc2?

простой пример:

doc1:

<doc>
  <file path="c:\temp\A.xml">
    <link absolutepath="c:\temp\B.xml"/>
    <link absolutepath="c:\temp\C.xml"/>
  </file>
  <file path="c:\temp\C.xml"> <!--This should match, because it's child link absolutepath is not the same as child link absolutepath of the corresponding file with the same path in doc2-->
    <link absolutepath="c:\temp\D.xml"/>
    <link absolutepath="c:\temp\F.xml"/>
  </file>
</doc>

doc2:

<doc>
  <file path="c:\temp\A.xml">
    <link absolutepath="c:\temp\B.xml"/>
    <link absolutepath="c:\temp\C.xml"/>
  </file>
  <file path="c:\temp\C.xml">
    <link absolutepath="c:\temp\D.xml"/>
    <link absolutepath="c:\temp\E.xml"/>
  </file>
</doc>

Есть идеи?

РЕДАКТИРОВАТЬ: Отредактировал пример XML, чтобы показать, что я имею в виду под несколькими ссылками для каждого элемента файла.Итак, я хочу, чтобы каждый файл в doc1 имел элемент ссылки с absolutepath, который не найден в элементе ссылки в doc2.Так что на самом деле количество ссылок в обоих одинаковое, но абсолютный путь иногда может отличаться, и это то, что я хочу найти и извлечь те файлы, в которых есть различие в элементах ссылок.

Вот моя попыткаизмените запрос, предложенный Джоном, чтобы извлечь несколько ссылок, но я думаю, что я делаю это неправильно, потому что впоследствии я не получаю правильный результат из запроса на исключение:

   var files = from file in doc1.Descendants("file")

                select new
                {
                    file = file.Attribute("path").Value,
                    link = file.Elements("link").Attributes("absolutepath")
                };
    var oldfiles = from file in doc2.Descendants("file")
                from link in file.Elements("link")
                select new
                {
                    file = file.Attribute("path").Value,
                    link = file.Elements("link").Attributes("absolutepath")
                };
    //Get the ones that are different between them
    var missing = files.Except(oldfiles);

1 Ответ

2 голосов
/ 16 августа 2011

Ну, я бы начал с XML-части.Первоначально я сделал это более сложным, чем нужно, но я думаю, что вы можете просто использовать:

var files = from file in document.Descendants("file")
            from link in file.Elements("link")
            select new { file = file.Attribute("path").Value,
                         link = link.Attribute("absolutepath").Value };

Тогда, если у вас есть files1 и files2 (вышеуказанный запрос применяется к каждому документу), выможно просто сделать:

var extraFiles = files1.Except(files2);

РЕДАКТИРОВАТЬ: Чтобы вернуться к элементам ссылки для этих файлов, вы можете использовать:

var linkElements = from link in file.Descendants("link")
                   join extra in extraFiles on 
                         new { file = link.Parent.Attribute("path").Value,
                               link = link.Attribute("absolutepath").Value }
                         equals extra
                   select link;

Немного стыдно снова запросить документ, но мы идем ...

(Я выбрал элемент ссылки, а не элемент файла, чтобы вы могли получить абсолютно правильный бит - вы всегда можете выбрать родительский элемент, чтобы попасть в файл.)

РЕДАКТИРОВАТЬ: Хорошо, если есть несколько элементов ссылки, и вы просто хотите найти файлы с отсутствующими элементами, это на самом деле довольно просто из того, что мы получили:

var justFiles = new HashSet<string>(extraFiles.Select(x => x.file).Distinct());
var fileElements = from element in file.Descendants("file")
                   where justFiles.Contains((string) element.Attribute("path")
                   select element;
...