XMLReader - Получить все пространства имен в документе - PullRequest
0 голосов
/ 14 марта 2020

Есть ли способ получить пространства имен в документе XML с использованием XMLReader? На данный момент я использую SimpleXMLElement::getDocNamespaces() для выполнения этой работы, но поскольку я работаю с довольно большими документами, есть недостаток, поскольку (насколько я знаю) Simple XML загружает весь документ сразу в отношении использования памяти.

Спасибо за любую помощь!

Ответы [ 2 ]

1 голос
/ 14 марта 2020

Чтобы прочитать XML с пространствами имен, вам не нужно знать префикс, используемый в документе. Вам нужно знать и сравнивать URI пространства имен. Поэтому не сравнивайте XMLReader::$name, но XMLReader::$localName и XMLReader::$namespaceURI.

Вот две веские причины для чтения пространства имен из документа.

  1. Generi c Конвертация ( как XML в JsonML)
  2. Отладка

В этом случае итерируйте потомков элементов и прочитайте атрибуты с именем узла 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"
  }
}
1 голос
/ 14 марта 2020

На основе кода из { ссылка }, который показывает, как читать атрибуты документа с использованием 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);
...