XML — Как заставить функцию ждать и вернуть другое значение функции

Итак, у меня есть какой-то XML, который мне нужен для обхода потомков, чтобы найти значение потомков. Проблема в фактическом цикле. То, как я знаю, — это создание функции, и если есть ребенок, используйте ту же функцию и перебирайте дочерние элементы — и снова, и так четвертый.

Моя проблема в том, что не похоже, что функция ожидает завершения «дочерней функции», прежде чем вернуть мое значение.

Есть ли лучший способ сделать это? Я знаю, что есть обратные вызовы, но я не уверен, как бы я реализовал это здесь

Пример XML

<?xml version="1.0" standalone="yes"?>
<pages>
<page>
<title>Parent Page1</title>
<id>0</id>
<children>
<page>
<title>Child Page1</title>
<id>1</id>
<children/>
</page>
</children>
</page>
<page>
<title>Parent Page2</title>
<id>2</id>
<children>
<page>
<title>Child Page2</title>
<id>3</id>
<children/>
</page>
</children>
</page>
</pages>

Пример PHP

$page = "Child Page2";
echo "The ID of " . $page . " is " . a($page);

function a ($title) {
$xml = simplexml_load_file("pages.xml") or die("Failed.");
return b ($xml[0], $title);
}

function b ($pages, $title) {
$val;
foreach ($pages as $page) {
if($page->title == $title) {
$val = $page->id;
break;
} else if ($page->children->children() > 0){
$val = b($page->children->children(), $title);
}
}
return $val;
}

Выводит: The ID of Child Page2 is

Теперь я знаю, что XML не идеален в этом примере, но это только заполнитель, поэтому вы понимаете, что я пытаюсь сделать. Я использую SimpleXML в XML, если это поможет

Решение

Проблема заключалась в том, что если b(); вернулся в первую ветку, но все равно нужно было проверить другие ветви детей, все вернулось null или просто ничего вообще.

Мое решение ниже работает, но оно пошло с ответом Суэйзи, потому что оно короче и эффективнее (экономит сохранение переменных)

-1

Решение

function b ($pages, $title){
foreach ($pages as $page){
if($page->title == $title){
// returns id regardless of how many loops in you are
return $page->id;}
else if ($page->children->children() > 0){
// call function if it has children
return b ($page->children->children(), $title);}}
// if nothing is found
return 'no results';}

Это самый простой способ, при условии, что может быть только один экземпляр каждого заголовка.

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

1

Другие решения

Попробуй это:

<?php

$page = "Child Page";
echo "The ID of " . $page . " is " . a($page);

function a($title) {
$pages = [
[
'title'    => 'Parent Page',
'id'       => 0,
'children' => [
[
'title'    => 'Child Page',
'id'       => 1,
'children' => []
]
]
]
];
return b($pages, $title);
}

function b($pages, $title) {
foreach ($pages as $page) {
if ($page['title'] == $title) {
$val = $page['id'];
} else if (count($page['children']) > 0) {
$val = b($page['children'], $title);
}
}
return $val;
}

Я бы не стал использовать XML здесь, если вам это не нужно. Это грубый пример использования массивов, но он работает для того, что вы пытаетесь сделать. Дайте мне знать, если это работает для вас. Если вам нравится объектная нотация, вы можете превратить массив в объект или использовать классы (предпочтительно).

1

Я думаю, что вы можете упростить работу, просто используя xPath:

function b( $xml, $title )
{
$val = Null;
$pattern = '//page/title[text()="'.$title.'"]/..';
if( $found = $xml->xpath( $pattern ) ) $val = $found[0]->id;
return $val;
}

Вы также можете изменить его только для того, чтобы в конечном итоге было более одного идентичного названия:

function b( $xml, $title )
{
$val = array();
$pattern = '//page/title[text()="'.$title.'"]/..';
foreach( $xml->xpath( $pattern ) as $node )
{
$val[] = $found[0]->id;
}
return $val;
}

Описание шаблона xPath:

//                      Search following pattern no matter where it is
page/title              <page> with child <title> with
[text()="'.$title.'"]   node value = $text
/..                     select parent node
1

Я наконец нашел проблему. Проблема заключалась в том, что, поскольку у меня много ветвей (много родителей с детьми), однажды мой цикл прошел первую ветку и ничего не нашел, он вернулся null к функции, которая также вернула null Вернуться к началу.

Я смог это исправить, добавив простой if ($received != null) как это

function b ($pages, $title) {
$val;
foreach ($pages as $page) {
if($page->title == $title) {
$val = $page->id;
break;
} else if ($page->children->children() > 0){
$received = b($page->children->children(), $title);
if ($received != null) { // Important
$val = $received;
}
}
}
return $val;
}

Там, где я разместил свой комментарий, вы можете увидеть, что окончательный возврат вынужден ждать остальную часть foreach, а не просто использовать первый null он получает

0