I'm familiar with XML, having put it to some simple uses. However, I've been requested to create a custom solution (that must use Perl) for submitting payments to AuthorizeNet's gateway. AuthNet offers no support for Perl, so I'm on my own.
I am using AuthNet's latest method, which relies on sending and receiving transaction data in XML format.
I have managed to get test (sandbox) transactions successfully submitted and approved, using the Perl module XML::LibXML.
I hit a snag when trying to parse the return data. I finally figured out I was dealing with namespaces for the first time. The sandbox return data I get is as follows.
<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>
I need to extract certain values from that. I take the above data, returned from the AuthNet gateway, store it in the var $cont
, and prepare it:
my $dom = XML::LibXML->load_xml(string => $cont);
Then I attempt to parse through the data nodes, searching for certain values, for example:
foreach my $transres ($dom->findnodes("/createTransactionResponse/messages/message")) {
print "Message: " . $transres->to_literal() . "<br />\n";
}
This never returns any values. Then I realized I was dealing with namespace issues. I tried many variations of registering the namespaces, to no avail, for example:
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";
}
This was all just casting about, hoping for some kind of result. I noticed that, even though the return data refers to multiple namespaces, none of them actually get used anywhere in the rest of the data. I found a number of StackOverflow responses on the XML namespace issue, but I could never find an example of how to reference nodes when none of the specified namespaces get used elsewhere in the XML data. Like, what is the default (if you will) namespace reference to use, when no namespace get referenced... If that makes sense.
I came across an entry elsewhere in StackOverflow, wherein it mentions using a "local-name" function that allows the ignoring of namespaces. I thought that might bypass the problem, and when I tried it, I did finally see some data display.
foreach my $transres ($dom->findnodes("//*[local-name()='resultCode']")) {
print "Result: " . $transres->to_literal() . "<br />\n";
}
This resulted in the return of the desired/expected value "Ok". It also works on the other nodes I have tried thus far. However, I am usually leery of using "just ignore it" type solutions, unless they are genuinely appropriate and called for.
My question comes down to this: Is the bypass-namespace method I used to finally access data from the returned XML data advisable?
I was wondering why AuthNet specifies multiple namespaces in the return data, and then uses none of them in the data - at least the data I am currently getting back. What if I just bypass the namespaces in my code, but then later, especially when we go live, the different namespaces become relevant? I actually don't know, and the AuthNet so-called "support" I have been able to reach has ranged from unhelpful to completely unresponsive.
Any advice/guidance from those more experienced with Perl/XML/namespace issues would be greatly appreciated.