Получить из плоского 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 шт):

Автор решения: Solt

С объектами работать не очень удобно, поэтому первым делом приводим данные к массиву. А потом обходим массив, ищем родителя проекта и, если найден, перекладываем к нему в подмассив '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);

Demo

Конечно, если нужна многоуровневая иерархия, то перекладывания надо повторять до тех пор, пока есть что перекладывать. Тогда надо обернуть второй цикл в while() и гонять, пока перекладывается. А еще при работе со списками, содержащими родителей, неплохо бы делать какую-то проверку на рекурсии, но в данном алгоритме зацикливаться нечему.

→ Ссылка