Как получить 50-мегабайтный zip-файл с файлом размером 600 МБ (более 300 000 "<" abc: ABCRecord ">") в datatable mysql? Сам файл xml имеет следующую структуру:
<?xml version='1.0' encoding='UTF-8'?> <abc:ABCData xmlns:abc="http://www.abc-example.com" xmlns:xyz="http:/www.xyz-example.com"> <abc:ABCHeader> <abc:ContentDate>2015-08-15T09:03:29.379055+00:00</abc:ContentDate> <abc:FileContent>PUBLISHED</abc:FileContent> <abc:RecordCount>310598</abc:RecordCount> <abc:Extension> <xyz:Sources> <xyz:Source> <xyz:ABC>5967007LIEEXZX4LPK21</xyz:ABC> <xyz:Name>Bornheim Register Centre</xyz:Name> <xyz:ROCSponsorCountry>NO</xyz:ROCSponsorCountry> <xyz:RecordCount>398</xyz:RecordCount> <xyz:ContentDate>2015-08-15T05:00:02.952+02:00</xyz:ContentDate> <xyz:LastAttemptedDownloadDate>2015-08-15T09:00:01.885686+00:00</xyz:LastAttemptedDownloadDate> <xyz:LastSuccessfulDownloadDate>2015-08-15T09:00:02.555222+00:00</xyz:LastSuccessfulDownloadDate> <xyz:LastValidDownloadDate>2015-08-15T09:00:02.555222+00:00</xyz:LastValidDownloadDate> </xyz:Source> </xyz:Sources> </abc:Extension> </abc:ABCHeader> <abc:ABCRecords> <abc:ABCRecord> <abc:ABC>5967007LIEEXZX4LPK21</abc:ABC> <abc:Entity> <abc:LegalName>REGISTERENHETEN I Bornheim</abc:LegalName> <abc:LegalAddress> <abc:Line1>Havnegata 48</abc:Line1> <abc:City>Bornheim</abc:City> <abc:Country>NO</abc:Country> <abc:PostalCode>8900</abc:PostalCode> </abc:LegalAddress> <abc:HeadquartersAddress> <abc:Line1>Havnegata 48</abc:Line1> <abc:City>Bornheim</abc:City> <abc:Country>NO</abc:Country> <abc:PostalCode>8900</abc:PostalCode> </abc:HeadquartersAddress> <abc:BusinessRegisterEntityID register="Enhetsregisteret">974757873</abc:BusinessRegisterEntityID> <abc:LegalForm>Organisasjonsledd</abc:LegalForm> <abc:EntityStatus>Active</abc:EntityStatus> </abc:Entity> <abc:Registration> <abc:InitialRegistrationDate>2014-06-15T12:03:33.000+02:00</abc:InitialRegistrationDate> <abc:LastUpdateDate>2015-06-15T20:45:32.000+02:00</abc:LastUpdateDate> <abc:RegistrationStatus>ISSUED</abc:RegistrationStatus> <abc:NextRenewalDate>2016-06-15T12:03:33.000+02:00</abc:NextRenewalDate> <abc:ManagingLOU>59670054IEEXZX44PK21</abc:ManagingLOU> </abc:Registration> </abc:ABCRecord> <abc:ABCRecord> <abc:ABC>5967007LIE45ZX4MHC90</abc:ABC> <abc:Entity> <abc:LegalName>SUNNDAL HOSTBANK</abc:LegalName> <abc:LegalAddress> <abc:Line1>Sunfsalsvegen 15</abc:Line1> <abc:City>SUNNDALSPRA</abc:City> <abc:Country>NO</abc:Country> <abc:PostalCode>6600</abc:PostalCode> </abc:LegalAddress> <abc:HeadquartersAddress> <abc:Line1>Sunndalsvegen 15</abc:Line1> <abc:City>SUNNDALSPRA</abc:City> <abc:Country>NO</abc:Country> <abc:PostalCode>6600</abc:PostalCode> </abc:HeadquartersAddress> <abc:BusinessRegisterEntityID register="Foretaksregisteret">9373245963</abc:BusinessRegisterEntityID> <abc:LegalForm>Hostbank</abc:LegalForm> <abc:EntityStatus>Active</abc:EntityStatus> </abc:Entity> <abc:Registration> <abc:InitialRegistrationDate>2014-06-26T15:01:02.000+02:00</abc:InitialRegistrationDate> <abc:LastUpdateDate>2015-06-27T15:02:39.000+02:00</abc:LastUpdateDate> <abc:RegistrationStatus>ISSUED</abc:RegistrationStatus> <abc:NextRenewalDate>2016-06-26T15:01:02.000+02:00</abc:NextRenewalDate> <abc:ManagingLOU>5967007LIEEXZX4LPK21</abc:ManagingLOU> </abc:Registration> </abc:ABCRecord> </abc:ABCRecords> </abc:ABCData>
Как должна выглядеть таблица mysql и как я могу это сделать? Цель состоит в том, чтобы все содержимое, помеченное abc в таблице. Кроме того, каждый день предоставляется новый zip-файл через ссылку для загрузки, и он должен обновлять таблицу каждый день. Почтовые файлы называются в следующей структуре: «20150815-XYZ-concatenated-file.zip». Пошаговый намек был бы замечательным? Я пробовал это: импортировать XML-файл со специальными тегами и пространствами имен <abc: xyz> в mysql как сейчас, но он еще не выполнен!
Основываясь на объяснении ThW ниже, я сделал следующее сейчас:
<?php // open input $reader = new XMLReader(); $reader->open('./xmlreader.xml'); // open output $output = fopen('./xmlreader.csv', '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'); }
Это верно?! И где я могу найти выход ?! И как мне получить вывод в mysql. Извините за мои вопросы о новичках, это первый раз, когда я это делаю …
$dbHost = "localhost"; $dbUser = "root"; $dbPass = "password"; $dbName = "new_xml_extract"; $dbConn = mysqli_connect($dbHost, $dbUser, $dbPass, $dbName); $delete = $dbConn->query("TRUNCATE TABLE `test_xml`"); .... $sql = "INSERT INTO `test_xml` (`.....`, `.....`)" . "VALUES ('". $dbConn->real_escape_string($.....) ."', '".$dbConn->real_escape_string($.....)."')"; $result = $dbConn->query($sql); }
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"