Как предотвратить префикс «default» при добавлении потомка с пространством имен по умолчанию? - PullRequest
1 голос
/ 15 апреля 2019

Простой DOMDocument и добавление двух дочерних узлов, один без и один с пространством имен по умолчанию:

$dom = new DOMDocument();
$dom->loadXML('<list/></list>');
$dom->formatOutput = true;

$docX = new DOMDocument();
$docX->loadXML('<item><one>bar</one></item>');

$dom->documentElement->appendChild($dom->importNode($docX->documentElement, true));
print($dom->saveXML()); // OK

$docY = new DOMDocument();
$docY->loadXML('<item><two xmlns="xxx:yyy">tar</two></item>');

$dom->documentElement->appendChild($dom->importNode($docY->documentElement, true));
print($dom->saveXML()); // Not OK

Добавление дочернего узла без атрибута xmlns работает нормально:

<?xml version="1.0"?>
<list>
  <item>
    <one>bar</one>
  </item>
</list>

При добавлении дочернего узла с пространством имен по умолчанию (т. Е. Атрибут xmlns) PHP добавляет псевдоним default для этого пространства имен:

<?xml version="1.0"?>
<list>
  ...
  <item xmlns:default="xxx:yyy">
    <default:two xmlns="xxx:yyy">tar</default:two>
  </item>
</list>

Я никогда не видел его в своем коде 15+ летв PHP.Есть ли рекомендуемый обходной путь, чтобы избежать такого поведения?

В гораздо более сложном сценарии я пытался просто установить для этого префикса значение null после вызова appendChild(), но он выдает загадочное сообщение DOMException: Namespace Error.Этот упрощенный пример этого не делает, вместо этого он генерирует следующий XML:

<?xml version="1.0"?>
<list>
  ...
  <item xmlns:default="xxx:yyy">
    <:two xmlns="xxx:yyy" xmlns:="xxx:yyy">tar</:two>
  </item>
</list>

В качестве обходного пути после добавления дочернего элемента я клонирую его, удаляя все пространства имен префиксов в процессе, удаляя исходный дочерний элемент.вместо добавления клона (префикса default нет) и повторного добавления префиксов, где:

function stripNamespace($dom, $target) {
    $clone = $dom->createElement(preg_replace('`.*:`', '', $target->nodeName));

    foreach ($target->attributes as $v)
        $clone->setAttribute($v->nodeName, $v->value);

    foreach ($target->childNodes as $child)
        $clone->appendChild(
            $child->nodeName == "#text" ?
                $dom->createTextNode($child->nodeValue) :
                $this->stripNamespace($dom, $child)
        );

    return $clone;
}

Есть ли менее громоздкий способ справиться с этим?

...