我正在使用SimpleXMLElement来读取从远程服务器返回的xml。 然后使用xpath解析结果:
$result = <<<XML
<DataImport2Result xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.xxx.xxx/Services/DataImport2">
<Number />
<Blocks>
<Block>
<Code>Fbf</Code>
<Fields>
<Field>
<Code>FinnsIFbf</Code>
<Value>1</Value>
</Field>
</Fields>
</Block>
</Blocks>
</DataImport2Result>
XML;
$xml = new SimpleXMLElement($result);
$xml->registerXPathNamespace("data", array_pop($xml->getNamespaces()));
foreach($xml->xpath("//data:Code[.='Fbf']/..") as $block) {
foreach($block[0]->Fields->Field as $field) {
echo "Code: ". $field->Code ."\n"; // SHould return FinnsIFbf
}
}
$ result是一个包含SimpleXMLElement对象的数组。尝试使用$ block [0] - &gt; Fields(SimpleXMLElement对象)作为数组时发生实际错误。所以结果就在那里。这是问题的迭代
这在PHP 5.3.2中运行得很好,但是在运行5.1.6的服务器上它失败了:
致命错误:在post / pre递增/递减中用作数组的对象必须通过引用返回值
在没有升级服务器版本的情况下解决此问题的最简单方法是什么(服务器管理员认为其“不稳定”版本较新)?
一个解决方案可能是如果我可以让xpath在第一个$ result中返回Field,所以我不必迭代$block[0]->Fields->Field
但是我没能做出这样的xpath表达式。
答案 0 :(得分:4)
正如Sjoerd的回答中提到的,$block
不是数组。 SimpleXMLElement::xpath()返回一个对象数组,每个对象代表一个单独的元素。基本上,您必须将$block[0]
替换为$block
,因为它已经代表了您正在寻找的块。
另外,我已经重写了你的XPath表达式。由于您正在寻找<data:Block/>
元素,因此您应该将其作为目标。关于<data:Code/>
的事情是一个谓词,所以它应该在括号内。当然在你的情况下结果是一样的,但是在语义上正确的表达式是一个很好的做法,有助于更清楚地了解当你重新阅读该代码时(或者如果其他人必须维护它)时会发生什么。
foreach ($xml->xpath('//data:Block[data:Code="Fbf"]') as $block) {
foreach ($block->Fields->Field as $field) {
echo "Code: ". $field->Code ."\n"; // SHould return FinnsIFbf
}
}
我没有注意到你说你感兴趣的只是<Field/>
元素。在这种情况下,您可以直接通过XPath获取它:(请记住它们都在数据命名空间中)
foreach ($xml->xpath('//data:Block[data:Code="Fbf"]/data:Fields/data:Field') as $field) {
echo "Code: ". $field->Code ."\n"; // SHould return FinnsIFbf
}
答案 1 :(得分:0)
可能是因为$ block不是数组。您应该使用var_dump
或print_r
进行确认,然后在代码中使用is_array
以确保它是一个数组。
如果SimpleXML找到多个具有相同名称的元素,则返回一个对象数组。如果它找到单个元素,则只返回该元素,而不是具有单个元素的数组。因此,当您期望多个元素时,您总是必须在只有一个元素的情况下编写例外情况。