dongyu4908 2019-04-22 14:31
浏览 99
已采纳

使用XMLReader和PHP获取大型XML文件中的子树数据

I'm trying to read a big XML file using XMLReader and I can't find a way to loop through a subtree correctly.

So far, I tried to use the read() and the next() functions. And it's not working properly. Here is the XML structure that I'm parsing:

<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>

As you can see, the node TELEFONES, can have multiple TELEFONE nodes. So I need to loop that and get them individually. So far, this is my code:

$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();

I'm getting two problems here. First, my final array is having information about only one CLIENTE node. It should have all the CLIENTE nodes, I'm indexing them with the $cont var.

The other problem is that, the TELEFONES node that is going to my $clientes array belongs to the last CLIENTE node of the XML. So, somehow my code is going through every CLIENTE node, but when I treat the TELEFONES node, my $clientes array is getting all messed up.

I just can't find a way to loop a subtree using XMLParser. Can someone help me?

  • 写回答

1条回答 默认 最新

  • 普通网友 2019-04-22 14:55
    关注

    Rather than trying to read the whole document element by element, you can with XMLReader ask it to import segments.

    In this example code, once you get to the <CLIENTE> level, it reads all of the elements of that level into a SimpleXMLElement (using simplexml_import_dom()). Once you have done this, you can then process each one using the simpler interface and not have to deal with start and end tags etc...

    $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;
                }
            }
    
        }
    }
    

    This does assume that each <CLIENTE> isn't very large. You may also have to be careful that the array $clientes doesn't become too large.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 Arcgis相交分析无法绘制一个或多个图形
  • ¥15 seatunnel-web使用SQL组件时候后台报错,无法找到表格
  • ¥15 fpga自动售货机数码管(相关搜索:数字时钟)
  • ¥15 用前端向数据库插入数据,通过debug发现数据能走到后端,但是放行之后就会提示错误
  • ¥30 3天&7天&&15天&销量如何统计同一行
  • ¥30 帮我写一段可以读取LD2450数据并计算距离的Arduino代码
  • ¥15 飞机曲面部件如机翼,壁板等具体的孔位模型
  • ¥15 vs2019中数据导出问题
  • ¥20 云服务Linux系统TCP-MSS值修改?
  • ¥20 关于#单片机#的问题:项目:使用模拟iic与ov2640通讯环境:F407问题:读取的ID号总是0xff,自己调了调发现在读从机数据时,SDA线上并未有信号变化(语言-c语言)