simpleXMLElement的属性中包含什么?

时间:2014-05-21 20:01:59

标签: php xml simplexml

问题1:以字符串

访问innerXHTML

想象一下以下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]也相同?

问题2:处理相同类型的多个节点

想象一下以下的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列表?

1 个答案:

答案 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_rvar_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,如果需要,通常允许更细粒度的控制。