【问题标题】:How to keep DOMNode::cloneNode() from inserting redundant namespaces?如何防止 DOMNode::cloneNode() 插入冗余命名空间?
【发布时间】:2016-11-10 22:51:52
【问题描述】:

我正在使用 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="">

这会使文档无效。一般来说,我发现混合命名空间和非命名空间方法调用是不切实际的。

【问题讨论】:

    标签: php xml dom xml-namespaces


    【解决方案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 库包含此作业的优化器。它也允许您更改/定义前缀。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多