0

原始 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.")";
}

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

提前谢谢了!

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


事实上,如果“将默认命名空间声明放在首位”,正如 Josh Davis 所指出的,查找前缀就会消失。+1。但这就是输出中的...

...  
<metadata xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"  
xmlns:cc="http://creativecommons.org/ns#">
...  

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

4

1 回答 1

2

当您附加这些孩子时,我猜想 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的就是新的文件。

哦,它还会从原始文档中清除多余的命名空间,可能会破坏“保持原样”的规则。

哦,我忘了提到你必须明确声明<magic/>要创建哪个命名空间:

$magicElement = $doc->createElementNS('http://www.w3.org/2000/blabla', 'magic');
于 2010-06-19T01:28:34.420 回答