如何保持DOMNode :: cloneNode()不插入冗余名称空间?
问题描述:
我使用PHP的built-in DOM实现来修改ODS电子表格中的XML文档,特别是content.xml
文件。本文档大量使用名称空间(在根元素中声明了35个不同的名称空间)。如何保持DOMNode :: cloneNode()不插入冗余名称空间?
我想用浅cloneNode()到table-cell
元素复制到一个新行,但结果并不完全等同于原:
<?xml version="1.0" encoding="UTF-8"?>
<office:document-content
xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0"
[... snip 32 ...]>
<!-- original -->
<table:table-cell table:style-name="ce5"
office:value-type="string"
calcext:value-type="string">
<!-- cloned -->
<table:table-cell xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0"
table:style-name="ce5"
office:value-type="string"
calcext:value-type="string">
虽然这是语义相似,它可能会导致重大的膨胀在更大的电子表格中(即使XML被压缩在磁盘上)。
有没有解决方案?
使用非名称空间感知的方法,并简单地复制属性(包括前缀和标签名称)的简易方法,似乎作品,起初:
$clone = $doc->createElement($ele->tagName);
foreach ($ele->attributes as $att) {
$clone->setAttribute($att->nodeName, $att->value);
}
生成的XML外观完全按照预期。但是,当克隆元素再次操作:
$clone->setAttributeNS($officeNS, "office:value-type", "string");
结果有两个相同的属性名称:
<table:table-cell xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
table:style-name="ce5"
office:value-type="string"
calcext:value-type="string"
office:value-type="string"
office:string-value="">
,这使得该文件无效。一般来说,我发现混合名称空间和非名称空间的方法调用是不切实际的。
答
这里有一个libxml的常数,它允许以优化负载的命名空间:
$xml = <<<'XML'
<f:foo xmlns:f="urn:foo">
<f:foo>
<f:foo xmlns:f="urn:foo">
</f:foo>
</f:foo>
</f:foo>
XML;
$document = new DOMDocument();
$document->loadXml($xml, LIBXML_NSCLEAN);
echo $document->saveXml();
输出:
<?xml version="1.0"?>
<f:foo xmlns:f="urn:foo">
<f:foo>
<f:foo>
</f:foo>
</f:foo>
</f:foo>
此作品居多,但我得到了一些无效的结果,如果使用相同的前缀用于同一文档中的不同名称空间。
FluentDOM库包含此作业的优化程序。它也允许您更改/定义前缀。