在更改XML结构后使节点忽略名称空间(前缀)。 PHP DOMDocument

时间:2010-06-18 23:19:06

标签: 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 />

如何避免? 在检查ongoings时,如果将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 is ...(已删除的前缀:)(已添加前缀:)(已删除前缀:)(已添加前缀:默认)...

非常感谢提前!

P.S。这是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添加的声明应该是标准的,我的任务也不是验证一致性,而是 - 简单地将所有原始子节点保存在其内容(声明,名称值,属性等)中,在该额外新创建的容器下。

1 个答案:

答案 0 :(得分: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');