【问题标题】:Parsing XML with pairs of elements using XDocument and LINQ使用 XDocument 和 LINQ 解析带有元素对的 XML
【发布时间】:2013-12-17 09:40:20
【问题描述】:

我正在尝试使用 XDocument 来解析 xml 文档,但是我对 XML 很陌生,过去只主要使用 JSON。到目前为止,我可以解析每个报告名称,但我一直在尝试解析参数列表。没有节点区分不同参数时如何解析参数列表?

var reports = xml.Descendants("Report").Select(reportElement => new
{
    Name = reportElement.Attribute("Name").Value,
    Parameters = reportElement.Descendants("ParameterList").Select(parameter => new
    {
    })
});

XML:

<ReportList>
    <Report Name="JobNotClose">
        <ParameterList>
            <Name>@StationCode</Name><Value>LAX</Value>
            <Name>@ShipmentType</Name><Value>SE|SI</Value>
        </ParameterList>
    </Report>
    <Report Name="JobWithoutSales">
        <ParameterList>
            <Name>@StationCode</Name><Value>PA</Value>
            <Name>@JobDateFrom</Name><Value>2013-10-1</Value>
            <Name>@JobDateTo</Name><Value>2013-10-31</Value>
        </ParameterList>
    </Report>
</ReportList>

【问题讨论】:

  • 那个 xml 对我来说看起来有点笨拙。参数条目不应该是 吗?
  • 看这就是我问的,但不,这就是它的格式。如果它是一个 节点,我会使用 .Descendants() 我不太确定如何处理像这样的结构

标签: c# .net xml linq linq-to-xml


【解决方案1】:

您可以使用Enumerable.Zip 将参数名称序列与参数值序列合并:

var reports = from r in xml.Root.Elements("Report")
              let parameters = r.Element("ParameterList")
              select new {
                  Name = (string)r.Attribute("Name"),
                  Parameters = parameters.Elements("Name")
                                         .Zip(parameters.Elements("Value"), 
                                              (n,v) => new { 
                                                  Name = (string)n, 
                                                  Value = (string)v 
                                              })
              };

这提供了以下报告集合:

[
  {
    "Name": "JobNotClose",
    "Parameters": [
      {
        "Name": "@StationCode",
        "Value": "LAX"
      },
      {
        "Name": "@ShipmentType",
        "Value": "SE|SI"
      }
    ]
  },
  {
    "Name": "JobWithoutSales",
    "Parameters": [
      {
        "Name": "@StationCode",
        "Value": "PA"
      },
      {
        "Name": "@JobDateFrom",
        "Value": "2013-10-1"
      },
      {
        "Name": "@JobDateTo",
        "Value": "2013-10-31"
      }
    ]
  }
]

【讨论】:

    【解决方案2】:

    试试这个(try我的意思是使用):

    var reports = xml.Descendants("Report").Select(reportElement => new
    {
        Name = reportElement.Attribute("Name").Value,
        Parameters = reportElement.Descendants("ParameterList").Select(parameter => 
        {
            List<string> names = parameter.Elements("Name").Select(x=>x.Value).ToList();
            List<string> values = parameter.Elements("Value").Select(x=>x.Value).ToList();
    
            List<object>  pairs=new List<object>();
    
            for (int i = 0; i < names.Count; i++)
            {
                pairs.Add(new { Name = names[i], Value = values[i] });
            }
    
            return pairs;                    
        }).ToList()
    }).ToList();
    

    您可以删除两个ToList() 调用。它只是让测试变得更容易。当然,有可能在您的 XML 中,&lt;Name&gt; &lt;Value&gt; 标签并不总是完整的(即Name 没有Value)。您可以在执行 for 循环之前进行检查。

    编辑:另一种选择:

    Dictionary<string, List<Tuple<string, string>>> rep = new Dictionary<string, List<Tuple<string, string>>>();
    
    foreach (XElement report in xml.Elements("Report"))
    {
        rep.Add(report.Attribute("Name").Value, new List<Tuple<string, string>>());
    
        List<string> names = report.Elements("ParameterList").FirstOrDefault().Elements("Name").Select(x => x.Value).ToList();
        List<string> values = report.Elements("ParameterList").FirstOrDefault().Elements("Value").Select(x => x.Value).ToList();
    
        for (int i = 0; i < names.Count; i++)
        {
             rep[report.Attribute("Name").Value].Add(new Tuple<string, string>(names[i], values[i]));
        }
    }
    

    【讨论】:

    • 这不会使参数成为列表列表吗?我可能从 Parameter 的开头写错了。据我了解,每个报告将仅包含一个 ParameterList 节点,其中包含多个 对
    • @ChaoticLoki,是的,它确实使它成为列表列表。这是这种方法的缺点。还有其他方法。这个是建立在你的逻辑之上的。
    【解决方案3】:

    也许这会奏效。

    您可以使用 XNode.ElementsAfterSelf 将 ParameterList 元素作为 IEnumerable。 然后循环遍历结果集并假设元素是成对的。

    这本质上为您提供了一种方法,可以按照它们在 ParameterList 中出现的顺序来解析元素,而不必担心 .Descendants 会弄乱顺序。

    当然,这里最大的假设是元素总是成对的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-01-27
      • 1970-01-01
      • 2016-02-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多