Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Wie bekomme ich eine 50-MB-Zip-Datei mit einer 600-MB-XML-Datei in eine MySQL-Datentabelle?

MySQL kennt Ihre XML-Struktur nicht. Während einfache, wohlgeformte XML-Strukturen direkt importiert werden können, müssen Sie komplexere Strukturen selbst konvertieren. Sie können CSV, SQL oder ein (unterstütztes) XML generieren.

Für große Dateien wie diesen ist XMLReader die beste API. Erstellen Sie zuerst eine Instanz und öffnen Sie die Datei:

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

Sie verwenden Namespaces, daher schlage ich vor, ein Mapping-Array für sie zu definieren:

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

Es ist möglich, dieselben Präfixe/Aliase wie in der XML-Datei zu verwenden, aber Sie können auch Ihre eigenen verwenden.

Durchlaufen Sie als Nächstes die XML-Knoten, bis Sie den ersten Datensatzelementknoten finden:

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

Sie müssen den lokalen Namen (den Tag-Namen ohne das Namespace-Präfix) und den Namespace-URI vergleichen. Auf diese Weise ist Ihre Programmierung nicht von den tatsächlichen Präfixen in der XML-Datei abhängig.

Nachdem Sie den ersten Knoten gefunden haben, können Sie zum nächsten gleichgeordneten Knoten mit demselben lokalen Namen wechseln.

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

Sie könnten XMLReader verwenden, um die Datensatzdaten zu lesen, aber mit DOM- und XPath-Ausdrücken ist es einfacher. XMLReader kann den aktuellen Knoten in einen DOM-Knoten erweitern. Bereiten Sie also ein DOM-Dokument vor, erstellen Sie ein XPath-Objekt dafür und registrieren Sie die Namespaces. Das Erweitern eines Knotens lädt den Knoten und alle Nachkommen in den Speicher, aber keine Elternknoten oder Geschwister.

$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() ermöglicht Ihnen die Verwendung von Xpath-Ausdrücken zum Abrufen von Skalarwerten oder Knotenlisten aus einem DOM.

fputcsv() macht es wirklich einfach, die Daten in eine CSV zu schreiben.

Zusammengesetzt:

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

Ausgabe:

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