从字符串加载时的SimpleXML奇怪行为


SimpleXML weird behavior while loading from string

我有一个非常长的XML,我正在PHP中使用simplexml_load_string来处理它。我面临着一个非常奇怪的行为。

这是XML,我已经缩短了这一部分,这很麻烦。

<?xml version="1.0" encoding="UTF-8"?>
<test><Customer></Customer><Comments><CustomerComment></CustomerComment></Comments></test>

我将此值保存为string。这是我的PHP代码。

$xml = '<?xml version="1.0" encoding="UTF-8"?>
<test><Customer></Customer><Comments><CustomerComment></CustomerComment></Comments></test>';
$xml = simplexml_load_string($xml);
var_dump($xml);

这是输出

object(SimpleXMLElement)#1 (2) {
  ["Customer"]=>
  object(SimpleXMLElement)#2 (0) {
  }
  ["Comments"]=>
  object(SimpleXMLElement)#3 (1) {
    [0]=>
    object(SimpleXMLElement)#4 (0) {
    }
  }
}

我不知道这个简单的代码出了什么问题,也不知道为什么它不能维护子名称CustomerComment。谷歌搜索了很多,还找不到任何相关的东西。

奇怪的是,我已经从XML树的根中删除了Customer子项,并且它正在正确地获取子项名称。

php > $xml = '<?xml version="1.0" encoding="UTF-8"?>
php ' <order><Comments><CustomerComment></CustomerComment></Comments></order>';
php > $xml = simplexml_load_string($xml);
php > var_dump($xml);
object(SimpleXMLElement)#1 (1) {
  ["Comments"]=>
  object(SimpleXMLElement)#3 (1) {
    ["CustomerComment"]=>
    object(SimpleXMLElement)#2 (0) {
    }
  }
}

现在真正奇怪的部分是,如果我按照打破XML树

<?xml version="1.0" encoding="UTF-8"?>
<order>
<Customer></Customer>
<Comments>
<CustomerComment></CustomerComment>
</Comments>
</order>

这是var_dump

object(SimpleXMLElement)#1 (2) {
  ["Customer"]=>
  object(SimpleXMLElement)#3 (0) {
  }
  ["Comments"]=>
  object(SimpleXMLElement)#2 (1) {
    ["CustomerComment"]=>
    object(SimpleXMLElement)#4 (0) {
    }
  }
}

它得到了正确的子名称,但XML与第一个示例相同(除了换行符)

请有人指出,这里出了什么问题?,以及如何解决这个问题。我猜问题是在一行中有相同的子名称(此时为Customer)。

我能想到的唯一可能的解决方案是在我的XML字符串中用>'n替换>

重要的是要认识到SimpleXML不会将XML转换为对象的数组或层次结构。与DOM一样,SimpleXML是一个用于访问XML的API(但使用起来更好!);因此,使用var_dump,或者盲目地转换为JSON,将不会给出有用的结果。相反,使用SimpleXML提供的API从XML文档中提取您实际需要的数据。

在这种情况下,您会发现作为API$xml->Comments->CustomerComment$xml->Comments[0]->CustomerComment都返回相同的元素(如果您事先不知道是否有人要添加第二个Comments元素,这很好)。在转储输出(或转换为平面数组)时,SimpleXML必须猜测要显示其中的哪一个。PHP的某些版本似乎有一个错误,它显示了0,而不是直接跳到CustomerComment,但简单的事实是无论如何都不应该依赖它,只访问您知道需要的节点即可。