2016-11-10 1 views
1

Я использую реализацию PHP built-in DOM для изменения XML-документа, в частности файла content.xml в электронной таблице ODS. В этом документе широко используется пространство имен (в корневом элементе объявлено 35 различных пространств имен).Как сохранить DOMNode :: cloneNode() от вставки избыточных пространств имен?

Я пытаюсь скопировать table-cell элемент в новую строку, используя мелкий cloneNode(), но результат не совсем идентичен оригиналу:

<?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=""> 

, что делает документ недействительным. В общем, я счел невыполнимым смешивать вызовы методов с именами и именами без имени.

ответ

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 есть оптимизатор для этой работы. Он также позволяет вам изменять/определять префиксы.

Смежные вопросы