повторение результата SimpleXml xpath - PullRequest
2 голосов
/ 24 июня 2010

Я использую 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] -> Fields (объект SimpleXMLElement) в качестве массива.Так что результаты есть.Проблема заключается в итерации.
Это прекрасно работает в PHP 5.3.2, но на сервере, на котором работает 5.1.6, происходит сбой:
Неустранимая ошибка: объекты, используемые как массивы в post /Предварительное увеличение / уменьшение должно возвращать значения по ссылке

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

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

Ответы [ 2 ]

4 голосов
/ 24 июня 2010

Как упоминалось в ответе Шёрда, $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
}
0 голосов
/ 24 июня 2010

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

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

...