Literate LINQ-to-XML: наилучшая практика для десериализации атрибута / значения в пары структурированных переменных / значений - PullRequest
5 голосов
/ 31 июля 2009

Я борюсь за десериализацию следующего XML:

<?xml version="1.0" encoding="utf-8" ?>

<conf name="settings">

    <item name="lorem"
        one="the"
        two="quick"
        three="brown"
        four="fox"
        five="jumps"
        six="over"
        seven="the"
        eight="lazy"
        nine="dog"
            />

    <item name="ipsum"
        one="how"
        two="many"
        three="roads"
        four="must"
        five="a"
        six="man"
        seven="walk"
        eight="down"
        nine="?"
            />

</conf>

надеясь сделать это самым элегантным и лаконичным способом, используя LINQ-to-XML, но, учитывая, что я не самый умный парень в городе, когда дело доходит до вложенных методов, типов вывода, обобщенных типов и т. Д., Я подумал было бы неплохо спросить, если кто-нибудь из вас, ребята, хотел бы пойти дальше и показать мне некоторую грамотность LINQ:)

Прямо сейчас для каждого значения я делаю что-то вроде:

XDocument config = XDocument.Load("whatever.conf");

var one = from q in config.Descendants("item")
            select (string)q.Attribute("one");

var two = from q in config.Descendants("item")
            select (string)q.Attribute("two");

И Я знаю Я полностью упускаю суть, не только потому, что я там повторяюсь, но и потому, что запросы работают только тогда, когда есть только один элемент, и снова, если у вас есть Любой комментарий или предложение было бы очень ценно. Большое спасибо заранее!

ОБНОВЛЕНИЕ: в случае, если, возможно, предыдущий пример не очень помог, вот более реалистичный сценарий:

<?xml version="1.0" encoding="utf-8" ?>

<conf name="ftp-settings" freq="daily" time="23:00">
    <item   name="isis"
            host="10.10.1.250"
            user="jdoe"
            pass="4/cB0kdFGprXR/3oTs8mtw=="
            file="backup.tar.gz"
            path="/var/log"
        />
    <item   name="seth"
            host="10.10.2.250"
            user="jdoe"
            pass="4/cB0kdFGprXR/3oTs8mtw=="
            file="backup.tar.gz"
            path="/var/log"
        />
</conf>

Поэтому для каждого из этих элементов я хотел бы сгенерировать переменные, чтобы я мог передать их в качестве параметров для какого-либо метода управления FTP.

РЕШИТЬ:

Это было так же просто, как сделать foreach :

var elements = from element in xml.Descendants("item") select element;

foreach (XElement item in elements) {
    ftp.DownloadFile(
        item.Attribute("host").Value,
        item.Attribute("user").Value,
        item.Attribute("pass").Value,
        item.Attribute("file").Value,
        item.Attribute("path").Value
        );
}

Ответы [ 2 ]

3 голосов
/ 31 июля 2009

Обычно я ожидал бы, что нужно одно представление каждого элемента, а не одна последовательность «одного» значения и другая последовательность «двух» значений. Другими словами, я бы ожидал что-то вроде:

var items = config.Descendants("item")
                  .Select(element => Item.FromXElement(element));

Если у вас много атрибутов в одном элементе, я считаю полезным разделить код «сделать объект из этого элемента» в его собственный метод (в данном случае Item.FromXElement), а не вставлять все это в запрос. Если Item не должен знать о своем представлении LINQ to XML, поместите метод куда-нибудь, который должен:)

items - это IEnumerable<Item>, который вы можете преобразовать в список или что угодно, что вы хотите сделать.

Конечно, это действительно зависит от того, что вы пытаетесь сделать - и мы действительно не знаем, что это значит. Может быть, вы действительно do хотите, чтобы каждая "последовательность атрибутов" отдельно ...


Item.FromXElement будет выглядеть примерно так:

public static Item FromXElement(XElement element)
{
    string name = (string) element.Attribute("name");
    string host = (string) element.Attribute("host");
    // etc
    return new Item(name, host, ...);
}

(Где, очевидно, вы бы создали конструктор с соответствующими параметрами.)

1 голос
/ 31 июля 2009

Я бы сделал это:

XDocument config = XDocument.Load("whatever.conf");

var pairs = from q in config.Descendants("item")
           select new {
               One = (string)q.Attribute("one"),
               Two = (string)q.Attribute("two") };

var ones = pairs.Select(pair => pair.One);
var twos = pairs.Select(pair => pair.Two);
...