sql >> データベース >  >> RDS >> Mysql

600MBのxmlファイルを含む50MBのzipファイルをmysqlデータテーブルに取り込むにはどうすればよいですか?

    MySQLはXML構造を認識していません。単純で整形式のXML構造を直接インポートできますが、より複雑な構造を自分で変換する必要があります。 CSV、SQL、または(サポートされている)XMLを生成できます。

    そのような大きなファイルの場合、XMLReaderが最適なAPIです。最初にインスタンスを作成してファイルを開きます:

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

    名前空間を使用しているので、それらのマッピング配列を定義することをお勧めします:

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

    XMLファイルと同じプレフィックス/エイリアスを使用することは可能ですが、独自のものを使用することもできます。

    次に、最初のレコード要素ノードが見つかるまでXMLノードをトラバースします。

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

    ローカル名(名前名プレフィックスのないタグ名)と名前付けURIを比較する必要があります。この方法でプログラムするのは、XMLファイルの実際のプレフィックスに依存しません。

    最初のノードを見つけたら、同じローカル名で次の兄弟に移動できます。

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

    XMLReaderを使用してレコードデータを読み取ることもできますが、DOMおよびXPath式を使用すると簡単になります。 XMLReaderは、現在のノードをDOMノードに拡張できます。したがって、DOMドキュメントを準備し、そのためのXPathオブジェクトを作成して、名前空間を登録します。ノードを展開すると、ノードとすべての子孫がメモリにロードされますが、親ノードや兄弟はロードされません。

    $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() Xpath式を使用して、DOMからスカラー値またはノードリストをフェッチできます。

    fputcsv() データをCSVに書き込むのが本当に簡単になりますか。

    まとめる:

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

    出力:

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



    1. 大きなMySqlテーブルの重複を削除します

    2. 単一または複数のデータベース

    3. MySQLでsqlalchemy接続を閉じる方法

    4. 正規表現str_replace