我有一个XML文件:
<Receipt Version="2.0" ReceiptDate="2012-08-30T23:10:05Z" CertificateId="A656B9B1B3AA509EEA30222E6D5E7DBDA9822DCD" xmlns="http://schemas.microsoft.com/windows/2012/store/receipt">
....
</Receipt>
,我尝试在PHP中使用XPath获取CertificateId
:
$doc = new DOMDocument();
$doc->loadXML($v);
$xpath = new DOMXPath($doc);
$query = 'string(/Receipt/@CertificateId)';
$id = $xpath->evaluate($query);
$id
是空的,因为Msft
已经放弃了这个链接,所以名称空间是不可访问的,也就是说,我必须得到CertificateId
忽略名称空间(如果我从XML中删除名称空间字符串,我的代码工作,但我宁愿不编辑XML)。我知道这可以用local-name()
XPath函数完成,但我如何在PHP中做到这一点?
下面是我从DOM中读取它的方法:
$id = null;
if ($doc->childNodes->length > 0)
{
$root = $doc->childNodes->item(0);
if ($root->nodeName == 'Receipt')
$id = $root->attributes->getNamedItem('CertificateId')->nodeValue;
}
这段代码忽略名称空间。但是如何使用XPath做到这一点呢?
在XPath 2.0中,可以对名称空间部分使用通配符:string(//*:Receipt/@CertificateId)
。但是,据我所知,PHP目前只实现了XPath 1.0。
您可以注册命名空间:
$xpath->registerNamespace('x', 'http://schemas.microsoft.com/windows/2012/store/receipt');
$query = 'string(//x:Receipt/@CertificateId)';
或者只选择属性,如果您甚至不想提及特定的名称空间:
$query = 'string(//*/@CertificateId)';
否则,您将被迫使用local-name
:
$query = "string(//*[local-name(.) = 'Receipt']/@CertificateId)";
这里不需要忽略名称空间。名称空间不必是现有的url。它们必须是全局唯一的urn。许多人将URL与他们拥有的域名一起使用,这样就不会有太多冲突的机会。你可以在那里放一些文档
要在Xpath中使用名称空间,只需为它注册一个前缀:
$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)')
);
输出:string(40) "A656B9B1B3AA509EEA30222E6D5E7DBDA9822DCD"
URN命名空间的示例为rfc6321
如果您不喜欢使用Xpath(无法想象为什么)。你可以使用感知命名空间的DOM方法和属性。
$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);