Получить данные поддерева в большом файле XML с помощью XMLReader и PHP

Я пытаюсь прочитать большой файл XML с помощью XMLReader и не могу найти способ правильно перебрать поддерево.

До сих пор я пытался использовать функции read() и next(). И это не работает должным образом. Вот структура XML, которую я анализирую:

<CLIENTES>
<CLIENTE>
        <CODIGO_INTERESSADO>10</CODIGO_INTERESSADO>
        <NOME_INTERESSADO>Pedro</NOME_INTERESSADO>
        <ENDERECO />
        <COMPLEMENTO />
        <ESTADO />
        <MUNICIPIO />
        <BAIRRO />
        <CEP />
        <DATA_CADASTRO>16/09/2015</DATA_CADASTRO>
        <STATUS>Ativo</STATUS>
        <TELEFONES>
            <TELEFONE>
                <NUMERO>(21) 96909-6905</NUMERO>
                <TIPO>Celular</TIPO>
            </TELEFONE>
        </TELEFONES>
    </CLIENTE>
<CLIENTE>
        <CODIGO_INTERESSADO>11</CODIGO_INTERESSADO>
        <NOME_INTERESSADO>Luiz</NOME_INTERESSADO>
        <ENDERECO />
        <COMPLEMENTO />
        <ESTADO />
        <MUNICIPIO />
        <BAIRRO />
        <CEP />
        <DATA_CADASTRO>16/09/2015</DATA_CADASTRO>
        <STATUS>Ativo</STATUS>
        <TELEFONES>
            <TELEFONE>
                <NUMERO>(21) 96909-6901</NUMERO>
                <TIPO>Celular</TIPO>
            </TELEFONE>
        </TELEFONES>
    </CLIENTE>
</CLIENTES>

Как видите, узел TELEFONES может иметь несколько узлов TELEFONE. Поэтому мне нужно зациклить это и получить их по отдельности. Пока это мой код:

$xml = new XMLReader();

$xml->open('xml_formatado_stack.xml');

$cont = 0;
$clientes = array();
while ($xml->read()) {

    if ($xml->nodeType == XMLReader::ELEMENT && $xml->localName == 'CLIENTES') {
        while ($xml->read()) {
            if ($xml->nodeType == XMLReader::ELEMENT && $xml->localName == 'CLIENTE') {

                while ($xml->read()) {
                    $telefone = array();
                    if ($xml->nodeType == XMLReader::ELEMENT) {
                        if ($xml->localName == 'CODIGO_INTERESSADO') {
                            $xml->read(); 
                            echo $xml->value."<br>";
                            $clientes[$cont]['codigo_interessado'] = $xml->value;                                                       
                        }

                        if ($xml->localName == 'NOME_INTERESSADO') {
                            $xml->read(); 
                            $clientes[$cont]['nome_interessado'] = $xml->value;
                        }

                        if ($xml->localName == 'ENDERECO') {
                            $xml->read(); 
                            $clientes[$cont]['endereco'] = $xml->value;
                        }

                        if ($xml->localName == 'COMPLEMENTO') {
                            $xml->read(); 
                            $clientes[$cont]['complemento'] = $xml->value;
                        }

                        if ($xml->localName == 'ESTADO') {
                            $xml->read(); 
                            $clientes[$cont]['estado'] = $xml->value;
                        }

                        if ($xml->localName == 'MUNICIPIO') {
                            $xml->read(); 
                            $clientes[$cont]['municipio'] = $xml->value;
                        }

                        if ($xml->localName == 'BAIRRO') {
                            $xml->read(); 
                            $clientes[$cont]['bairro'] = $xml->value;
                        }

                        if ($xml->localName == 'CEP') {
                            $xml->read(); 
                            $clientes[$cont]['cep'] = $xml->value;
                        }


                        if ($xml->localName == 'DATA_CADASTRO') {
                            $xml->read(); 
                            $clientes[$cont]['data_cadastro'] = $xml->value;
                        }

                        if ($xml->localName == 'STATUS') {
                            $xml->read(); 
                            $clientes[$cont]['status'] = $xml->value;                           
                        }

                        if ($xml->localName == 'TELEFONES') {
                            while ($xml->read()) {
                                if ($xml->nodeType == XMLReader::ELEMENT && $xml->localName == 'TELEFONE') {
                                    while ($xml->read()) {
                                        if ($xml->nodeType == XMLReader::ELEMENT) {
                                            if ($xml->localName == 'NUMERO') {
                                                $xml->read(); 
                                                $telefone['numero'] = $xml->value;                                              
                                            }

                                            if ($xml->localName == 'TIPO') {
                                                $xml->read(); 
                                                $telefone['tipo'] = $xml->value;
                                            }
                                        }
                                    }
                                }
                            }                           
                            $clientes[$cont]['telefones'][] = $telefone;
                            $cont++;
                        }                       
                    }

                }
            }
        }

    }
}

