【问题标题】:Linq to XML (C#) parse XML tree with no attributes/id to objectLinq to XML (C#) 解析没有属性/id 到对象的 XML 树
【发布时间】:2012-01-25 18:10:38
【问题描述】:

我有一个类(Person)和一个 XML 树:

<rows>
    <row>
        <number>1110</number>
        <name>Street</name>
        <value>First Avenue</value>
        <description>First Avenue</description>
    </row>
    <row>
        <number>1120</number>
        <name>House number</name>
        <value>281</value>
        <description>281</description>
    </row>
    <row>
        <number>1160</number>
        <name>Postal</name>
        <value>2552AD</value>
        <description>2552AD</description>
    </row>
    <row>
        <number>1170</number>
        <name>Area</name>
        <value>Peru</value>
        <description>Peru</description>
    </row>
</rows>

person 类具有街道、门牌号、邮政和区域等属性。如何填充这个人对象?

我的查询中的问题是我不知道在哪里添加:

where (string)c.Element("name") == "Street"

到目前为止我的代码:

public class XMLparser
{
    public Person XMLparse(string path)
    {
        Person person = new Person();
        List<Person> ListPerson = new List<Person>();
        XDocument file = XDocument.Load(path);
        var query = from c in file.Descendants("row")
                    select new
                    {
                        c.Element("value").Value 
                    };

        // Loop through results
        foreach (var value in query)
        {
            person._street = value.Value;
            person._housenumber = value.Value;
            person._postal = value.Value;
            person._area = value.Value;
        }

        return person;
   }
}

我想要的是从xml中取出并填写

person._street = value.Value;      //<-- First Avenue
person._housenumber = value.Value; //<-- 281
person._postal = value.Value;      //<-- 2552AD
person._area = value.Value;        //<-- Peru    

编辑:

这是原始的 XMl 树。

    <?xml version="1.0" encoding="utf-8" ?>
    <results>
      <person>
        <categories>
          <category>
            <number>01</number>
            <name>Person</name>
            <rows>
              <row>
                <number>0110</number>
                <name>ID</name>
                <value>value ID</value>
                <description>value ID</description>
              </row>
            </rows>
          </category>
          <category>
            <number>08</number>
            <name>Address</name>
            <rows>
              <row>
                <number>1110</number>
                <name>Street</name>
                <value>value street</value>
                <description>value street</description>
              </row>
              <row>
                <number>1120</number>
                <name>House number</name>
                <value>value House number</value>
                <description>value House number</description>
              </row>
              <row>
                <number>1160</number>
                <name>Postal</name>
                <value>value Postal</value>
                <description>value Postal</description>
              </row>
              <row>
                <number>1170</number>
                <name>Area</name>
                <value>value Area</value>
                <description>value Area</description>
              </row>
            </rows>
          </category>
        </categories>
      </person>
      <person>
        <categories>
          <category>
            <number>01</number>
            <name>Person</name>
            <rows>
              <row>
                <number>0110</number>
                <name>ID</name>
                <value>value ID</value>
                <description>value ID</description>
              </row>
            </rows>
          </category>
          <category>
            <number>08</number>
            <name>Address</name>
            <rows>
              <row>
                <number>1110</number>
                <name>Street</name>
                <value>value Street</value>
                <description>value Street</description>
              </row>
              <row>
                <number>1120</number>
                <name>House number</name>
                <value>value House number</value>
                <description>value House number</description>
              </row>
              <row>
                <number>1130</number>
                <name>House number extra</name>
                <value>value House number extra</value>
                <description>value House number extra</description>
              </row>
              <row>
                <number>1160</number>
                <name>Postal</name>
                <value>value Postal</value>
                <description>value Postal</description>
              </row>
              <row>
                <number>1170</number>
                <name>Area</name>
                <value>value Area</value>
                <description>value Area</description>
              </row>
            </rows>
          </category>
        </categories>
      </person>
    </results>

【问题讨论】:

    标签: c# xml linq


    【解决方案1】:

    您可以使用此代码:

    XDocument file = XDocument.Parse(xml);
    var persons
      = file.Descendants("rows")
            .Select (x => 
                {
                    var person = new Person();
                    var values = x.Descendants("row")
                                  .GroupBy(y => y.Element("name").Value, 
                                           y => y.Element("value").Value)
                                  .ToDictionary (y => y.Key, y => y.First());
    
                    foreach(var value in values)
                    {
                        switch (value.Key)
                        {
                            case "Street":
                                person.Street = value.Value;
                                break;
                            case "House number":
                                person.Housenumber = value.Value;
                                break;
                            case "Postal":
                                person.Postal = value.Value;
                                break;
                            case "Area":
                                person.Area = value.Value;
                                break;
                        }
                    }
                    return person;
                });
    

    它假定 XML 可以包含多个 rows 标签,每个人一个标签。然后它获取rows标签内每个row标签的名称和值,并用这些值初始化一个人。

    【讨论】:

    • 您能否扩展您的帖子,详细说明您使用 GroupBy 的原因?这段代码实现了同样的目的; var values = x.Descendants("row").ToDictionary(y => y.Element("name").Value, y => y.Element("value").Value);但我很好奇我是否错过了你答案的一些微妙方面。干杯
    • @ChrisMcAtackney:如果一个属性有多个 row 标记,您的代码将引发异常。我的只是取第一个而忽略所有其他。使用哪个代码很大程度上取决于上下文:如果您可以确定,这种情况不会出现,请使用您的较短版本,否则使用我的。 XML 看起来像是来自遗留系统,在这种情况下我倾向于小心。
    • 酷,感谢您的解释。 LINQ 查询中的空值安全性是我仍在努力解决的问题,因此学习这样的技巧总是有用的。
    • 看起来很有前途!我现在无法运行代码(笔记本电脑的一些问题)。我会在早上尽快回复进展情况。但与此同时,提前非常感谢您。之后我将不得不测试添加多人、额外的 Xelement 等。
    • @DanielHilgarth 谢谢你的代码。我尝试快速查看 var 人员,我看到属性已填充。但是我无法理解您的代码(lambda 表达式(?)部分,如果我有多个人怎么办,我可以在哪里添加“persons.Add(person);”行?在我的原始帖子中,我将添加原始 XML 树。
    【解决方案2】:

    您的 Linq 查询需要同时包含“naam”值和“value”值。然后在 foreach 循环中为每个预期的“naam”值添加一个带有 case 块的 switch 块。然后将“值”值存储在 Person 对象中。

    【讨论】:

      【解决方案3】:

      下面的代码应该给你一个人对象的列表:

      string sampleXml =
                  @"<rows>
            <row>
              <number>1110</number>
              <name>Street</name>
              <value>First Avenue</value>
              <description>First Avenue</description>
            </row>
            <row>
              <number>1120</number>
              <name>House number</name>
              <value>281</value>
              <description>281</description>
            </row>
            <row>
              <number>1160</number>
              <name>Postal</name>
              <value>2552AD</value>
              <description>2552AD</description>
            </row>
            <row>
              <number>1170</number>
              <name>Area</name>
              <value>Peru</value>
              <description>Peru</description>
            </row>
          </rows>";
              var file = XDocument.Parse(sampleXml);
      
              var query = from row in file.Descendants("row")
                          select new Person
                          {
                              Street = row.Element("number").Value,
                              HouseNumber = row.Element("name").Value,
                              Postal = row.Element("value").Value,
                              Area = row.Element("description").Value
                          };
      
              var list = query.ToList();
      

      【讨论】:

      • -1:你测试了吗?这是完全不同的东西。每个row 标记代表Person 类的一个属性。哪个属性由name 标记的值定义。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多