使用 SimpleXMLElement 时添加命名空间
这就是我所追求的
<!-- language: lang-xml -->
<ws:Test>
<ws:somename2>somevalue2</ws:somename2>
<ws:make>
<ws:model>foo</ws:model>
<ws:model>bar</ws:model>
</ws:make>
</ws:Test>
这是我当前的代码
<!-- language: lang-php -->
$xmlTest = new SimpleXMLElement('<Test/>', 0, false, 'ws', true);
$xmlTest->addChild("ws:somename2", "somevalue2", 'http://microsoft.com/wsdl/types/');
$make = $xmlTest->addChild('ws:make', null, 'ws');
#$make->addAttribute('name','Ford');
$make->addChild('ws:model', 'foo', 'ws');
$make->addChild('ws:model', 'bar', 'ws');
header ("Content-Type:text/xml");
print_r($xmlTest->asXML());
,但它输出
<!-- language: lang-xml -->
<Test>
<ws:somename2>somevalue2</ws:somename2>
<ws:make>
<ws:model>foo</ws:model>
<ws:model>bar</ws:model>
</ws:make>
</Test>
如您所见,测试中缺少 ws:
This is what I am after
<!-- language: lang-xml -->
<ws:Test>
<ws:somename2>somevalue2</ws:somename2>
<ws:make>
<ws:model>foo</ws:model>
<ws:model>bar</ws:model>
</ws:make>
</ws:Test>
This is my current code
<!-- language: lang-php -->
$xmlTest = new SimpleXMLElement('<Test/>', 0, false, 'ws', true);
$xmlTest->addChild("ws:somename2", "somevalue2", 'http://microsoft.com/wsdl/types/');
$make = $xmlTest->addChild('ws:make', null, 'ws');
#$make->addAttribute('name','Ford');
$make->addChild('ws:model', 'foo', 'ws');
$make->addChild('ws:model', 'bar', 'ws');
header ("Content-Type:text/xml");
print_r($xmlTest->asXML());
but it outputs
<!-- language: lang-xml -->
<Test>
<ws:somename2>somevalue2</ws:somename2>
<ws:make>
<ws:model>foo</ws:model>
<ws:model>bar</ws:model>
</ws:make>
</Test>
As you can see the ws: is missing from Test
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
SimpleXML 有一个不寻常的怪癖,即名称空间前缀是从根元素中过滤出来的。我不确定它为什么这样做。
然而,我使用的解决方法基本上是为前缀添加前缀,以便解析器仅删除第一个,并保留第二个。
这似乎对我有用,尽管我有兴趣了解为什么 SimpleXML 会这样做。
SimpleXML has an unusual quirk where the namespace prefixes are filtered from the root element. I'm not sure why it does this.
However, a workaround I've used has been to basically prefix the prefix, so that the parser only removes the first ones, and leaves the second
This seems to work for me, though I'm interested to understand why SimpleXML does this exactly.
问题
这段代码的问题出在第一行:
在做任何其他事情之前,让我们将其输出为 XML:
这是有道理的,我们得到了我们输入的内容。
该手册对于
$ns 的内容相当模糊
参数确实如此,但在这种情况下它没有做任何有用的事情。它的作用是设置读取 XML 的上下文,以便->foo
引用
和>['bar']
指的是ws:bar="..."
。它不会改变 XML 本身的结构。设置根命名空间
要在根元素上设置命名空间,我们只需将其包含在定义根元素的字符串中:
到目前为止一切顺利...
在子元素上设置命名空间
接下来,让我们理智地检查一下问题中的代码实际上是什么输出(我添加了一些空格以使其更具可读性):
好的,因此该文档包含两个命名空间声明:
xmlns:ws="http://microsoft.com/wsdl/types/"
于make
元素上的somename2
元素xmlns:ws="ws"
,然后由model
元素继承如果我们添加更正后的根元素会发生什么?
太酷了,所以
somename2
元素现在从根元素继承其命名空间定义,并且不会重新声明它。但是make
和model
有什么问题呢?让我们比较一下:第三个参数应该是命名空间 URI,而不仅仅是前缀。因此,当我们将其指定为
'ws'
时,SimpleXML 假定我们想要将实际的命名空间 URI 声明为ws
,因此添加了一个xmlns
属性这样做。我们真正想要的是所有元素都在同一个命名空间中:
太棒了,我们已经得到了想要的输出!
整理
但是这段代码看起来相当难看,为什么我们必须到处重复 URI?好吧,就 SimpleXML 而言,没有太多选择:相同的前缀在文档的不同部分可能意味着不同的内容,因此我们必须告诉它我们想要什么。
我们可以做的是使用命名空间 URI 的变量或常量来整理我们的代码,而不是每次都完整地写出来:
名称
XMLNS_WS
没有什么特别的在这里,它同样可以是变量、类常量或命名空间常量。代码的运行方式完全相同,只是看起来更容易一些。The Problem
The problem with this code is in the very first line:
Before doing anything else, let's output this as XML:
That makes sense, we got out what we put in.
The manual is rather vague on what the
$ns
argument does, but in this case it is not doing anything useful. What it does is set the context for reading the XML, so that->foo
refers to<ws:foo>
and['bar']
refers tows:bar="..."
. It doesn't do anything to change the structure of the XML itself.Setting a Root Namespace
To set a namespace on the root element, we just have to include it in our string defining the root element:
So far so good...
Setting Namespaces on Children
Next, let's sanity check what the code in the question actually outputs (I've added some whitespace to make it more readable):
OK, so this document contains two namespace declarations:
xmlns:ws="http://microsoft.com/wsdl/types/"
on thesomename2
elementxmlns:ws="ws"
on themake
element, which is then inherited by themodel
elementsWhat happens if we add our corrected root element?
Cool, so the
somename2
element now inherits its namespace definition from the root element, and doesn't re-declare it. But what's wrong with themake
andmodel
s? Let's compare:That third argument is supposed to be the namespace URI, not just the prefix. So when we gave it as
'ws'
, SimpleXML assumed we wanted to declare the actual namespace URI asws
, so added anxmlns
attribute to do so.What we actually wanted was all the elements to be in the same namespace:
Great, we've got our desired output!
Tidying Up
But that code looks rather ugly, why do we have to repeat the URI everywhere? Well, as far as SimpleXML is concerned, there's not much choice: the same prefix can mean different things in different parts of the document, so we have to tell it what we want.
What we can do is tidy up our code using a variable or constant for the namespace URI, rather than writing it out in full each time:
There's nothing special about the name
XMLNS_WS
here, and it could equally be a variable, a class constant, or a namespace constant. The code runs exactly the same, it's just a little easier on the eye.