var_dump($clientes);

$xml->close();

У меня тут две проблемы. Во-первых, мой последний массив содержит информацию только об одном узле CLIENTE. В нем должны быть все узлы CLIENTE, я индексирую их с помощью $cont var.

Другая проблема заключается в том, что узел TELEFONES, который идет к моему массиву $clientes, принадлежит последнему узлу CLIENTE XML. Итак, каким-то образом мой код проходит через каждый узел CLIENTE, но когда я обрабатываю узел TELEFONES, мой массив $clientes становится все испорченным.

Я просто не могу найти способ зациклить поддерево с помощью XMLParser. Кто-нибудь может мне помочь?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
0
208
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вместо того, чтобы пытаться прочитать весь документ поэлементно, вы можете с помощью XMLReader попросить его импортировать сегменты.

В этом примере кода, как только вы доберетесь до уровня <CLIENTE>, он считывает все элементы этого уровня в SimpleXMLElement (используя simplexml_import_dom()). После того, как вы это сделаете, вы можете обрабатывать каждый из них, используя более простой интерфейс, и вам не придется иметь дело с начальными и конечными тегами и т. д.

$xml = new XMLReader();

$xml->open('xml_formatado_stack.xml');

$clientes = array();
$doc = new DOMDocument;
while ($xml->read()) {

    if ($xml->nodeType == XMLReader::ELEMENT && $xml->localName == 'CLIENTES') {
        while ($xml->read()) {
            if ($xml->nodeType == XMLReader::ELEMENT && $xml->localName == 'CLIENTE') {
                // Import all child elements into $cl
                $cl = simplexml_import_dom($doc->importNode($xml->expand(), true));
                // Extract each piece of data, i.e. $cl->CODIGO_INTERESSADO and convert to string to store it
                $cliente = [ 'codigo_interessado' => (string)$cl->CODIGO_INTERESSADO,
                    'nome_interessado' => (string)$cl->NOME_INTERESSADO,

                    // You will need to complete this bit

                ];
                // Loop across each of the TELEFONE records and store them
                foreach ( $cl->TELEFONES->TELEFONE as $telefone )   {
                    $cliente['telefones'][] = ['numero' => (string)$telefone->NUMERO,
                        'tipo' => (string)$telefone->TIPO
                    ];
                }
                // Add the new data to the overall list
                $clientes[] = $cliente;
            }
        }

    }
}

Это предполагает, что каждый <CLIENTE> не очень велик. Возможно, вам также придется следить за тем, чтобы массив $clientes не стал слишком большим.

Это сработало, Найджел Рен, спасибо. Мой файл XML очень большой, в нем много узлов CLIENTE. Узел CLIENTE имеет внутри себя больше узлов, всего 25 узлов, 2 из них с той же структурой, что и TELEFONE, с дочерними элементами. Это плохо, если я буду продолжать использовать ваш метод для анализа данных?

churros 22.04.2019 17:06

Этот метод подходит для большинства задач, он будет обрабатывать узлы CLIENTE со 100 (если не 1000) узлами. Делает обработку каждого намного проще.

Nigel Ren 22.04.2019 17:09

Другие вопросы по теме