Parser en PHP de gros fichiers XML

En PHP 7, plusieurs méthodes existent pour parser des xml. SimpleXML est très pratique et facile d'accès mais consomme énormement de mémoire avec des gros fichiers. Voyons comment être plus robuste avec l'api XMLReader qui ne charge pas tout le fichier source en mémoire mais traite les données sous forme de flux.

Prenons la structure de xml suivante:

 1<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
 2<pdv_liste>
 3  <pdv id="1000001" cp="01000" pop="R">
 4    <prix nom="Gazole" id="1" maj="2019-01-04T10:53:48" valeur="1328"/>
 5    <prix nom="Gazole" id="1" maj="2019-01-07T10:25:25" valeur="1348"/>
 6  </pdv>
 7  <pdv id="1000002" latitude="4621842" longitude="522767" cp="01000" pop="R">
 8    <prix nom="Gazole" id="1" maj="2019-01-03T13:12:46" valeur="1344"/>
 9    <prix nom="Gazole" id="1" maj="2019-01-04T14:47:58" valeur="1344"/>
10  </pdv>
11</pdv_liste>

L'exemple réel est tiré de https://donnees.roulez-eco.fr/opendata/annee/2019 dont le fichier xml fait 300Mo, comporte 13000 noeuds <pdv> et 4 millions de noeuds <prix>

Utilisation de SimpleXML seul :

 1#!/usr/bin/env php
 2<?php
 3
 4$bigXmlFile = 'PrixCarburants_annuel_2019.xml';
 5
 6$xmlRoot = simplexml_load_file($bigXmlFile);
 7foreach ($xmlRoot as $pdvNode) {
 8  foreach ($pdvNode->prix as $prix) {
 9    echo (float) $prix['valeur'] . "\n";
10  }
11}

Le script va planter si trop peu de mémoire est alloué.

Utilisation avec XmlReader et SimpleXML :

 1#!/usr/bin/env php
 2<?php
 3
 4$bigXmlFile = 'PrixCarburants_annuel_2019.xml';
 5
 6$bigXmlReader = new XMLReader();
 7$bigXmlReader->open($bigXmlFile);
 8while ($bigXmlReader->read()) {
 9  if ($bigXmlReader->name === 'pdv') {
10    $subXmlStr = $bigXmlReader->readOuterXml();
11    $pdvNode = simplexml_load_string($subXmlStr);
12    foreach ($pdvNode->prix as $prix) {
13      echo (float) $prix['valeur'] . "\n";
14    }
15  }
16}
17$bigXmlReader->close();

Le script ne va pas aller plus vite mais ne consommera que très peu de mémoire.

comments powered by Disqus