如何在PHP DOM中检测和删除不必要的xmlns:<something>属性?</something>

时间:2010-09-28 07:30:13

标签: php xml dom namespaces xml-namespaces

说我有这样的源文档:

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

这里显然不需要xmlns:someprefix并且不做任何事情,因为该元素中没有使用该前缀(或者在我的情况下,在文档中的任何地方)。

在PHP中,在我使用DOMDocument-&gt; loadXML()将其加载到DOM树之后,我希望能够检测到存在这样的命名空间声明,并将其删除。

我知道我可以用hasAttribute()阅读它,甚至用removeAttributeNS()删除它(奇怪的是),但前提是我知道它的前缀。它根本没有出现在DOMNode->attributes中,因为我试图找到的东西不被视为属性。除了将其序列化回XML字符串并运行正则表达式之外,我看不出有任何方法可以在不知道前缀的情况下检测它是否存在。

我该怎么办?查询哪些命名空间(即xmlns:something)已在元素中声明的任何方法?

1 个答案:

答案 0 :(得分:1)

如何检测:

<?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函数循环生成的数组,跳过未使用的名称空间声明。这不是一个有趣的传递时间,所以我将把实现留给你。根据{{​​3}},另一个选项可以是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>

使用基于以前$ used数组的xsl(名称空间和not()子句,所以你仍然需要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>