想象一下以下XML:
<?xml version="1.0" encoding="utf-8" ?>
<feed>
<title type="text">This is my title</title>
<id>123456</id>
<content>Hello World</content>
</feed>
假设我们想要将<id>
值作为字符串访问。有人会认为可以通过以下方式访问:
$xml = simplexml_load_file('file.xml');
print_r($xml->id);
但那不对,我们最终会打印一个新的SimpleXMLElement,如下所示:
SimpleXMLElement Object
(
[0] => 123456
)
所以我们回到一个新对象,其中0是属性,我想?有两种方式可以自然地访问它,这两种方式都不起作用:
//throws an error
$xml = simplexml_load_file('file.xml');
print_r($xml->id->0);
//prints "SimpleXMLElement Object ( [0] => 123456 )"
$xml = simplexml_load_file('file.xml');
print_r($xml->id[0]);
这导致问题A:$xml->id
内部是什么?它类似于一个对象,但它也像一个数组。最终,有两种方法可以访问此值:
//prints '123456'
$xml = simplexml_load_file('file.xml');
$id = (array) $xml->id;
print_r($id[0]);
//prints '123456'
$xml = simplexml_load_file('file.xml');
print_r($xml->id->__toString());
其中,第二个感觉更多&#34;正确&#34;对我来说,但是我想知道这里发生了什么。 问题B:为什么$xml->id
和$xml->id[0]
相同?就此而言,为什么$xml->id[0]
和$xml->id[0][0][0][0][0][0]
也相同?
想象一下以下的XML
<?xml version="1.0" encoding="utf-8" ?>
<feed>
<title type="text">This is my title</title>
<tag>news</tag>
<tag>sports</tag>
<content>Hello World</content>
</feed>
假设您想获得所有标签的列表。这是我开始变得非常困惑的地方。
$xml = simplexml_load_file('file.xml');
print_r($xml->tag);
这具有以下结果:
SimpleXMLElement Object
(
[0] => news
)
这很明智,但这是我无法得到的部分。我们也可以这样做:
$xml = simplexml_load_file('file.xml');
print_r($xml->tag[1]);
打印出来:
SimpleXMLElement Object
(
[0] => sports
)
到底是什么?如果$xml->tag
内有两个标记,那么问题C:为什么不会print_r($xml->tag)
打印以下内容:
SimpleXMLElement Object
(
[0] => news
[1] => sports
)
我猜$xml->tag
暗示$xml->tag[0]
?最终,我可以看到访问所有<tags>
列表的唯一方法是使用xpath:
$xml = simplexml_load_file('file.xml');
$tags = $xml->xpath('//tag');
//$tags is now an array of objects. We want an array of strings.
foreach ($tags as &$tag) {
$tag = (string) $tag;
}
print_r($tags);
哪个输出:
Array
(
[0] => news
[1] => sports
)
但老实说,似乎有很多代码可以做一些非常简单和常见的事情。那么问题D:有没有更好的方法从PHP本地获取XML列表?
答案 0 :(得分:3)
问题1:以字符串形式访问innerXHTML
您可以通过强制将 SimpleXMLElement 作为字符串访问内部XML:
print_r((string) $xml->id); # gives 123456
那么,这是如何工作的?这是有效的,因为在PHP中,您可以使用__toString()
magic method对任何可以将其转换为字符串的对象进行编程。 SimpleXMLElement 是一个执行相同操作的内部对象。
为什么print_r($xml->id)
看起来如此奇怪?那是因为 SimpleXMLElement \ s上的print_r
和var_dump
是骗子。所以不要太依赖他们。 SimpleXMLElement 可以在这里说谎,因为它是一个内部对象。当我们在PHP用户空间中编写自己的对象时,它可以否定我们无法做到的规则。
问题A:$ xml-&gt; id里面是什么?
这只是一个 SimpleXMLElement 。它就像一个已经实现ArrayAccess的对象。因此,您可以编写可以像数组一样访问的对象。 SimpleXMLElement 也可以。
它还会覆盖标准的数组转换。当强制转换为数组时, SimpleXMLElement 将遵循的确切规则有点不那么直观(我到目前为止所做的最佳列表是SimpleXML and JSON Encode in PHP – Part I + II,因为规则与JSON相同编码,只有当你感兴趣,因为你通常不需要那么详细的水平)。
问题B:为什么$ xml-&gt; id和$ xml-&gt; id [0]相同?
这是因为$xml->id
是第一个<id>
元素的别名,它也可以通过它的数字索引$xml->id[0]
访问。这顺便说一下。允许您访问元素本身,即使它在一个变量中:
$id = $xml->id;
# change inner text
$id[0] = 'hello'; // $id = 'hello'; would have turned $id into a string
# remove the node from the tree
unset($id[0]); // unset($id); would have unset the $id variable only
$id[0]
或$id->{0}
符号有时也称为 simplexml自引用。有关更多参考文献的更长答案是:https://stackoverflow.com/a/16062633/367456。
顺便说一句,那不是相同的。这只是访问文档中相同XML节点的两种方法。
就此而言:$xml->id->{0}
也会奏效。与$xml->id[0]->{0}
甚至$xml->id->{0}[0][0]->{0}[0]->{0}[0][0]->{0}[0]->{0}[0][0]->{0}[0]
等等一样,等等。
问题2:处理相同类型的多个节点
问题C:为什么print_r($ xml-&gt;标签)不打印以下内容:
这是因为由于SimpleXML的简化,它不能同时做到,所以需要做出决定。通常使用$xml->tag
,您希望访问名为<tag>
的第一个元素而不是所有标记。但是通过强制转换,您可以为SimpleXML提供所需的提示:
通过强制转换为字符串,你基本上会说:给我第一个元素值。
(string) $xml->tag; # news
通过强制转换为数组,您可以说:给我所有元素值:
(array) $xml->tag # Array([0] => news, [1] => sports)
这可能已经是你要求的了
问题D:有没有更好的方法从PHP本地获取XML列表值?
这在很大程度上取决于您的需求。正如您已经意识到的那样,SimpleXML中的“简单”带来了很多魔力,而且并不总是很容易理解。它是某种典型XML解析需求的精简界面,但它并不能完全涵盖所有情况。
DOM姐妹库允许您使用基于DOMDocument的API访问更详细的API,如果需要,通常允许更细粒度的控制。