Как обнаружить и удалить ненужные атрибуты xmlns: <something>в PHP DOM? - PullRequest
2 голосов
/ 28 сентября 2010

Скажем, у меня есть исходный документ, подобный этому:

<element>
  <subelement xmlns:someprefix="mynamespace"/>
</element>

xmlns:someprefix здесь явно не нужен и ничего не делает, так как этот префикс не используется в этом элементе (или в моемв любом месте документа).

В PHP после того, как я загрузил это в дерево DOM с помощью DOMDocument-> loadXML (), я хотел бы иметь возможность обнаружить, что такое объявление пространства имен существуети удалите его.

Я знаю, что могу прочитать его с помощью hasAttribute() и даже удалить его с помощью removeAttributeNS() (как ни странно), но только если я знаю его префикс.Он вообще не отображается в DOMNode->attributes, поскольку то, что я пытаюсь найти, не считается атрибутом.Я не вижу способа обнаружить, что он там есть, не зная префикса, кроме как сериализовать его обратно в строку XML и запустить регулярное выражение или что-то в этом роде.

Как я могу это сделать?Любой способ запросить, какие пространства имен (например, xmlns: что-то) были объявлены в элементе?

1 Ответ

1 голос
/ 28 сентября 2010

Как обнаружить:

<?php
$d = new DOMDocument();
$d->loadXML('
<element>
  <subelement xmlns:someprefix="http://mynamespace/asd">
  </subelement>
</element>');
$sxe = simplexml_import_dom($d);
$namespaces = $sxe->getDocNamespaces(true);
$x = new DOMXpath($d);
foreach($namespaces as $prefix => $url){
        $count = $x->evaluate("count(//*[namespace-uri()='".$url."' or @*[namespace-uri()='".$url."']])");
        echo $prefix.' ( '.$url.' ): used '.$count.' times'.PHP_EOL;
}

Как удалить: pfff, о вашей единственной известной мне опции - это использовать xml_parse_into_struct() (поскольку это не libxml2-зависимый afaik) и проходить через получившийся массив с функциями XML Writer, пропуская объявления пространства имен не используется. Это не веселое времяпрепровождение, поэтому я оставлю реализацию вам. Другой вариант может быть XSL в соответствии с этим вопросом , но я сомневаюсь, что он очень полезен. Мое лучшее усилие, похоже, увенчалось успехом, но перемещает пространства имен «верхнего уровня» / rootnode детям, что приводит к еще большему беспорядку.

edit : это похоже на работу:

Учитывая XML (добавлен некоторый беспорядок в пространстве имен):

<element xmlns:yetanotherprefix="http://mynamespace/yet">
  <subelement
        xmlns:someprefix="http://mynamespace/foo"
        xmlns:otherprefix="http://mynamespace/bar"
        foo="bar"
        yetanotherprefix:bax="foz">
        <otherprefix:bar>
                <yetanotherprefix:element/>
                <otherprefix:element/>
        </otherprefix:bar>
        <otherprefix:bar>
                <yetanotherprefix:element/>
                <otherprefix:element/>
        </otherprefix:bar>
        <yetanotherprefix:baz/>
  </subelement>

С xsl (namespaces & not() предложением, основанным на предыдущем массиве $ used, так что вам все равно понадобится этот файл.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
    xmlns:yetanotherprefix="http://mynamespace/yet"
    xmlns:otherprefix="http://mynamespace/bar"> 
    <xsl:template match="/">
        <xsl:apply-templates select="/*"/>
    </xsl:template>
    <xsl:template match="*">
        <xsl:element name="{name(.)}">
                <xsl:apply-templates select="./@*"/>
                <xsl:copy-of select="namespace::*[not(name()='someprefix')]"/>
                <xsl:apply-templates select="./node()"/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="@*">
        <xsl:copy/>
    </xsl:template>
</xsl:stylesheet>

Результаты:

<?xml version="1.0"?>
<element xmlns:yetanotherprefix="http://mynamespace/yet">
  <subelement xmlns:otherprefix="http://mynamespace/bar" foo="bar" yetanotherprefix:bax="foz">
        <otherprefix:bar>
                <yetanotherprefix:element/>
                <otherprefix:element/>
        </otherprefix:bar>
        <otherprefix:bar>
                <yetanotherprefix:element/>
                <otherprefix:element/>
        </otherprefix:bar>
        <yetanotherprefix:baz/>
  </subelement>
</element>
...