gpt4 book ai didi

php - 在 PHP 中使用 importNode、namespace 和 appendChild 的奇怪事情

转载 作者:行者123 更新时间:2023-12-04 17:01:46 24 4
gpt4 key购买 nike

我发现 importNode 之后的 xml 会有一个“默认”前缀。经过一些实验,我发现了一些奇怪的现象。
如何解释以下结果:
代码在这里:

<?php
$dom = new DOMDocument();
$xml = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<A xmlns="xmlns://www.abc.com"><B/></A>
XML;
$dom->loadXML($xml);
$new_dom = new DOMDocument();
$new_root = $new_dom->createElement("root");
$new_node = $new_dom->importNode($dom->documentElement->childNodes->item(0), TRUE);

//order is important
$new_dom->appendChild($new_root); //1
$new_root->appendChild($new_node); //2
$new_node->removeAttributeNS("xmlns://www.abc.com", ""); //3
//

echo $new_dom->saveXML()
?>

123
<?xml version="1.0"?>
<root><B/></root>

132,231,321,312
<?xml version="1.0"?>
<root><default:B/></root>

213
<?xml version="1.0"?>
<root xmlns:default="xmlns://www.abc.com"><default:B/></root>

最佳答案

您正在删除使用的命名空间的命名空间定义。根据调用的顺序,会触发不同的修复/回退。删除/更改命名空间的预期方法是遍历并重新创建节点。

libxml 对命名空间定义做了一些优化和回退。如果您做了“奇怪”的事情,它可能会替换命名空间别名,并且可能会破坏结果。触发器是具有命名空间的属性。但没有前缀。与元素不同,命名空间内的属性必须有前缀。这是触发默认命名空间前缀的示例:

$document = new DOMDocument();
$document->appendChild($document->createElementNS('urn:1', 'foo'));
// add attribute in namespace without prefix
$document->documentElement->setAttributeNS('urn:1', 'bar', 21);
echo $document->saveXML();

输出:
<?xml version="1.0"?> 
<foo xmlns="urn:1" xmlns:default="urn:1" default:bar="21"/>

即使您为属性使用前缀,libxml 也会识别出它与默认元素命名空间相同的命名空间并尝试优化:
$document = new DOMDocument();
$document->appendChild($document->createElementNS('urn:1', 'foo'));
// add attribute in element namespace with prefix
$document->documentElement->setAttributeNS('urn:1', 'b:bar', 21);
echo $document->saveXML();

我的规则是,如果我需要在命名空间内添加属性,则始终为命名空间使用前缀。
$document = new DOMDocument();
$document->appendChild($document->createElementNS('urn:1', 'b:foo'));
$document->documentElement->setAttributeNS('urn:1', 'b:bar', 21);
echo $document->saveXML();

输出:
<?xml version="1.0"?> 
<b:foo xmlns:b="urn:1" b:bar="21"/>
$new_node->removeAttributeNS("xmlns://www.abc.com", "");告诉 DOM 删除命名空间内的一个属性 xmlns://www.abc.com没有名字。然而 xmlns=""不是属性,而是命名空间定义。它使用相同的语法,并且在某些情况下可以使用属性方法进行修改,但 libxml 可能会再次添加它,因为后代或属性节点位于命名空间内并且需要定义。

将它们视为属性 xmlns="..."不在任何 namespace 和 namespace 定义中,前缀类似于 xmlns:foo="..."在保留的命名空间内 http://www.w3.org/2000/xmlns/ . imho 删除命名空间定义的正确调用是:
// xmlns="..."
$node->removeAttributeNS(NULL, 'xmlns');
// xmlns:prefix="..." - broken in PHP or libxml?
$node->removeAttributeNS('http://www.w3.org/2000/xmlns/', 'prefix');

例子:
$document = new DOMDocument();
$document->appendChild($document->createElementNS('urn:1', 'b:foo'));
$document->documentElement->setAttributeNS(NULL, 'xmlns', 'urn:2');
$document->documentElement->setAttributeNS(
'http://www.w3.org/2000/xmlns/', 'xmlns:bar', 'urn:3'
);
echo $document->saveXML();
$document->documentElement->removeAttributeNS(NULL, 'xmlns');
echo $document->saveXML();
// for some reason that does not work
$document->documentElement->removeAttributeNS(
'http://www.w3.org/2000/xmlns/', 'bar'
);
echo $document->saveXML();
// but this works - weird
$document->documentElement->removeAttributeNS('urn:3', 'bar');
echo $document->saveXML();

输出:
<?xml version="1.0"?> 
<b:foo xmlns:b="urn:1" xmlns:bar="urn:3" xmlns="urn:2"/>
<?xml version="1.0"?>
<b:foo xmlns:b="urn:1" xmlns:bar="urn:3"/>
<?xml version="1.0"?>
<b:foo xmlns:b="urn:1" xmlns:bar="urn:3"/>
<?xml version="1.0"?>
<b:foo xmlns:b="urn:1"/>

关于php - 在 PHP 中使用 importNode、namespace 和 appendChild 的奇怪事情,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53293167/

24 4 0