gpt4 book ai didi

XML::LibXML 和命名空间

转载 作者:行者123 更新时间:2023-12-04 16:53:19 26 4
gpt4 key购买 nike

我熟悉 XML,已经将它用于一些简单的用途。但是,我被要求创建一个自定义解决方案(必须使用 Perl)来向 AuthorizeNet 的网关提交付款。 AuthNet 不提供对 Perl 的支持,所以我只能靠自己。

我正在使用 AuthNet 的 latest method ,它依赖于以 XML 格式发送和接收交易数据。

我已经成功地使用 Perl 模块 XML::LibXML 成功提交并批准了测试(沙盒)事务。 .

我在尝试解析返回数据时遇到了障碍。我终于发现我是第一次处理命名空间。我得到的沙箱返回数据如下。

<createTransactionResponse
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd">

<refId />

<messages>
<resultCode>Ok</resultCode>
<message>
<code>I00001</code>
<text>Successful.</text>
</message>
</messages>

<transactionResponse>
<responseCode>1</responseCode>
<authCode>GTR92Q</authCode>
<avsResultCode>Y</avsResultCode>
<cvvResultCode>P</cvvResultCode>
<cavvResultCode>2</cavvResultCode>
<transId>40003699670</transId>
<refTransID />
<transHash>7E1148E18D5D0E0BE202EB1BCE4B0F09</transHash>
<testRequest>0</testRequest>
<accountNumber>XXXX1111</accountNumber>
<accountType>Visa</accountType>
<messages>
<message>
<code>1</code>
<description>This transaction has been approved.</description>
</message>
</messages>
<userFields>
<userField>
<name>MerchantDefinedFieldName1</name>
<value>MerchantDefinedFieldValue1</value>
</userField>
</userFields>
<transHashSha2 />
</transactionResponse>

</createTransactionResponse>

我需要从中提取某些值。我把上面的数据,从AuthNet网关返回,存储在变量 $cont中,并准备它:
my $dom = XML::LibXML->load_xml(string => $cont);

然后我尝试解析数据节点,搜索某些值,例如:
foreach my $transres ($dom->findnodes("/createTransactionResponse/messages/message")) {
print "Message: " . $transres->to_literal() . "<br />\n";
}

这永远不会返回任何值。然后我意识到我正在处理命名空间问题。我尝试了许多注册命名空间的变体,但无济于事,例如:
my $xpc = XML::LibXML::XPathContext->new($dom);
$xpc->registerNs("xsi", "http://www.w3.org/2001/XMLSchema-instance");
$xpc->registerNs("xsd", "http://www.w3.org/2001/XMLSchema");

foreach my $transres ($xpc->findnodes("//xsi:resultCode")) {
print "Result: " . $transres->to_literal() . "<br />\n";
}

这一切都只是在胡思乱想,希望得到某种结果。我注意到,即使返回数据引用多个命名空间,它们实际上都没有在其余数据的任何地方使用。我发现了许多关于 XML 命名空间问题的 StackOverflow 响应,但我找不到一个示例,说明当 XML 数据的其他地方没有使用任何指定的命名空间时如何引用节点。比如,当没有命名空间被引用时,要使用的默认命名空间引用是什么(如果你愿意的话)......如果这是有道理的。

我遇到了一个 entry elsewhere in StackOverflow ,其中提到使用允许忽略命名空间的“本地名称”函数。我以为这样可以绕过问题,当我尝试时,我终于看到了一些数据显示。
foreach my $transres ($dom->findnodes("//*[local-name()='resultCode']")) {
print "Result: " . $transres->to_literal() . "<br />\n";
}

这导致返回所需/预期值“Ok”。它也适用于我迄今为止尝试过的其他节点。但是,我通常对使用“只是忽略它”类型的解决方案持怀疑态度,除非它们确实合适并且需要。

我的问题归结为:我用来最终从返回的 XML 数据访问数据的旁路命名空间方法是否可取?

我想知道为什么 AuthNet 在返回数据中指定多个命名空间,然后在数据中不使用它们 - 至少是我目前正在返回的数据。如果我只是绕过代码中的命名空间,但后来,尤其是当我们上线时,不同的命名空间变得相关怎么办?我实际上不知道,我能够获得的 AuthNet 所谓的“支持”从无用到完全无响应。

非常感谢那些对 Perl/XML/命名空间问题更有经验的人的任何建议/指导。

最佳答案

你大致上是正确的。问题是您的 XML 数据使用默认命名空间,该命名空间适用于所有没有显式命名空间前缀的标识符

xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd"

正如您所观察到的, xsixsd您的数据中未使用前缀,因此无需在您的 Perl 代码中指定它们。同时,XPath 没有隐式命名空间的概念,因此您必须为 AuthNet 命名空间指定一个显式缩写并在所有 XPath 表达式中使用它。

所使用的缩写不必与 XML 数据中定义的缩写相同,而且很明显,在默认命名空间的情况下它不能匹配。

下面是我将如何编码您对 resultCode 的访问元素。我总是喜欢使用来自文档根目录的完整 XPath 表达式,而不是使用 //anet:resultCode 搜索文档中的所有元素。
my $dom = XML::LibXML->load_xml( string => $cont );

my $xpc = XML::LibXML::XPathContext->new( $dom );
$xpc->registerNs( anet => 'AnetApi/xml/v1/schema/AnetApiSchema.xsd' );

for my $transres ( $xpc->findnodes('/anet:createTransactionResponse/anet:messages/anet:resultCode' ) ) {
printf "Result: %s<br />\n", $transres->to_literal;
}

关于XML::LibXML 和命名空间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39969027/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com