开发者

iterating SimpleXml xpath result

I'm using SimpleXMLElement to read xml returned from a remote server. The results are then parsed with xpath like this:

$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 Si开发者_开发百科mpleXMLElement($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
    }
}

The $result is an Array with SimpleXMLElement objects. The actual error occurs when trying to use $block[0]->Fields(SimpleXMLElement object) as an array. So the results are there. It's iterating that is the problem.

This works just fine in PHP 5.3.2, but on the server which is running 5.1.6 it fails with:

Fatal error: Objects used as arrays in post/pre increment/decrement must return values by reference

What's the simplest way to fix this without upgrading the server version (server admin thinks its "unstable" with a newer version)?

One solution could be if I could make the xpath return the Field in the first $result, so I wont have to iterate the $block[0]->Fields->Field but I failed to make such an xpath expression.


As was mentionned in Sjoerd's answer, $block is not an array. SimpleXMLElement::xpath() returns an array of objects, each of those objects representing one single element. So basically, you have to replace $block[0] with $block since it already represents the block you're looking for.

Also, I have rewritten your XPath expression. Since you're looking for a <data:Block/> element, that's what you should target. The thing about <data:Code/> is a predicate, so it should go within brackets. Of course in your case the result is the same, but it's good practice to have semantically correct expressions, helps having a clearer idea of what's going on later on when you re-read that code (or if someone else has to maintain it.)

foreach ($xml->xpath('//data:Block[data:Code="Fbf"]') as $block) {
    foreach ($block->Fields->Field as $field) {
        echo "Code: ". $field->Code ."\n"; // SHould return FinnsIFbf
    }
}

Update

I didn't notice that you said that all you were interested in was the <Field/> element. In that case you can get it directly through XPath: (remember that they're all in the data namespace)

foreach ($xml->xpath('//data:Block[data:Code="Fbf"]/data:Fields/data:Field') as $field) {
    echo "Code: ". $field->Code ."\n"; // SHould return FinnsIFbf
}


It is probably because $block is not an array. You should use var_dump or print_r to confirm that, and then use is_array in your code to make sure it is an array.

If SimpleXML finds multiple elements with the same name, it returns an array of objects. If it finds a single element, it returns just that element, not an array with a single element. So when you expect multiple elements, you always have to code an exception case for when there is only one element.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