读取多个 xml 节点而不是一个节点时出现问题

Issue with reading multiple xml nodes instead of one

XML 账单通常有一个返回和解析的节点。我们遇到了 XML 账单有多个节点的问题。由于未设置代码来处理该问题,因此客户最终收到了错误的账单。

这是我拥有的用于检查帐单列表的代码。如果它返回一个节点,那么它会解析来自 xml.

的信息
    var response = new List<CustomerBill>();
    try
    {
        foreach (GetBillForCAResponse eBillResponse in eBillResponseList)
        {
            var statementDetailsResponse =   GetStatementDetails(
                new GetStatementDetailsRequest
                {
                   BatchId = eBillResponse.BatchId,
                   CustomerAccountId =    eBillResponse.CA.ToString("000000000"),
                   StatementId =   eBillResponse.CAS_NUM.ToString("0000")
                });

           string xmlBill = statementDetailsResponse.StatementAsXML.ToString();
           var document = new XmlDocument();
           document.LoadXml(xmlBill);

           var saDetailedPageNode = XmlBillParser.GetDetailPageSectionBySa(requestSa, xmlBill);
           if (saDetailedPageNode == null) continue;

           var customerBill = new CustomerBill();
           customerBill.IsSurepay = XmlBillParser.GetSurepayFlagFromBill(document);
           customerBill.ServiceAddress = XmlBillParser.GetServiceAddress(requestSa, document);
           customerBill.monthName = XmlBillParser.GetnillStatementDate(requestSa, xmlBill);
           customerBill.EqCurlPlanBal = XmlBillParser.getEqualizerCurrentPlanBalance(document);
           customerBill.EqPymntDue = XmlBillParser.getEqualizerPaymentDue(document);

           customerBill.Service = GetServiceAccountUsageAndBillingDetail(requestSa, xmlBill, saDetailedPageNode);
           response.Add(customerBill);
        }
    }
    catch (Exception ex)
    {
        trace.Write(new InvalidOperationException(requestSa, ex));
    }
    return response;
}

这里是检查 XML 中是否有节点的方法。我已经更改了代码,因此 returns 所有节点。我必须将类型 xmlNode 更改为 xmlNodeList 因为现在它返回一个节点集合。 ****这就是导致我的代码在其他地方出现所有问题的原因。***

public static xmlNode GetDetailPageSectionBySa(string sa, string statementXml)
{
    XmlDocument document = new XmlDocument();
    document.LoadXml(statementXml);
    string requestSa = sa.PadLeft(9, '0');
    string xpath = String.Format("//Para[IRBILGP_SA_SAA_ID_PRINT.SERVICE.ACCOUNT.STATMENT='{0}S{1}']/..", requestSa.Substring(0, 4), requestSa.Substring(4));
    return document.SelectNodes(xpath);
    //var nodes = document.SelectNodes(xpath);
   // if(nodes.Count > 0) return nodes[nodes.Count - 1];
    //if(!SaExistInBill(requestSa, statementXml)) return null;
    //var node = GetDetailPageSectionByBillPrisminfoIndex(sa, statementXml);
    //if (node != null) return node;
    //return null;
}

