这听起来很容易回答,但我无法让它发挥作用。我正在运行PHP 5.2.6。
我有一个DOM元素(根元素),当我转到$ element-> saveXML()时,它会输出一个xmlns属性:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
...
但是,我无法在PHP中以编程方式找到任何方式来查看该命名空间。我希望能够检查它是否存在以及它的设置。
检查$document->documentElement->namespaceURI
将是明显的答案,但这是空的(我实际上从来没有能够将其变为非空)。什么在输出中生成xmlns值以及如何读取它?
到目前为止,我能够做到这一点的唯一实用方法是完全破解 - 通过使用saveXML()将其保存为字符串,然后使用正则表达式读取它。
编辑:
这可能是使用loadHTML()而不是loadXML()加载XML然后使用saveXML()打印出来的一种特性。当你这样做时,似乎由于某种原因,saveXML添加了一个xmlns属性,即使没有办法使用DOM方法检测到这个xmlns值是文档的一部分。我想这意味着如果我有办法检测传入的文件是否已经使用loadHTML()加载,那么我可以用不同的方式解决这个问题。
答案 0 :(得分:5)
Like edorian already showed,当标记加载loadXML
时,获取命名空间的工作正常。但你是对的,这对于装有loadHTML
的Markup来说不适用:
$html = <<< XML
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:m="foo" lang="en">
<body xmlns="foo">Bar</body>
</html>
XML;
$dom = new DOMDocument;
$dom->loadHTML($html);
var_dump($dom->documentElement->getAttribute("xmlns"));
var_dump($dom->documentElement->lookupNamespaceURI(NULL));
var_dump($dom->documentElement->namespaceURI);
会产生空的结果。但是你可以使用XPath
$xp = new DOMXPath($dom);
echo $xp->evaluate('string(@xmlns)');
// http://www.w3.org/1999/xhtml;
和身体
echo $xp->evaluate('string(body/@xmlns)'); // foo
或与上下文节点
$body = $dom->documentElement->childNodes->item(0);
echo $xp->evaluate('string(@xmlns)', $body);
// foo
我没有受过教育的假设是,在内部,HTML文档与真实文档不同。内部libxml uses a different module to parse HTML和DOMDocument本身将具有不同的nodeType,因为您只需通过执行验证
var_dump($dom->nodeType); // 13 with loadHTML, 9 with loadXml
答案 1 :(得分:3)
使用PHP 5.2.6我发现了两种方法:
<?php
$xml = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?'.
'><html xmlns="http://www.w3.org/1999/xhtml" lang="en"></html>';
$x = DomDocument::loadXml($xml);
var_dump($x->documentElement->getAttribute("xmlns"));
var_dump($x->documentElement->lookupNamespaceURI(NULL));
打印
string(28) "http://www.w3.org/1999/xhtml"
string(28) "http://www.w3.org/1999/xhtml"
希望这就是你所要求的:)
答案 2 :(得分:1)
嗯,你可以用这样的函数来做到这一点:
function getNamespaces(DomNode $node, $recurse = false) {
$namespaces = array();
if ($node->namespaceURI) {
$namespaces[] = $node->namespaceURI;
}
if ($node instanceof DomElement && $node->hasAttribute('xmlns')) {
$namespaces[] = $xmlns = $node->getAttribute('xmlns');
foreach ($node->attributes as $attr) {
if ($attr->namespaceURI == $xmlns) {
$namespaces[] = $attr->value;
}
}
}
if ($recurse && $node instanceof DomElement) {
foreach ($node->childNodes as $child) {
$namespaces = array_merge($namespaces, getNamespaces($child, vtrue));
}
}
return array_unique($namespaces);
}
所以,你给它一个DomEelement,然后它找到所有相关的命名空间:
$xml = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<html xmlns="http://www.w3.org/1999/xhtml"
lang="en"
xmlns:foo="http://example.com/bar">
<body>
<h1>foo</h1>
<foo:h2>bar</foo:h2>
</body>
</html>';
var_dump(getNamespaces($dom->documentElement, true));
打印出来:
array(2) {
[0]=>
string(28) "http://www.w3.org/1999/xhtml"
[3]=>
string(22) "http://example.com/bar"
}
请注意,DomDocument会自动删除所有未使用的命名空间......
至于为什么$dom->documentElement->namespaceURI
总是null
,这是因为文档元素没有命名空间。 xmlns
属性为文档提供默认命名空间,但它不为html
标记赋予命名空间(用于DOM交互)。您可以尝试$dom->documentElement->removeAttribute('xmlns')
,但我不能100%确定它是否有用......