Tertium Tertium - 28 days ago 7
PHP Question

Getting an XML attribute with DOMXPath in PHP ignoring namespaces

I have an XML file:

<Receipt Version="2.0" ReceiptDate="2012-08-30T23:10:05Z" CertificateId="A656B9B1B3AA509EEA30222E6D5E7DBDA9822DCD" xmlns="http://schemas.microsoft.com/windows/2012/store/receipt">
....
</Receipt>


and I try to get
CertificateId
with XPath in PHP:

$doc = new DOMDocument();
$doc->loadXML($v);
$xpath = new DOMXPath($doc);
$query = 'string(/Receipt/@CertificateId)';
$id = $xpath->evaluate($query);


$id
is void because
Msft
has abandoned this link, so the namespace is not accessible, that is I have to get
CertificateId
ignoring namespace (if I remove namespace string from XML, my code works, but I'd prefer to not edit XML). I know it can be done with
local-name()
XPath function, but how can I do this in PHP?




Here's how I read it from DOM:

$id = null;
if ($doc->childNodes->length > 0)
{
$root = $doc->childNodes->item(0);
if ($root->nodeName == 'Receipt')
$id = $root->attributes->getNamedItem('CertificateId')->nodeValue;
}


This code ignores namespaces. But how to do this using XPath?

Answer

In XPath 2.0 you might use a wildcard for the namespace part: string(//*:Receipt/@CertificateId). However, PHP currently implements only XPath 1.0, as far as I know.

You can either register the namespace:

$xpath->registerNamespace('x', 'http://schemas.microsoft.com/windows/2012/store/receipt');
$query = 'string(//x:Receipt/@CertificateId)';

or select only attributes, if you don't want to even mention specific namespace:

$query = 'string(//*/@CertificateId)';

Otherwise, you are forced to use local-name:

$query = "string(//*[local-name(.) = 'Receipt']/@CertificateId)";