如何检测和删除不必要的xmlns:< something> PHP DOM中的属性? [英] How to detect and remove unnecessary xmlns:<something> attributes in PHP DOM?

查看:110
本文介绍了如何检测和删除不必要的xmlns:< something> PHP DOM中的属性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

说我有这样的源文件:

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

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



在PHP中, ve将其加载到DOMDocument-> loadXML()的DOM树中,我想能够检测到这样的命名空间声明存在,并将其删除。



我知道我可以用 hasAttribute()读取它,甚至用 removeAttributeNS()(奇怪地)删除它,但只有如果我知道它的前缀。它根本不出现在 DOMNode->属性中,因为我试图找到的东西不被认为是属性。我不能看到任何方法来检测它,而不知道前缀,除了将其序列化为XML字符串和运行正则表达式或某事。



我如何做吗任何查询哪个命名空间(即xmlns:something)已经在元素中声明的方式?

解决方案

如何检测: p>

 <?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 。'或@ * [namespace-uri()='。$ url。']]));
echo $ prefix。'('。$ url。'):used'。$ count。'times'.PHP_EOL;
}

如何删除:pfff,关于您唯一的选择,我知道是使用 xml_parse_into_struct()(因为这不是libxml2依赖afaik),并循环使用 XML Writer 函数生成的数组,跳过未使用的命名空间声明。不是一个有趣的passtime,所以我将离开实施由你。根据此问题,另一个选项可以是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/Transformversion =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:拷贝/>
< / xsl:template>
< / xsl:stylesheet>

结果:

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


Say I have a source document like this:

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

The xmlns:someprefix is obviously not needed here and doesn't do anything since that prefix is not being used in that element (or in my case, anywhere in the document).

In PHP, after I've loaded this into a DOM tree with DOMDocument->loadXML(), I'd like to be able to detect that such a namespace declaration exists, and remove it.

I know that I can read it with hasAttribute() and even remove it with removeAttributeNS() (strangely) but only if I know its prefix. It doesn't appear in DOMNode->attributes at all, as the thing I'm trying to find is not considered an attribute. I cannot see any way of detecting that it is there without knowing the prefix, other than serialising it back to an XML string and running a regex or something.

How can I do it? Any way to query which namespaces (ie xmlns:something) have been declared in an element?

解决方案

How to detect:

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

How to remove: pfff, about your only option that I know of is to use xml_parse_into_struct() (as this is not libxml2 reliant afaik), and looping through the resulting array with XML Writer functions, skipping namespace declarations which are not used. Not a fun passtime, so I'll leave the implementation up to you. Another option could be XSL according to this question, but I doubt it is of much use. My best effort seems to succeed, but moves 'top-level'/rootnode namespaces to children, resulting in even more clutter.

edit: this seems to work:

Given XML (added some namespace clutter):

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

With xsl (namespaces & not() clause based on previous $used array, so you'll still need that 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>

Results in:

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

这篇关于如何检测和删除不必要的xmlns:&lt; something&gt; PHP DOM中的属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