повторение результата SimpleXml xpath

Я использую 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
    }
}

Результатом $ является массив с объектами SimpleXMLElement. Фактическая ошибка возникает при попытке использовать $block[0]->Fields(объект SimpleXMLElement) в качестве массива. Так что результаты есть. Проблема в итерации.
Это прекрасно работает в PHP 5.3.2, но на сервере с 5.1.6 происходит сбой с:
Неустранимая ошибка: Объекты используются как массивы в post/ предварительное увеличение/уменьшение должно возвращать значения по ссылке

Каков самый простой способ исправить это без обновления версии сервера (администратор сервера считает его «нестабильным» с более новой версией)?

Одним из решений может быть, если бы я мог заставить xpath возвращать поле в первом $result, поэтому мне не придется повторять $block[0]->Fields->Field, но мне не удалось создать такое выражение xpath.


person baloo    schedule 24.06.2010    source источник
comment
Пожалуйста, опубликуйте короткий воспроизводимый фрагмент кода. Вероятно, вы неправильно обращаетесь к элементам. Кроме того, сообщение об ошибке не имеет ничего общего с тем, что вы опубликовали.   -  person Josh Davis    schedule 24.06.2010
comment
@Josh Davis: я обновил код, чтобы предоставить пример, который должен работать из коробки и дает ту же ошибку.   -  person baloo    schedule 24.06.2010
comment
Спасибо, я посмотрю на это через мгновение.   -  person Josh Davis    schedule 24.06.2010


Ответы (2)


Как упоминалось в ответе Сьорда, $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
}
person Josh Davis    schedule 24.06.2010

Вероятно, это потому, что $block не является массивом. Вы должны использовать var_dump или print_r, чтобы подтвердить это, а затем использовать is_array в своем коде, чтобы убедиться, что это массив.

Если SimpleXML находит несколько элементов с одинаковыми именами, он возвращает массив объектов. Если он находит один элемент, он возвращает только этот элемент, а не массив с одним элементом. Поэтому, когда вы ожидаете несколько элементов, вам всегда нужно кодировать случай исключения, когда есть только один элемент.

person Sjoerd    schedule 24.06.2010
comment
Я не уверен, что вы имели в виду, возвращая массив объектов. xpath() всегда возвращает массив, а доступ к элементам через нотацию объекта (например, $xml->Blocks) всегда возвращает SimpleXMLElement, независимо от того, сколько элементов он представляет, на котором вы можете использовать нотацию массива с числовыми индексами для доступа к элементам в том порядке, в котором они появляются. в документе. В этом примере вы можете получить доступ к этому блоку через $xml->Blocks[0]->Block[0], даже если есть только один из них. Однако в более старых версиях SimpleXML были случаи, когда он не работал. - person Josh Davis; 24.06.2010