代码之家  ›  专栏  ›  技术社区  ›  Nano Taboada

将LINQ编写为XML:将属性/值反序列化为结构化变量/值对的最佳实践

  •  5
  • Nano Taboada  · 技术社区  · 17 年前

    我正在努力反序列化以下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管理方法的参数传递。

    解决了的:

    就像做一个 前额 :

    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 回复  |  直到 17 年前
        1
  •  3
  •   Jon Skeet    17 年前

    通常,我希望每个元素都有一个表示,而不是一个“一”值序列和另一个“两”值序列。换言之,我希望:

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

    如果在一个元素中有很多属性,我发现将“使一个对象与这个元素”代码分离到它自己的方法(在本例中)是很有帮助的 Item.FromXElement )而不是把它全部塞进查询中。如果 Item 不应该知道它的linq-to-xml表示,把方法放在应该的地方:)

    items 然后是 IEnumerable<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, ...);
    }
    

    (显然,您将使用适当的参数创建一个构造函数。)

        2
  •  1
  •   Pavel Minaev    17 年前

    我会这样做:

    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);
    
    推荐文章