我有以下XML响应代码
<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>
对此,我想获取ErrorCode元素。
我使用的是我认为应该可以使用的代码,但这不是
rt.find("./s:Body/r:CalculatePremiumResponse/r:XmlResult/r:ResponseData/r:ErrorDetails/r:ErrorCode",ns)
根据我的理解,这应该可行。它可以工作到ErrorDetails
,但是当我尝试获取ErrorCode元素时,它将返回空。
感谢您的帮助
答案 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,因为这是真正聪明的人闲逛的地方。