识别LINQ-to-XML:将属性/值反序列化为结构化变量/值对的最佳实践

时间:2009-07-31 19:12:39

标签: c# serialization linq-to-xml

我正在努力反序列化以下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 个答案:

答案 0 :(得分:3)

通常我希望想要每个元素的单个表示,而不是一个“one”值序列和另一个“two”值序列。换句话说,我希望有类似的东西:

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

如果你在一个元素中有很多属性,我发现将“从这个元素中创建一个对象”代码分离到它自己的方法(在这种情况下是Item.FromXElement)而不是填充它是有帮助的全部进入查询。如果Item不应该知道它的LINQ to XML表示,那么把方法放在应该的地方:)

items然后是IEnumerable<Item>,您可以将其转换为列表或其他任何您想要做的事情。

当然,这实际上取决于你想要做什么 - 我们并不真正知道这意味着什么。也许你真的分别想要每个“属性序列”...


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 :(得分:1)

我会这样做:

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);