XMLReader - 获取文档中的所有命名空间
XMLReader - Get all namespaces in document
有没有办法使用 XMLReader 获取 XML 文档中的命名空间?
现在我正在使用 SimpleXMLElement::getDocNamespaces()
来完成这项工作,但是由于我正在处理相当大的文档,所以有一个缺点,因为(据我所知)SimpleXML 会立即加载整个文档内存使用。
感谢您的帮助!
基于 中显示如何使用 XMLReader 读取文档属性的代码,这只是检查属性是否具有前缀 xmlns
,如果有,它会添加使用前缀(即 localName
值)/URI(即属性值)将其放入命名空间列表中...
$xml = new XMLReader;
$xml->open($fileName);
$doc = new DOMDocument;
$namespaces = [];
while ($xml->read()) {
if($xml->hasAttributes) {
while($xml->moveToNextAttribute()) {
if ( $xml->prefix == 'xmlns' ) {
$namespaces [ $xml->localName ] = $xml->value;
}
}
}
}
print_r($namespaces);
要使用命名空间阅读 XML,您不需要知道文档中使用的前缀。您需要知道并比较名称空间 URI。所以不要比较 XMLReader::$name
但是
XMLReader::$localName
和 XMLReader::$namespaceURI
.
这里有两个从文档中读取命名空间的正当理由。
- 通用转换(如 XML 到 JsonML)
- 调试
在这种情况下,迭代元素后代并读取具有节点名称 xmlns
和 http://www.w3.org/2000/xmlns/
命名空间中的属性。
请注意,只有名称空间 URI 是唯一的。前缀不是唯一的或总是必需的。
演示:
$xml = <<<'XML'
<f:foo xmlns:f="urn:a" xmlns="urn:default" xmlns:b="urn:b">
<f:bar xmlns:f="urn:c" xmlns="urn:a"/>
</f:foo>
XML;
$xmlUrl = 'data://text/plain;base64,'.base64_encode($xml);
$reader = new XMLReader();
$reader->open($xmlUrl);
$namespaces = [];
while ($reader->read()) {
if ($reader->nodeType == XMLReader::ELEMENT && $reader->hasAttributes) {
while ($reader->moveToNextAttribute()) {
if ($reader->name === 'xmlns') {
$namespaces[$reader->value][] = '#default';
} elseif ($reader->namespaceURI === 'http://www.w3.org/2000/xmlns/') {
$namespaces[$reader->value][] = $reader->localName;
}
}
}
}
var_dump($namespaces);
输出:
array(4) {
["urn:a"]=>
array(2) {
[0]=>
string(1) "f"
[1]=>
string(8) "#default"
}
["urn:default"]=>
array(1) {
[0]=>
string(8) "#default"
}
["urn:b"]=>
array(1) {
[0]=>
string(1) "b"
}
["urn:c"]=>
array(1) {
[0]=>
string(1) "f"
}
}
有没有办法使用 XMLReader 获取 XML 文档中的命名空间?
现在我正在使用 SimpleXMLElement::getDocNamespaces()
来完成这项工作,但是由于我正在处理相当大的文档,所以有一个缺点,因为(据我所知)SimpleXML 会立即加载整个文档内存使用。
感谢您的帮助!
基于 中显示如何使用 XMLReader 读取文档属性的代码,这只是检查属性是否具有前缀 xmlns
,如果有,它会添加使用前缀(即 localName
值)/URI(即属性值)将其放入命名空间列表中...
$xml = new XMLReader;
$xml->open($fileName);
$doc = new DOMDocument;
$namespaces = [];
while ($xml->read()) {
if($xml->hasAttributes) {
while($xml->moveToNextAttribute()) {
if ( $xml->prefix == 'xmlns' ) {
$namespaces [ $xml->localName ] = $xml->value;
}
}
}
}
print_r($namespaces);
要使用命名空间阅读 XML,您不需要知道文档中使用的前缀。您需要知道并比较名称空间 URI。所以不要比较 XMLReader::$name
但是
XMLReader::$localName
和 XMLReader::$namespaceURI
.
这里有两个从文档中读取命名空间的正当理由。
- 通用转换(如 XML 到 JsonML)
- 调试
在这种情况下,迭代元素后代并读取具有节点名称 xmlns
和 http://www.w3.org/2000/xmlns/
命名空间中的属性。
请注意,只有名称空间 URI 是唯一的。前缀不是唯一的或总是必需的。
演示:
$xml = <<<'XML'
<f:foo xmlns:f="urn:a" xmlns="urn:default" xmlns:b="urn:b">
<f:bar xmlns:f="urn:c" xmlns="urn:a"/>
</f:foo>
XML;
$xmlUrl = 'data://text/plain;base64,'.base64_encode($xml);
$reader = new XMLReader();
$reader->open($xmlUrl);
$namespaces = [];
while ($reader->read()) {
if ($reader->nodeType == XMLReader::ELEMENT && $reader->hasAttributes) {
while ($reader->moveToNextAttribute()) {
if ($reader->name === 'xmlns') {
$namespaces[$reader->value][] = '#default';
} elseif ($reader->namespaceURI === 'http://www.w3.org/2000/xmlns/') {
$namespaces[$reader->value][] = $reader->localName;
}
}
}
}
var_dump($namespaces);
输出:
array(4) {
["urn:a"]=>
array(2) {
[0]=>
string(1) "f"
[1]=>
string(8) "#default"
}
["urn:default"]=>
array(1) {
[0]=>
string(8) "#default"
}
["urn:b"]=>
array(1) {
[0]=>
string(1) "b"
}
["urn:c"]=>
array(1) {
[0]=>
string(1) "f"
}
}