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::$localNameXMLReader::$namespaceURI.

这里有两个从文档中读取命名空间的正当理由。

  1. 通用转换(如 XML 到 JsonML)
  2. 调试

在这种情况下,迭代元素后代并读取具有节点名称 xmlnshttp://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"
  }
}