Получить из плоского XML многомерый массив
Всем привет. Подскажите, каким образом сформировать многомерный вложенный массив из плоского XML-файла?
Есть узлы XML дерева (ProjectWrapper). У таких узлов есть вложенные узлы:
UID - уникальный идентификатор ParentProjectId - тут хранится идентификатор родительского узла Name - наименование сущности
Вот пример:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetProjectsResponse xmlns="http://streamline/">
<GetProjectsResult>
<ProjectWrapper>
<UID>464c2da2-d365-4235-b7de-2dc39be34c71</UID>
<ParentProjectId>3d6922ef-b925-478c-99b8-797a69c03ec2</ParentProjectId>
<Name>План-график проекта</Name>
</ProjectWrapper>
<ProjectWrapper>
<UID>7317a8d8-5911-42cd-84bd-8da33e43a6d0</UID>
<ParentProjectId>464c2da2-d365-4235-b7de-2dc39be34c71</ParentProjectId>
<Name>Старт проекта</Name>
</ProjectWrapper>
<ProjectWrapper>
<UID>a20b554d-b00a-4278-8149-e62b65f30c5e</UID>
<ParentProjectId>464c2da2-d365-4235-b7de-2dc39be34c71</ParentProjectId>
<Name>Экспрес обследование</Name>
</ProjectWrapper>
<ProjectWrapper>
<UID>73d090b2-38d6-40b4-af71-5c99a833c5db</UID>
<ParentProjectId>a20b554d-b00a-4278-8149-e62b65f30c5e</ParentProjectId>
<Name>Подготовка шаблонов проектных документов</Name>
</ProjectWrapper>
<ProjectWrapper>
<UID>351b4b19-1bde-4a0c-9db4-e337da3fe8c3</UID>
<ParentProjectId>73d090b2-38d6-40b4-af71-5c99a833c5db</ParentProjectId>
<Name>Реестр требований к целевой системе</Name>
</ProjectWrapper>
<ProjectWrapper>
<UID>7e39327e-3685-4afe-90d1-8b014b08e9c6</UID>
<ParentProjectId>a20b554d-b00a-4278-8149-e62b65f30c5e</ParentProjectId>
<Name>Анализ трех копий баз в разрезе функциональных блоков</Name>
</ProjectWrapper>
</GetProjectsResult>
</GetProjectsResponse>
</soap:Body>
</soap:Envelope>
Подскажите, как мне из вот такой плоской структуры получить многомерный массив с дочерними элементами? Понимаю, что возможно задача и тривиальная, но я пока что такой метод написать не смог
Ответы (1 шт):
С объектами работать не очень удобно, поэтому первым делом приводим данные к массиву. А потом обходим массив, ищем родителя проекта и, если найден, перекладываем к нему в подмассив 'children':
//Загружаем XML
$soap_obj=simplexml_load_string($xml,null,0,'soap',1)->xpath('//soap:Body')[0];
$pr_w=$soap_obj->GetProjectsResponse->GetProjectsResult->ProjectWrapper;
foreach($pr_w as $p){ //Преобразуем список в массив
$projects["$p->UID"]=['name'=>"$p->Name",'parent'=>"$p->ParentProjectId"];
}
print_r($projects);
foreach($projects as $UID=>$p){
if(isset($projects[$p['parent']])){ //Ищем родителя
$projects[$p['parent']]['children'][$UID]=$p; //Перекладываем в родителя
unset($projects[$UID]); //Удаляем из основного массива
}
}
print_r($projects);
Конечно, если нужна многоуровневая иерархия, то перекладывания надо повторять до тех пор, пока есть что перекладывать. Тогда надо обернуть второй цикл в while() и гонять, пока перекладывается. А еще при работе со списками, содержащими родителей, неплохо бы делать какую-то проверку на рекурсии, но в данном алгоритме зацикливаться нечему.