所以回到它被调用的地方..我在这里得到一个无效的争论 customerBill.Service = GetServiceAccountUsageAndBillingDetail(requestSA, xmlBill, saDetailedPageNode); 因为参数 saDetailedPageNode 现在是 xmlNodeList,而它期望的类型是 xmlNode。如果我转到我在此代码末尾添加的 private static ServiceAddressBillDetail GetServiceAccountUsageAndBillingDetail(string requestSA, string xmlBill, XmlNode detailPageNode) 方法,那么您可以看到。如果我将参数 XmlNode detailPageNode 更改为 XmlNodeList detailPageNode ,我必须这样做来修复上面的无效参数,我得到 detailPageNode.SelectNodes 变得无效,因为 xmlNodeList 没有 SelectNodes 作为扩展方法。我通过这种方法大量使用这种扩展方法。所以我遇到了很多错误。

           var saDetailedPageNode = XmlBillParser.GetDetailPageSectionBySa(requestSa, xmlBill);
           if (saDetailedPageNode == null) continue;

           var customerBill = new CustomerBill();
           customerBill.IsSurepay = XmlBillParser.GetSurepayFlagFromBill(document);
           customerBill.ServiceAddress = XmlBillParser.GetServiceAddress(requestSa, document);
           customerBill.monthName = XmlBillParser.GetnillStatementDate(requestSa, xmlBill);
           customerBill.EqCurlPlanBal = XmlBillParser.getEqualizerCurrentPlanBalance(document);
           customerBill.EqPymntDue = XmlBillParser.getEqualizerPaymentDue(document);

           customerBill.Service = GetServiceAccountUsageAndBillingDetail(requestSa, xmlBill, saDetailedPageNode);
           response.Add(customerBill);
        }
    }
    catch (Exception ex)
    {
        trace.Write(new InvalidOperationException(requestSa, ex));
    }
    return response;
}
    private static ServiceAddressBillDetail GetServiceAccountUsageAndBillingDetail(string requestSA, string xmlBill, XmlNode detailPageNode)
    {
        var saBillDetail = new ServiceAddressBillDetail();
        saBillDetail.UsageServiceName = requestSA;

        var meterReadEndXMLNodes = detailPageNode.SelectNodes("Usage_kWh_b"); 

        if (meterReadEndXMLNodes.Count == 0)
        {
            meterReadEndXMLNodes = detailPageNode.SelectNodes("Usage_kWh_a");
        }
        if (meterReadEndXMLNodes.Count == 0)
        {
            meterReadEndXMLNodes = detailPageNode.SelectNodes("APSElec_kWh_b");
        }
        if (meterReadEndXMLNodes.Count == 0)
        {
            meterReadEndXMLNodes = detailPageNode.SelectNodes("APSElec_kWh_a");
        }

        var demandXMLNodes = detailPageNode.SelectNodes("Usage_kW_Total_Bold");

如何修复我的无效参数,以便我可以使用 xmlNodeList 而不是 xmlNode?有没有办法转换或转换?或者还有另一个我可以使用的 xml 对象吗?

因为我现在要返回多个节点。我知道我需要遍历 customerBill 部分。如果不为每个节点创建新账单,我该怎么做?一个xml中的所有节点需要包含在一个账单中。

很难看出发生了什么,但这可能就是问题所在;

string xpath = String.Format("//Para..

“//”将搜索整个文档,但您可能想要搜索后代元素。

这是处理类似问题的一些代码;

XmlNodeList staffNodes = resultXML.SelectNodes("//staff");
List<TempStaff> tempStaffs = staffNodes
    .Cast<XmlNode>()
    .Select(
        i =>
            new TempStaff()
            {
                StaffId = i.SelectSingleNode("id").InnerText,
                Forename = i.SelectSingleNode("forename").InnerText,
                Surname = i.SelectSingleNode("surname").InnerText,
            }
    ).ToList();

我的 XML 看起来像

<staff><forename>asdf</forename><surname>ddsf</surname><id>123</id>... </staff>
<staff><forename>asdfas</forename><surname>asffdf</surname><id>456</id>...</staff>

根据您提供的代码,唯一需要考虑重构 XmlNodeList 的部分是 GetServiceAccountUsageAndBillingDetail(),因此您有两个选择:

  1. 更新 GetServiceAccountUsageAndBillingDetail() 改为采用 XmlNodeList 参数并聚合该方法中的值以得出最终的 ServiceAddressBillDetail 对象。
  2. 遍历 XmlNodeList 中的 XmlNode 对象并自行协调不同的 ServiceAddressBillDetail 对象。

没有详细说明 ServiceAddressBillDetail,我只能猜测哪个更好,但我建议使用第一个选项。

private static ServiceAddressBillDetail GetServiceAccountUsageAndBillingDetail(
    string requestSA, 
    string xmlBill, 
    XmlNodeList detailPageNodes)
{
   var saBillDetail = new ServiceAddressBillDetail();
   saBillDetail.UsageServiceName = requestSA;

    foreach(XmlNode detailPageNode in detailPageNodes)
    {
        var meterReadEndXMLNodes = detailPageNode.SelectNodes("Usage_kWh_b"); 

        if (meterReadEndXMLNodes.Count == 0)
        {
            meterReadEndXMLNodes = detailPageNode.SelectNodes("Usage_kWh_a");
        }
        if (meterReadEndXMLNodes.Count == 0)
        {
            meterReadEndXMLNodes = detailPageNode.SelectNodes("APSElec_kWh_b");
        }
        if (meterReadEndXMLNodes.Count == 0)
        {
            meterReadEndXMLNodes = detailPageNode.SelectNodes("APSElec_kWh_a");
        }

        var demandXMLNodes = detailPageNode.SelectNodes("Usage_kW_Total_Bold");
        //Whatever comes next
    }
}

假设 ServiceAddressBillDetail 具有 "usage" 的属性,您可以简单地将每个 detailPageNode 的适当值添加到 saBillDetail 对象。