php - 使节点在更改 XML 结构后忽略命名空间(前缀)。 PHP DOM文档

标签 php xml dom namespaces domdocument

原始 XML (myfile.xml)

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<blabla
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:cc="http://creativecommons.org/ns#"
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:blabla="http://www.w3.org/2000/blabla"
    xmlns="http://www.w3.org/2000/blabla"
    version="1.0">
    <title>Hello there</title>
    <metadata>
        <rdf:RDF>
            <cc:whtaat />
        </rdf:RDF>
    </metadata>
    <sometag>
        <anothertag id="anothertag1111">
            <andanother id="yep" />
        </anothertag >
    </sometag>
</blabla>

目的是在文档根节点下直接添加一个子节点,并将“原始”子节点“推”到新子节点下:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<blabla
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:cc="http://creativecommons.org/ns#"
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:blabla="http://www.w3.org/2000/blabla"
    xmlns="http://www.w3.org/2000/blabla"
    version="1.0">
    <magic>
        <title>Hello there</title>
        <metadata>
            <rdf:RDF>
                <cc:whtaat />
            </rdf:RDF>
        </metadata>
        <sometag>
            <anothertag id="anothertag1111">
                <andanother id="yep" />
            </anothertag >
        </sometag>
    </magic>
</blabla>

这个 php 脚本就是这样做的
<?php 
header("Content-type: text/xml");
// Create dom document
$doc = new DOMDocument(); 
$doc->load("myfile.xml");
$doc->preserveWhiteSpace = false; 
$doc->formatOutput = true; 
// Get first child (blabla)
$blablaNode = $doc->firstChild;
// Crete magic element to hold all children in blabla 
$magicElement = $doc->createElement('magic');
while($blablaNode->hasChildNodes()) {
    // Remove child from blablaNode and append it into magicElement
    $magicElement->appendChild($blablaNode->removeChild($blablaNode->firstChild));
}
// Append magicElement to blablaNode
$magicElement = $blablaNode->appendChild($magicElement);
echo $doc->saveXML();
?>

但是输出是
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<blabla xmlns:dc="http://purl.org/dc/elements/1.1/"
        xmlns:cc="http://creativecommons.org/ns#"
        xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
        xmlns:blabla="http://www.w3.org/2000/blabla"
        xmlns="http://www.w3.org/2000/blabla" version="1.0">
<magic>
    <blabla:title xmlns:default="http://www.w3.org/2000/blabla">Hello there</blabla:title>
    <blabla:metadata xmlns:default="http://www.w3.org/2000/blabla" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:cc="http://creativecommons.org/ns#">
        <rdf:RDF>
            <cc:whtaat/>
        </rdf:RDF>
    </blabla:metadata>
    <blabla:sometag xmlns:default="http://www.w3.org/2000/blabla">
        <blabla:anothertag id="anothertag1111">
            <blabla:andanother id="yep"/>
        </blabla:anothertag>
    </blabla:sometag>
</magic>
</blabla>

所以每个节点(在“默认”命名空间中)都附加了“blaba”前缀
<blabla:title />

如何避免这种情况?
如果将 PHP 更改为
while($blablaNode->hasChildNodes()) {
$removedChild = $blablaNode->removeChild($blablaNode->firstChild);
echo "(prefix for removed:".$removedChild->prefix.")";
$magicElement->appendChild($removedChild);
echo "(prefix for added:".$magicElement->lastChild->prefix.")";
}

echo 是 ...(删除的前缀:)(添加的前缀:)(删除的前缀:)(添加的前缀: 默认)...

提前谢谢了!

附言这是 this 的续集因此问题“或者也许有人有更好的解决方案来实现理想的结果[添加魔术节点并推送其中的所有内容]”仍然适用......

事实上,如果“将默认命名空间声明放在首位”,正如 Josh Davis 所指出的那样,查找前缀就会消失。 +1。但这就是输出......
...  
<metadata xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"  
xmlns:cc="http://creativecommons.org/ns#">
...  

...声明仍然存在。
澄清。我不是那些 XML 文档的创建者。因此检查默认命名空间声明的位置......即使实现它仍然不会给出理想的结果。即使按照标准,libxml 添加的那些声明应该在那里,我的任务也不是验证一致性,而是
- 简单地放置所有原始子节点,完整的内容(声明、名称值、属性等) , 在那个额外的新创建的容器下。

最佳答案

当您附加这些子项时,我猜 libxml 会查找“http://www.w3.org/2000/blabla”的第一个命名空间声明并找到“blabla”。现在,如果您将默认命名空间声明放在首位,它会发现默认命名空间有效,并且不会在这些节点前面加上 blabla。

<blabla xmlns="http://www.w3.org/2000/blabla"
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:cc="http://creativecommons.org/ns#"
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:blabla="http://www.w3.org/2000/blabla"
    version="1.0">

更新

这个问题完全是装饰性的,但如果您想删除多余的命名空间声明,您可以转储并重新加载您的 XML:
$xml = $doc->saveXML();
$doc = new DOMDocument;
$doc->loadXML($xml, LIBXML_NSCLEAN);
echo $doc->saveXML();

如果您重复使用 $doc,请注意变量,这并不意味着像 $blablaNode 这样的东西将保持功能,它不会。新款$doc是一个新文件。

哦,它还会从原始文档中清除多余的 namespace ,可能会破坏“保持完整”规则。

哦,我忘了提到你必须明确声明哪个命名空间 <magic/>将被创建为:
$magicElement = $doc->createElementNS('http://www.w3.org/2000/blabla', 'magic');

关于php - 使节点在更改 XML 结构后忽略命名空间(前缀)。 PHP DOM文档,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3073631/

相关文章:

php - 使用多个表从 xenforo 数据库在 Laravel 中进行用户身份验证

php - 从具有 "AUTO_INCREMENT"的字段中获取未使用的 id - mysql

xml - XML XPath 1.0-如何在XPath表达式中正确使用'not'函数

javascript - Contenteditable DIV - 如何确定光标是在内容的开头还是结尾

javascript - 为什么jQuery或诸如getElementById之类的DOM方法找不到元素?

javascript - React refs - 使用 refs 访问 DOM 节点

php - 如何从选择框中选择多个选项

c# - HttpWebRequest 收到 "WebException: The request timed out"

xml - 将图像插入 XML 文件

xml - postgresql query_to_xml 删除标签 'row'