J'essaie d'analyser les fichiers XML du contenu et des structures de DMOZ dans MySQL, mais tous les scripts existants pour ce faire sont très anciens et ne fonctionnent pas bien. Comment puis-je ouvrir un gros fichier XML (1 Go) en PHP pour l'analyser ?
Réponses
Trop de publicités?Ce n'est pas une solution idéale, mais c'est juste pour proposer une autre option :
Vous pouvez diviser de nombreux fichiers XML volumineux en morceaux, notamment ceux qui ne sont que des listes d'éléments similaires (comme le fichier sur lequel vous travaillez).
Par exemple, si votre doc ressemble à.. :
<dmoz>
<listing>....</listing>
<listing>....</listing>
<listing>....</listing>
<listing>....</listing>
<listing>....</listing>
<listing>....</listing>
...
</dmoz>
Vous pouvez le lire en une méga ou deux à la fois, envelopper artificiellement le peu de complet <listing>
que vous avez chargées dans une balise de niveau Root, puis les charger via simplexml/domxml (j'ai utilisé domxml, en adoptant cette approche).
Franchement, je préfère cette approche si vous utilisez PHP < 5.1.2. Avec 5.1.2 et plus, XMLReader est disponible, ce qui est probablement la meilleure option, mais avant cela, vous êtes coincé avec soit la stratégie de chunking ci-dessus, soit la vieille librairie SAX/expat. Et je ne sais pas pour le reste d'entre vous, mais je déteste écrire/maintenir des parsers SAX/expat.
Notez, cependant, que cette approche n'est PAS vraiment pratique lorsque votre document n'a pas se composer de nombreux éléments identiques de niveau inférieur (par exemple, cela fonctionne très bien pour toute sorte de liste de fichiers, ou d'URL, etc., mais cela n'aurait aucun sens pour l'analyse d'un gros document HTML)
Vous pouvez combiner XMLReader avec DOM pour cela. En PHP, les deux API (et SimpleXML) sont basées sur la même bibliothèque - libxml2. Les grands XML sont généralement une liste d'enregistrements. Vous utilisez donc XMLReader pour itérer les enregistrements, charger un seul enregistrement dans DOM et utiliser les méthodes DOM et Xpath pour extraire les valeurs. La clé est la méthode XMLReader::expand()
. Il charge le nœud actuel dans une instance XMLReader et ses descendants en tant que nœuds DOM.
Exemple XML :
<books>
<book>
<title isbn="978-0596100087">XSLT 1.0 Pocket Reference</title>
</book>
<book>
<title isbn="978-0596100506">XML Pocket Reference</title>
</book>
<!-- ... -->
</books>
Exemple de code :
// open the XML file
$reader = new XMLReader();
$reader->open('books.xml');
// prepare a DOM document
$document = new DOMDocument();
$xpath = new DOMXpath($document);
// find the first `book` element node at any depth
while ($reader->read() && $reader->localName !== 'book') {
continue;
}
// as long as here is a node with the name "book"
while ($reader->localName === 'book') {
// expand the node into the prepared DOM
$book = $reader->expand($document);
// use Xpath expressions to fetch values
var_dump(
$xpath->evaluate('string(title/@isbn)', $book),
$xpath->evaluate('string(title)', $book)
);
// move to the next book sibling node
$reader->next('book');
}
$reader->close();
Notez que le nœud développé n'est jamais ajouté au document DOM. Cela permet au GC de le nettoyer.
Cette approche fonctionne également avec les espaces de noms XML.
$namespaceURI = 'urn:example-books';
$reader = new XMLReader();
$reader->open('books.xml');
$document = new DOMDocument();
$xpath = new DOMXpath($document);
// register a prefix for the Xpath expressions
$xpath->registerNamespace('b', $namespaceURI);
// compare local node name and namespace URI
while (
$reader->read() &&
(
$reader->localName !== 'book' ||
$reader->namespaceURI !== $namespaceURI
)
) {
continue;
}
// iterate the book elements
while ($reader->localName === 'book') {
// validate that they are in the namespace
if ($reader->namespaceURI === $namespaceURI) {
$book = $reader->expand($document);
var_dump(
$xpath->evaluate('string(b:title/@isbn)', $book),
$xpath->evaluate('string(b:title)', $book)
);
}
$reader->next('book');
}
$reader->close();
Ma solution :
$reader = new XMLReader();
$reader->open($fileTMP);
while ($reader->read()) {
if ($reader->nodeType === XMLReader::ELEMENT && $reader->name === 'xmltag' && $reader->isEmptyElement === false) {
$item = simplexml_load_string($reader->readOuterXML(), null, LIBXML_NOCDATA);
//operations on file
}
}
$reader->close();
0 votes
amolnpujari.wordpress.com/2012/03/31/reading_huge_xml-rb il est si simple de traiter de gros fichiers xml en ruby