Рекурсивная итерация по объекту SimpleXML *, где структура не известна * - PullRequest
0 голосов
/ 13 февраля 2019

Каждый пример итерации xml, который я нашел в Интернете (включая документы по PHP, W3Schools и стек переполнение поиск), предполагает, что мы знаем структуру заранее.Я хотел бы создать цикл, который повторяется настолько глубоко, насколько это возможно в каждой ветви, и просто возвращает имена узлов и значения, которые он находит.Например:

<za-lord>
    <orderid>dresden1234</orderid>
    <customer>toot-toot</customer>
    <pizza>
        <sauce>marinara</sauce>
        <crust>thin</crust>
        <toppings>
            <cheese>extra</cheese>
            <veg>
                <onions>yes</onions>
                <peppers>extra</peppers>
                <olives>no</olives>
            </veg>
            <meat>
                <groundbeef>yes</groundbeef>
                <ham>no</ham>
                <sausage>no</sausage>
            </meat>
        </toppings>
    </pizza>
</za-lord>  

То, что я ищу, это:

orderid = dresden1234
customer = toot-toot
sauce = marinara
crust = thin
cheese = extra
onions = yes
peppers = extra
olives = no
groundbeef = yes
ham = no
sausage = no 

Я потратил пару часов сейчас на написание примеров кода, тестируя различные варианты foreach , и короткая версия такова, что ничто не дает мне то, что я хочу.Не зная структуры заранее, возможно ли рекурсивно выполнить итерацию вышеупомянутого xml и вернуть имена и значения узлов с помощью SimpleXML, и если да, то как?

1 Ответ

0 голосов
/ 13 февраля 2019

Вы можете использовать объект SimpleXMLIterator и рекурсировать его, чтобы получить все значения узла:

function list_nodes($sxi) {
    for($sxi->rewind(); $sxi->valid(); $sxi->next() ) {
        if ($sxi->hasChildren()) {
            list_nodes($sxi->current());
        }
        else {
            echo $sxi->key() . " = " . $sxi->current() . "\n";
        }
    }
}
$sxi = new SimpleXMLIterator($xmlstr);
list_nodes($sxi);

Вывод:

orderid = dresden1234 
customer = toot-toot 
sauce = marinara 
crust = thin 
cheese = extra 
onions = yes 
peppers = extra 
olives = no 
groundbeef = yes 
ham = no 
sausage = no

Демонстрация на 3v4l.org

Обновление

Если ваш xml может иметь пространства имен, вы должны использовать более сложный подход, проверяя каждый узел на наличие детей вкаждое из пространств имен в документе:

function list_children($node, $names) {
    $children = false;
    foreach ($names as $name) {
        if (count($node->children($name))) {
            $children = true;
            foreach ($node->children($name) as $child) {
                list_children($child, $names);
            }
        }
    }
    if (!$children) {
        echo $node->getName() . " = $node\n";
    }
}

$xml = new SimpleXMLElement($xmlstr);
list_children($xml, array_merge(array(''), $xml->getNamespaces(true)));

Вывод (для демонстрационной версии xml, такой же, как вопрос, но с добавленными пространствами имен):

orderid = dresden1234 
customer = toot-toot 
sauce = marinara 
crust = thin 
cheese = extra 
onions = yes 
peppers = extra 
olives = no 
ham = no 
sausage = no
groundbeef = yes 

Демо на 3v4l.орг

...