Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Como obtenho um arquivo zip de 50 MB com um arquivo xml de 600 MB em uma tabela de dados mysql?


O MySQL não conhece sua estrutura XML. Embora possa importar diretamente estruturas XML simples e bem formadas, você mesmo precisará converter estruturas mais complexas. Você pode gerar CSV, SQL ou um XML (suportado).

Para arquivos grandes como esse XMLReader é a melhor API. Primeiro crie uma instância e abra o arquivo:
$reader = new XMLReader();
$reader->open('php://stdin');

Você está usando namespaces, então sugiro definir uma matriz de mapeamento para eles:
$xmlns = [
  'a' => 'http://www.abc-example.com'
];

É possível usar os mesmos prefixos/aliases do arquivo XML, mas você também pode usar os seus próprios.

Em seguida, percorra os nós XML até encontrar o primeiro nó do elemento de registro:
while (
  $reader->read() && 
  ($reader->localName !== 'ABCRecord' ||  $reader->namespaceURI !== $xmlns['a'])
) {
  continue;
}

Você precisa comparar o nome local (o nome da tag sem o prefixo do namespace) e o URI do namespace. Desta forma a sua programação não depende dos prefixos reais no arquivo XML.

Depois de encontrar o primeiro nó, você pode passar para o próximo irmão com o mesmo nome local.
while ($reader->localName === 'ABCRecord') {
  if ($reader->namespaceURI === 'http://www.abc-example.com') {
    // read data for the record ...
  }      
  // move to the next record sibling
  $reader->next('ABCRecord');
}

Você pode usar XMLReader para ler os dados do registro, mas é mais fácil com expressões DOM e XPath. XMLReader pode expandir o nó atual em um nó DOM. Portanto, prepare um documento DOM, crie um objeto XPath para ele e registre os namespaces. A expansão de um nó carregará o nó e todos os descendentes na memória, mas não os nós pais ou irmãos.
$dom   = new DOMDocument;
$xpath = new DOMXpath($dom);
foreach ($xmlns as $prefix => $namespaceURI) {
  $xpath->registerNamespace($prefix, $namespaceURI);
}

while ($reader->localName === 'ABCRecord') {
  if ($reader->namespaceURI === 'http://www.abc-example.com') {
    $node = $reader->expand($dom);
    var_dump(
      $xpath->evaluate('string(a:ABC)', $node),
      $xpath->evaluate('string(a:Entity/a:LegalName)', $node)
    );
  }
  $reader->next('ABCRecord');
}

DOMXPath::evaluate() permite que você use a expressão Xpath para buscar valores escalares ou listas de nós de um DOM.

fputcsv() será muito fácil escrever os dados em um CSV.

Coloque junto:
// open input
$reader = new XMLReader();
$reader->open('php://stdin');

// open output
$output = fopen('php://stdout', 'w');
fputcsv($output, ['id', 'name']);

$xmlns = [
  'a' => 'http://www.abc-example.com'
];

// prepare DOM
$dom   = new DOMDocument;
$xpath = new DOMXpath($dom);
foreach ($xmlns as $prefix => $namespaceURI) {
  $xpath->registerNamespace($prefix, $namespaceURI);
}

// look for the first record element
while (
  $reader->read() && 
  (
    $reader->localName !== 'ABCRecord' || 
    $reader->namespaceURI !== $xmlns['a']
  )
) {
  continue;
}

// while you have an record element
while ($reader->localName === 'ABCRecord') {
  if ($reader->namespaceURI === 'http://www.abc-example.com') {
    // expand record element node
    $node = $reader->expand($dom);
    // fetch data and write it to output
    fputcsv(
      $output, 
      [
        $xpath->evaluate('string(a:ABC)', $node),
        $xpath->evaluate('string(a:Entity/a:LegalName)', $node)
      ]
    );
  }

  // move to the next record sibling
  $reader->next('ABCRecord');
} 

Resultado:
id,name
5967007LIEEXZX4LPK21,"REGISTERENHETEN I Bornheim"
5967007LIE45ZX4MHC90,"SUNNDAL HOSTBANK"