在Python中处理XML响应。无法获取元素数据

时间:2019-07-13 11:24:30

标签: xpath nokogiri

我有以下XML响应代码

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><CalculatePremiumResponse xmlns="http://tempuri.org/"><XmlResult><ResponseData>&#xD;
  <ErrorDetails>&#xD;
    <ErrorCode>1a</ErrorCode>&#xD;
    <ErrorDesc>Mandatory fields missing</ErrorDesc>&#xD;
    <Remarks>PIAM Code, Body Type</Remarks>&#xD;
    <WarningInd>N</WarningInd>&#xD;
  </ErrorDetails>&#xD;
</ResponseData></XmlResult></CalculatePremiumResponse></s:Body></s:Envelope>

对此,我想获取ErrorCode元素。

我使用的是我认为应该可以使用的代码,但这不是

rt.find("./s:Body/r:CalculatePremiumResponse/r:XmlResult/r:ResponseData/r:ErrorDetails/r:ErrorCode",ns)

根据我的理解,这应该可行。它可以工作到ErrorDetails,但是当我尝试获取ErrorCode元素时,它将返回空。

感谢您的帮助

2 个答案:

答案 0 :(得分:0)

您可以使用local-name()忽略名称空间

//*[local-name()='CalculatePremiumResponse']/*[local-name()='XmlResult']/*[local-name()='ResponseData']/*[local-name()='ErrorDetails']/*[local-name()='ErrorCode']

答案 1 :(得分:0)

命名空间是必不可少的恶魔,但它们的恶魔会使我们发疯。

如果我们绝对确定它们对我们没有用,Nokogiri可以让我们将其淘汰。从您的XML样本看来,这可能是其中之一。考虑以下代码:

require 'nokogiri'

xml = Nokogiri::XML(<<EOT)
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Body>
    <CalculatePremiumResponse xmlns="http://tempuri.org/">
      <XmlResult>
        <ResponseData>
          <ErrorDetails>
            <ErrorCode>1a</ErrorCode>
            <ErrorDesc>Mandatory fields missing</ErrorDesc>
            <Remarks>PIAM Code, Body Type</Remarks>
            <WarningInd>N</WarningInd>
          </ErrorDetails>
        </ResponseData>
      </XmlResult>
    </CalculatePremiumResponse>
  </s:Body>
</s:Envelope>
EOT

目前,我们有一个看起来合理的XML文档:

xml.to_xml
# => "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
#    "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">\n" +
#    "  <s:Body>\n" +
#    "    <CalculatePremiumResponse xmlns=\"http://tempuri.org/\">\n" +
#    "      <XmlResult>\n" +
#    "        <ResponseData>\n" +
#    "          <ErrorDetails>\n" +
#    "            <ErrorCode>1a</ErrorCode>\n" +
#    "            <ErrorDesc>Mandatory fields missing</ErrorDesc>\n" +
#    "            <Remarks>PIAM Code, Body Type</Remarks>\n" +
#    "            <WarningInd>N</WarningInd>\n" +
#    "          </ErrorDetails>\n" +
#    "        </ResponseData>\n" +
#    "      </XmlResult>\n" +
#    "    </CalculatePremiumResponse>\n" +
#    "  </s:Body>\n" +
#    "</s:Envelope>\n"

运行remove_namespaces!可以清除它们:

xml.remove_namespaces!
xml.to_xml
# => "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
#    "<Envelope>\n" +
#    "  <Body>\n" +
#    "    <CalculatePremiumResponse>\n" +
#    "      <XmlResult>\n" +
#    "        <ResponseData>\n" +
#    "          <ErrorDetails>\n" +
#    "            <ErrorCode>1a</ErrorCode>\n" +
#    "            <ErrorDesc>Mandatory fields missing</ErrorDesc>\n" +
#    "            <Remarks>PIAM Code, Body Type</Remarks>\n" +
#    "            <WarningInd>N</WarningInd>\n" +
#    "          </ErrorDetails>\n" +
#    "        </ResponseData>\n" +
#    "      </XmlResult>\n" +
#    "    </CalculatePremiumResponse>\n" +
#    "  </Body>\n" +
#    "</Envelope>\n"

使我们无需担心节点即可访问节点:

xml.at('ErrorCode').text # => "1a"

有关更多信息,请参见remove_namespaces!。我不喜欢或不建议删除它们,但有时这是更简单的方法。

注意:声明节点的完整路径很少是一个好主意。浏览器喜欢通过允许我们查看其调试工具中的路径来“帮助”,但是如果节点的名称更改或在该路径中移动,则代码将中断。而是查找地标以在其中导航并找到您的目标节点。这将减少处理XML / HTML文档的脆弱性。

如果您绝对必须使用名称空间,建议您将问题带到Nokogiri mail-list,因为这是真正聪明的人闲逛的地方。