使用linq查询从XML提取值

时间:2018-11-30 09:44:27

标签: c# xml linq

linq和XML的新手,正在寻找一种返回值的方法
<AddtlInf></AddtlInf>作为列表,然后将这些值连接到单个字符串。

以下XML:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<Document xmlns='urn:iso:std:iso:20022:tech:xsd:pain.002.001.03' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>
  <CstmrPmtStsRpt>
    <GrpHdr>
      <MsgId>21233519</MsgId>
      <CreDtTm>2018-11-29T09:28:00</CreDtTm>
      <InitgPty>
        <Nm>Standard Bank SA</Nm>
        <Id>
          <OrgId>
            <BICOrBEI>SBZAZAJJXXX</BICOrBEI>
          </OrgId>
        </Id>
      </InitgPty>
    </GrpHdr>
    <OrgnlGrpInfAndSts>
      <OrgnlMsgId>Domestic Base-612742-300749</OrgnlMsgId>
      <OrgnlMsgNmId>PAIN.001.001.03</OrgnlMsgNmId>
      <OrgnlCreDtTm>2018-11-29T12:23:06</OrgnlCreDtTm>
      <OrgnlNbOfTxs>1</OrgnlNbOfTxs>
      <OrgnlCtrlSum>17500.00</OrgnlCtrlSum>
      <GrpSts>RJCT</GrpSts>
      <StsRsnInf>
        <Rsn>
          <Cd>NARR</Cd>
        </Rsn>
        <AddtlInf>Duplicate File</AddtlInf>
        <AddtlInf>Error: 6789</AddtlInf>
        <AddtlInf>Not Processed</AddtlInf>
      </StsRsnInf>
    </OrgnlGrpInfAndSts>
  </CstmrPmtStsRpt>
</Document>

到目前为止,我有:

var info = doc.Descendants(ns + "CstmrPmtStsRpt")
           .Descendants(ns + "OrgnlGrpInfAndSts")
           .Descendants(ns + "StsRsnInf")                                       
           .Select(r => new
           {
                Info = r.Element(ns + "AddtlInf").Value                                          
           }).ToList();

但这仅返回“重复文件”,即第一个值。我该如何解决?

4 个答案:

答案 0 :(得分:2)

您需要访问StsRsnInf的子元素:

var info = doc.Descendants(ns + "CstmrPmtStsRpt")
            .Descendants(ns + "OrgnlGrpInfAndSts")
            .Descendants(ns + "StsRsnInf")                                       
            .SelectMany(r => r.Elements(ns + "AddtlInf").Select(s => new
            {
              Info = s.Value
            })).ToList();

通过使用Element(不带尾号s),您只能访问单个元素,而不是多个元素,因此您的结果仅包含第一个元素的值。

通过使用SelectMany而不是Select,可以从子枚举中返回多个元素。

答案 1 :(得分:0)

在您的代码中,r.Element将始终返回集合的第一个元素。 而是尝试使用r.Elements,它将返回“ AddtlInf”元素的集合。

有关此的详细信息,请查看此link

答案 2 :(得分:0)

您可以在Linq中使用SelectMany

var result = (string)xdoc.Descendants("member")
                         .FirstOrDefault(x => (string)x.Element("name") == "responseCode")
                         ?.Element("value");

    var info = xdoc.Descendants("CstmrPmtStsRpt")
   .Descendants("OrgnlGrpInfAndSts")
   .Descendants("StsRsnInf")                                       
   .SelectMany(r=> r.Descendants("AddtlInf")).ToList();
   Console.WriteLine(info.Count); // prints 3.

Dotnet在这里摆弄:https://dotnetfiddle.net/IKd7go

答案 3 :(得分:0)

作为替代方案,这对我来说似乎更容易:

var list = doc.XPathSelectElements
                ("Document/CstmrPmtStsRpt/OrgnlGrpInfAndSts/StsRsnInf/AddtlInf")
                .Select(n => n.Value);