【问题标题】:Linq-to-xml to get child nodeslinq-to-xml 获取子节点
【发布时间】:2015-09-17 10:55:59
【问题描述】:

我无法确定如何使用 linq-to-xml 从下面的 xml 中提取总价和单个价格(例如,我想获取票价价格以及所有价格的总和)。任何帮助将不胜感激,尤其是使用 linq-to-xml 的方法语法

我使用以下代码将数据加载到 xDocument 中并使用 xmlResponse 对象来解析响应。

var xmlResponse = from element in xdoc.Descendants()
                              select element;

并获取类似的数据

xmlResponse.SingleOrDefault(x => x.Name.LocalName == "Registration")

以下是 xml 响应的子集:-

<StateList>
    <State>
      <SourceJobID>J999999999999</SourceJobID>
      <TargetJobState>Complete</TargetJobState>
      <TargetJobID>11111111</TargetJobID>
      <TargetSystem>TESTSYSTEM</TargetSystem>
      <VehicleDetails>
        <Registration>TESTREGISRATION</Registration>
        <Plate>11111111111</Plate>
        <CO2Rating>160</CO2Rating>
        <Badge>1111111</Badge>
        <Description>TEST DESCRIPTION</Description>
      </VehicleDetails>
      <CompleteDetails>
        <CompletedOn>2015-09-15T13:39:11+01:00</CompletedOn>
        <JobDistance>0</JobDistance>
        <WaitingTime />
        <CO2Usage>0</CO2Usage>
        <ChargeList>
          <Charge>
            <Name>Airport Pickup</Name>
            <Currency>GBP</Currency>
            <Price>0.00</Price>
          </Charge>
          <Charge>
            <Name>Fare</Name>
            <Currency>GBP</Currency>
            <Price>0.00</Price>
          </Charge>
          <Charge>
            <Name>Extra Stops</Name>
            <Currency>GBP</Currency>
            <Price>0.00</Price>
          </Charge>
        </ChargeList>
      </CompleteDetails>
    </State>

【问题讨论】:

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


    【解决方案1】:

    假设您的示例中只有一个状态,您可以执行以下操作:

            decimal fare = decimal.Parse(xml.Descendants("Charge").Single(x => x.Element("Name").Value == "Fare").Element("Price").Value);
            decimal total = xml.Descendants("Charge").Sum(x => decimal.Parse(x.Element("Price").Value));
    

    尽管如果您的列表中有一系列元素,您将不得不对其进行修改。

    编辑:如果如您在 cmets 中所说,您只想汇总某些费用:

            // Valid names of charges to sum.
            string[] names = { "Airport Pickup", "Fare" };
            // Iterate over every state.
            foreach (var state in xml.Descendants("State")) 
            {
                // Get all charge elements in the current state whose names are contained in 'names' - then convert their 'Price' element to decimal and sum them.
                decimal stateTotal = state.Descendants("Charge").Where(x => names.Contains(x.Element("Name").Value)).Sum(x => decimal.Parse(x.Element("Price").Value)); 
            }
    

    【讨论】:

    • 我需要将 single 更改为 first 以使第一个 linq 查询正常工作。当我输入 25.00 的票价和 10.00 的 Airport Pickup 时,第二个查询给了我一个 wonr 总数,它总共带回了 210
    • 这是因为它将汇总所有州的所有费用。如果您只想对第一个状态的费用求和,您可以将调用修改为:decimal total = xml.Descendants("State").First().Descendants("Charge").Sum(x =&gt; decimal.Parse(x.Element("Price").Value));
    • 您可以通过以下方式遍历所有状态:foreach (var state in xml.Descendants("State")) { decimal stateTotal = state.Descendants("Charge").Sum(x =&gt; decimal.Parse(x.Element("Price").Value)); }
    • 谢谢。如果我想汇总部分费用而不是全部费用,例如仅汇总机场接送和票价,该怎么办?
    • 我已经用针对这种情况的示例更新了答案。
    【解决方案2】:
    if(doc.Descendants("Charge").Any())
    {
        var FarePrice = doc.Descendants("Charge")
                    .Where(x => x.Descendants("Name").First().Value.Equals("Fare")).First().Element("Price").Value;
    
        var Sum = doc.Descendants("Charge")
                    .Select(x => Convert.ToDouble(x.Descendants("Price").First().Value))
                    .Sum();     
        Console.WriteLine("Fare price:{0} Sum:{1}",FarePrice,Sum);
    } 
    

    它返回 35 作为 10 和 25 输入的总和。

    在这里提琴:https://dotnetfiddle.net/cuHXBn

    【讨论】:

    • 效果很好。 XML 也可能缺少费用。如果是这种情况,是否有一种简单的方法来检查并将 FarePrice 和 Sum 设置为 null?
    • 如果收费不在 xml 文档中,它会返回“序列不包含匹配元素”。
    • 与其他答案一样,总和计算出错误的总数。以 25.00 和 10.00 两次收费带回 210
    • 奇怪的是它仍然给我错误的总数,我尝试了不同的值
    • @macca18:你试过我在答案中添加的小提琴吗?
    猜你喜欢
    • 2012-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多