首页 > 解决方案 > 使用 XMLReader 和 PHP 获取大 XML 文件中子树的数据

问题描述

我正在尝试使用 XMLReader 读取一个大的 XML 文件,但我找不到正确循环子树的方法。

到目前为止,我尝试使用 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 变量对它们进行索引。

另一个问题是,要访问我的 $clientes 数组的 TELEFONES 节点属于 XML 的最后一个 CLIENTE 节点。所以,不知何故,我的代码正在通过每个 CLIENTE 节点,但是当我处理 TELEFONES 节点时,我的 $clientes 数组变得一团糟。

我只是找不到使用 XMLParser 循环子树的方法。有人能帮我吗?

标签: phpxmlxmlreader

解决方案


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不要变得太大。


推荐阅读