【问题标题】:Issue with reading multiple xml nodes instead of one读取多个 xml 节点而不是一个的问题
【发布时间】:2015-10-11 08:54:14
【问题描述】:

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 中是否存在节点的方法。我已经更改了代码,以便返回所有节点。我不得不将类型 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中的所有节点都需要包含在一个bill中。

【问题讨论】:

  • 这看起来像你希望有人为你做重构工作;你似乎明白你需要做什么,为什么不直接去做呢?
  • 我是一个相当新的程序员。据我了解我需要做什么,我不确定如何去做。我已经尽我所知做了。任何帮助或指导都会有所帮助
  • 也许你应该改用 xmlserializer,如果你觉得它适合你,它可以简化你的代码。在这里查看我的答案:stackoverflow.com/questions/29850559/…

标签: c# xml c#-4.0 xml-parsing


【解决方案1】:

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

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>

【讨论】:

  • 任何关于我需要将其更改为以搜索特定元素的指导或示例
  • 如果您选择要使用 XPath 查询的元素,那么您可以使用与所选元素相似的 XPath 减去 //。我已经编辑了答案以添加解决类似问题的代码。
【解决方案2】:

根据您提供的代码,唯一需要考虑到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 具有“使用”属性,您只需将每个detailPageNode 中的适当值添加到saBillDetail 对象即可。

【讨论】:

  • 感谢您的帮助。最后一个问题。我需要使用 'foreach(var saDetailedPageNode in xmlBillParser.GetDetailPageSectionBySA(requestSA, xmlBill)' 循环通过 customerBill 部分,但我得到一个错误。有没有更好的方法来做到这一点?
  • 我正在循环遍历 var customerBill = new CustomerBill(); customerBill.IsSurepay = XmlBillParser.GetSurepayFlagFromBill(document); customerBill.ServiceAddress = XmlBillParser.GetServiceAddress(requestSa, 文档); customerBill.monthName = XmlBillParser.GetnillStatementDate(requestSa, xmlBill); customerBill.EqCurlPlanBal = XmlBillParser.getEqualizerCurrentPlanBalance(document); customerBill.EqPymntDue = XmlBillParser.getEqualizerPaymentDue(document); customerBill.Service = GetServiceAccountUsageAndBillingDetail(requestSa, xmlBill, saDetailedPageNode);然后返回响应
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-21
  • 1970-01-01
  • 2019-10-09
  • 2020-12-18
相关资源
最近更新 更多