我正在使用PHP的built-in DOM实现来修改XML文档,特别是ODS电子表格中的content.xml
文件。本文档大量使用命名空间(在根元素中声明了35个不同的命名空间)。
我正在尝试使用浅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="">
使文档无效。一般来说,我发现混合使用命名空间和非命名空间的方法调用是不切实际的。
答案 0 :(得分:1)
这是一个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库包含此作业的优化程序。它允许您更改/定义前缀。