Reputation: 6308
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?
Upvotes: 2
Views: 1033
Reputation: 19502
Here is no need to ignore the namespace. Namespaces do not have to be existing URLs. They have to be globally unique URNs. Many people use an URL with an domain they own, not much chance of an conflict that way. And you can put some documentation there.
To use an namespace in Xpath, just register a prefix for it:
$xml = <<<'XML'
<Receipt
Version="2.0"
ReceiptDate="2012-08-30T23:10:05Z"
CertificateId="A656B9B1B3AA509EEA30222E6D5E7DBDA9822DCD"
xmlns="http://schemas.microsoft.com/windows/2012/store/receipt">
</Receipt>
XML;
$document = new DOMDocument();
$document->loadXml($xml);
$xpath = new DOMXpath($document);
$xpath->registerNamespace(
'sr', 'http://schemas.microsoft.com/windows/2012/store/receipt'
);
var_dump(
$xpath->evaluate('string(//sr:Receipt/@CertificateId)')
);
Output:
string(40) "A656B9B1B3AA509EEA30222E6D5E7DBDA9822DCD"
An example for an URN namespace is rfc6321
If you don't like to use Xpath (Can't imagine why). You can use the namespace aware DOM methods and properties.
$id = null;
if ($document->childNodes->length > 0) {
$node = $document->childNodes->item(0);
if (
$node->localName == 'Receipt' &&
$node->namespaceURI == 'http://schemas.microsoft.com/windows/2012/store/receipt'
) {
$id = $node->getAttributeNS(null, 'CertificateId');
}
}
var_dump($id);
Upvotes: 1
Reputation: 21492
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)";
Upvotes: 1