sql >> Base de Datos >  >> RDS >> Mysql

¿Cómo obtengo un archivo zip de 50 MB con un archivo xml de 600 MB en una tabla de datos mysql?

MySQL no conoce su estructura XML. Si bien puede importar estructuras XML simples y bien formadas directamente, deberá convertir estructuras más complejas usted mismo. Puede generar CSV, SQL o un XML (compatible).

Para archivos grandes como ese, XMLReader es la mejor API. Primero crea una instancia y abre el archivo:

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

Está utilizando espacios de nombres, por lo que sugiero definir una matriz de mapeo para ellos:

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

Es posible usar los mismos prefijos/alias que en el archivo XML, pero también puede usar los suyos propios.

A continuación, recorra los nodos XML hasta que encuentre el primer nodo del elemento de registro:

while (
  $reader->read() && 
  ($reader->localName !== 'ABCRecord' ||  $reader->namespaceURI !== $xmlns['a'])
) {
  continue;
}

Debe comparar el nombre local (el nombre de la etiqueta sin el prefijo del espacio de nombres) y el URI del espacio de nombres. De esta manera, su programa no depende de los prefijos reales en el archivo XML.

Después de encontrar el primer nodo, puede atravesar al siguiente hermano con el mismo nombre 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');
}

Puede usar XMLReader para leer los datos del registro, pero es más fácil con las expresiones DOM y XPath. XMLReader puede expandir el nodo actual en un nodo DOM. Así que prepare un documento DOM, cree un objeto XPath para él y registre los espacios de nombres. Expandir un nodo cargará el nodo y todos los descendientes en la memoria, pero no los nodos principales ni los hermanos.

$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() le permite usar la expresión Xpath para obtener valores escalares o listas de nodos de un DOM.

fputcsv() ¿Será realmente fácil escribir los datos en un CSV?

Juntar:

// 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');
} 

Salida:

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