Mysql
 sql >> Database >  >> RDS >> Mysql

Come posso ottenere un file zip da 50 MB con un file xml da 600 MB in un datatable mysql?

MySQL non conosce la tua struttura XML. Sebbene possa importare direttamente strutture XML semplici e ben formate, dovrai convertire tu stesso strutture più complesse. Puoi generare CSV, SQL o un XML (supportato).

Per file di grandi dimensioni come quello XMLReader è la migliore API. Per prima cosa crea un'istanza e apri il file:

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

Stai usando gli spazi dei nomi, quindi ti suggerisco di definire un array di mappatura per loro:

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

È possibile utilizzare gli stessi prefissi/alias del file XML, ma puoi anche utilizzare i tuoi.

Quindi attraversa i nodi XML fino a trovare il primo nodo dell'elemento record:

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

È necessario confrontare il nome locale (il nome del tag senza il prefisso dello spazio dei nomi) e l'URI dello spazio dei nomi. In questo modo la programmazione non dipende dai prefissi effettivi nel file XML.

Dopo aver trovato il primo nodo, puoi passare al fratello successivo con lo stesso nome locale.

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

È possibile utilizzare XMLReader per leggere i dati del record, ma è più semplice con le espressioni DOM e XPath. XMLReader può espandere il nodo corrente in un nodo DOM. Quindi prepara un documento DOM, crea un oggetto XPath per esso e registra gli spazi dei nomi. L'espansione di un nodo caricherà il nodo e tutti i discendenti in memoria, ma non i nodi principali o i fratelli.

$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() consente di utilizzare l'espressione Xpath per recuperare valori scalari o elenchi di nodi da un DOM.

fputcsv() renderà davvero facile scrivere i dati in un CSV.

Metti insieme:

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

Uscita:

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