php - 使用 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 循环子树的方法。有人能帮我吗?
解决方案
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
不要变得太大。
推荐阅读
- flutter - 在 Flutter 2.5 中在 Android 中全屏后仰、粘性、粘性沉浸式、边到边
- ubuntu - 我在 Intellij idea 中打开模拟器时出错
- android - RecyclerView 重置自定义视图的 LayoutParams
- c - 如果我只能访问指针变量,如何在调用函数时将指向结构的指针传递给 C 中的另一个函数
- java - javax.el.PropertyNotFoundException:在类型 [com.something.something.models.something] 上找不到属性 [版本] 我哪里出错了?
- r - 为什么 floor_date 会阻止 geom_rect() 绘制?
- kotlin - Kotlin:kotlin 编码时虚拟工作室代码出错
- node.js - ExpressJS 和 Mongoose 查询范围问题
- powerbi - PowerBI:在新列中计算每个 ID 和每个周期的唯一子 ID
- hololens - 如何在 Hololens2 中移动 UWP 应用位置?