Скажем, у меня есть исходный документ:
<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>