Выберите определенные узлы в XML с помощью LINQ

Я пишу функцию, которая загружает XML-документ и преобразует его в CSV. Поскольку мне нужны только некоторые значения из файла XML, цель, которую я пытаюсь достичь, — выбрать только те узлы, которые меня интересуют.

Вот мой код:

      XDocument csvDocument = XDocument.Load(tempOutput);

        StringBuilder csvBuilder = new StringBuilder(1000);

        foreach (XElement node in csvDocument.Descendants("Sample"))
        {
            foreach (XElement innerNode in node.Elements())
            {
                        csvBuilder.AppendFormat("{0},", innerNode.Value);
                    }

                    csvBuilder.Remove(csvBuilder.Length -1, 1);

                    csvBuilder.AppendLine();
                }
                csvOut = csvBuilder.ToString();

Но таким образом я выбираю ВСЕ дочерние узлы внутри узла «Образец».

В XML дерево «Образец»:

<Sample Type="Object" Class ="Sample">
    <ID>1</ID>
    <Name>10096</Name>
    <Type>2</Type>
    <Rep>0</Rep>
    <Selected>True</Selected>
    <Position>1</Position>
    <Pattern>0</Pattern>
   </Sample>

Код работает безупречно, но мне нужно, чтобы были выбраны только «ID» и «Selected», а их значения записаны в файл CSV.

Может ли кто-нибудь указать мне в правильном направлении, пожалуйста?

Спасибо.


person user1776401    schedule 30.03.2013    source источник
comment
Итак, что вы хотите сделать, {ID}, {Name} и т. д. для каждого объекта Sample?   -  person It'sNotALie.    schedule 31.03.2013


Ответы (1)


Узнайте больше о Linq-to-xml здесь. Вы на самом деле не пользуетесь преимуществом "связности" XObjects

var samples = csvDocument.Descendants("Sample")
                         .Select(el => new {
                             Id = el.Element("ID").Value,
                             Selected = el.Elemnt("Selected").Value
                         });

Это создает для вас IEnumerable<T>, где 'T' — это анонимный тип с свойства Id и Selected. Вы можете проанализировать (int.Parse или bool.Parse) значения Id и Selected для обеспечения безопасности типов. Но поскольку вы просто пишете объекту StringBuilder, вам может быть все равно... просто к вашему сведению.

Затем объект StringBuilder можно записать следующим образом:

foreach (var sample in samples) {
    csvBuilder.AppendFormat(myFormattedString, sample.Id, sample.Selected);
}

Предостережение заключается в том, что ваш анонимный объект и цикл for-each должны находиться в одной области видимости. Но есть способы обойти это, если это необходимо.

Как всегда, есть несколько способов содрать шкуру с кошки.

Обновление ... в исх. комментировать:

foreach (XElement node in csvDocument.Descendants("Sample"))
{
    foreach (XElement innerNode in node.Elements())
    {
        //    this logic assumes different formatting for values
        //    otherwise, change if statement to || each comparison
        if(innerNode.Name == "ID") {
            // append/format stringBuilder
            continue;
        }

        if(innerNode.Name == "Selected") {
            // append/format stringBuilder
            continue;
        }
    }

    csvBuilder.Remove(csvBuilder.Length -1, 1);

    csvBuilder.AppendLine();
}
person IAbstract    schedule 30.03.2013
comment
Конечно, я должен был бы попробовать и этот способ. Но я хотел бы пойти по пути, который я уже закодировал. Должен быть способ редактирования: foreach (XElement innerNode в node.Elements()), добавление некоторого правила для пропуска нежелательных элементов или взятие только тех, которые мне нужны. - person user1776401; 31.03.2013
comment
В своем foreach проверьте имя innerNode, и если это не ID или Selected, то пропустите его? Или я что-то упускаю? - person Pete; 31.03.2013
comment
Спасибо IAbstract! Ваш код работает! Раньше я пытался добавить innerNode.Name к оператору foreach, но это выдавало мне ошибки! Спасибо еще раз. Кстати, Пит, я тоже пробовал таким образом, добавляя свойство Skip к оператору foreach, но мне пришлось сделать что-то не так, потому что это не сработало. Не могли бы вы опубликовать рабочий пример, пожалуйста? - person user1776401; 31.03.2013