在PHP中使用importNode,命名空间和appendChild时发生的奇怪事情

时间:2018-11-14 04:24:03

标签: php xml dom namespaces

我发现importNode之后的xml将具有“默认”前缀。经过一些实验,我发现了一些奇怪的现象。 如何解释以下结果: 代码在这里:

Shader "Unlit/Environment Texture" {
Properties {
    _MainTex ("Base (RGB)", 2D) = "white" {}
    _MainTexBias ("Mip Bias (-1 to 1)", float) = -1
}

SubShader {
    Tags { "RenderType"="Opaque" }

    Lighting Off
    Fog { Mode off }

        Pass {  
            CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag

                #include "UnityCG.cginc"

                struct appdata_t {
                    float4 vertex : POSITION;
                    float2 texcoord : TEXCOORD0;
                };

                struct v2f {
                    float4 vertex : SV_POSITION;
                    half2 texcoord : TEXCOORD0;
                };

                sampler2D _MainTex;
                float4 _MainTex_ST;
                half _MainTexBias;

                v2f vert (appdata_t v)
                {
                    v2f o;
                    o.vertex = UnityObjectToClipPos(v.vertex);
                    o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
                    return o;
                }

                fixed4 frag (v2f i) : SV_Target
                {
                    fixed4 col = tex2Dbias(_MainTex, half4(i.texcoord.x,i.texcoord.y,0.0,_MainTexBias));
                    return col;
                }
            ENDCG
        }
    }
}

1 个答案:

答案 0 :(得分:1)

您要删除使用的名称空间的名称空间定义。根据呼叫的顺序,会触发不同的维修/后备。删除/更改名称空间的预期方法是遍历并重新创建节点。

libxml对名称空间定义进行了一些优化和回退。如果您做“奇怪”的事情,它可能会替换名称空间别名,并可能破坏结果。触发时是带有名称空间的属性。但没有前缀。与元素不同,名称空间内的属性必须具有前缀。这是一个触发默认名称空间前缀的示例:

$document = new DOMDocument();
$document->appendChild($document->createElementNS('urn:1', 'foo'));
// add attribute in namespace without prefix
$document->documentElement->setAttributeNS('urn:1', 'bar', 21);
echo $document->saveXML();

输出:

<?xml version="1.0"?> 
<foo xmlns="urn:1" xmlns:default="urn:1" default:bar="21"/>

即使为属性使用前缀,libxml也会识别出它与试图优化的默认元素名称空间相同:

$document = new DOMDocument();
$document->appendChild($document->createElementNS('urn:1', 'foo'));
// add attribute in element namespace with prefix
$document->documentElement->setAttributeNS('urn:1', 'b:bar', 21);
echo $document->saveXML();

如果需要在名称空间中添加属性,我的规则是始终为名称空间使用前缀。

$document = new DOMDocument();
$document->appendChild($document->createElementNS('urn:1', 'b:foo'));
$document->documentElement->setAttributeNS('urn:1', 'b:bar', 21);
echo $document->saveXML();

输出:

<?xml version="1.0"?> 
<b:foo xmlns:b="urn:1" b:bar="21"/>

$new_node->removeAttributeNS("xmlns://www.abc.com", "");告诉DOM删除名称空间xmlns://www.abc.com中没有名称的属性。但是xmlns=""不是属性,而是名称空间定义。它使用相同的语法,并且在某些情况下可以使用属性方法进行修改,但是libxml可能会再次添加它,因为后代或属性节点位于名称空间内,并且需要定义。

将它们视为属性xmlns="..."不在任何命名空间中,并且前缀为xmlns:foo="..."之类的命名空间定义位于保留的命名空间http://www.w3.org/2000/xmlns/中。 imho 删除名称空间定义的正确调用是:

// xmlns="..."
$node->removeAttributeNS(NULL, 'xmlns');
// xmlns:prefix="..." - broken in PHP or libxml?
$node->removeAttributeNS('http://www.w3.org/2000/xmlns/', 'prefix');

示例:

$document = new DOMDocument();
$document->appendChild($document->createElementNS('urn:1', 'b:foo'));
$document->documentElement->setAttributeNS(NULL, 'xmlns', 'urn:2');
$document->documentElement->setAttributeNS(
  'http://www.w3.org/2000/xmlns/', 'xmlns:bar', 'urn:3'
);
echo $document->saveXML();
$document->documentElement->removeAttributeNS(NULL, 'xmlns');
echo $document->saveXML();
// for some reason that does not work
$document->documentElement->removeAttributeNS(
  'http://www.w3.org/2000/xmlns/', 'bar'
);
echo $document->saveXML();
// but this works - weird
$document->documentElement->removeAttributeNS('urn:3', 'bar');
echo $document->saveXML();

输出:

<?xml version="1.0"?> 
<b:foo xmlns:b="urn:1" xmlns:bar="urn:3" xmlns="urn:2"/> 
<?xml version="1.0"?> 
<b:foo xmlns:b="urn:1" xmlns:bar="urn:3"/> 
<?xml version="1.0"?> 
<b:foo xmlns:b="urn:1" xmlns:bar="urn:3"/> 
<?xml version="1.0"?> 
<b:foo xmlns:b="urn:1"/>