Как обнаружить и удалить ненужные атрибуты xmlns: <something> в PHP DOM?

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

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

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

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

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

Как мне это сделать? Любой способ запросить, какие пространства имен (т. Е. Xmlns: something) были объявлены в элементе?

Как определить:

 <?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 reliant afaik) и перебирать результирующий массив с помощью функций XML Writer , пропуская декларации пространства имен, которые не используются. Не весело, так что я оставлю реализацию до вас. Другой вариант может быть XSL в соответствии с этим вопросом , но я сомневаюсь, что он очень полезен. Мое лучшее усилие, похоже, преуспевает, но переводит пространства имен верхнего уровня / rootnode для детей, что приводит к еще большему количеству помех.

редактирование : похоже, это работает:

Учитывая 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 массиве, так что вам все равно понадобится этот afaik.

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