19 août 2011

Mapping XML - Array - JSON en PHP

Vouloir établir une correspondance entre JSON et XML n'est pas nouveau. (cf. Converting Between XML and JSON). D'ailleurs, le Zend Framework propose sa solution XML to JSON conversion.
Cependant,

  • le format est-il adapté ?
  • l’opération inverse est-elle possible ?

Vouloir passer du XML au JSON revient en fait à transformer du XML en une structure mémoire de type tableau. Toutes les solutions en PHP que j'ai trouvé passe par cette étape. Aucune ne transforme la chaîne de caractères XML en chaîne de caractères JSON. La véritable question est donc :
Comment faire un mapping entre XML et un tableau PHP ?
Le format JSON n'étant plus qu'une sérialisation du tableau. Du coup, l'opération inverse n'est pas de vouloir transformer du JSON en XML mais bien de vouloir transformer un tableau en XML. Le problème est donc de passer d'une structure mémoire à un fichier XML et réciproquement. CQFD ;-)
La belle affaire me direz-vous ? C'est pareil ! Oui sauf qu'en abordant le problème de cette manière, on doit produire un code capable de transformer toute structure mémoire en XML, et cela a une influence directe sur le format d’équivalence que l'on va choisir. Et à ce petit jeu là, c'est le format proposé par Google qui me semble le plus adapté ! cf. Using JSON in the Google Data Protocol

XML_Array

Voici donc une petite classe PHP, disponible au travers d'un package PEAR qui permet de transformer n'importe quel document XML en tableau PHP. Mais qui permet également l'opération inverse à savoir transformer n'importe quel tableau PHP en fichier XML.

array2xml.php

<?php
require_once 'XML/Array.php';

$array_input = array (
  'rdf:RDF' => 
  array (
    'xmlns:rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
    'xmlns' => 'http://www.exemple.com/fake#',
    'rdf:Description' => 
    array (
      0 => 
      array (
        'rdf:about' => 'urn:id:aaa',
        'name' => 
        array (
          '#text' => 'Dupont T.',
        ),
        'email' => 
        array (
          'type' => 'main',
          '#text' => 'dupont@example.com',
        ),
      ),
      1 => 
      array (
        'rdf:about' => 'urn:id:bbb',
        'name' => 
        array (
          '#text' => 'Dupond D.',
        ),
        'email' => 
        array (
          'type' => 'main',
          '#text' => 'dupond@exeample.com ',
        ),
      ),
    ),
  ),
);

$xml = XML_array::export($array_input);
$array_output = XML_array::import($xml);

assert($array_input == $array_output);

?>

xml2array.php

<?php
require_once 'XML/Array.php';
$xml_input = <<<EOT
<rdf:RDF
	xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
	xmlns="http://www.exemple.com/fake#">
	<rdf:Description rdf:about="urn:id:aaa">
		<name>Dupont T.</name>
		<email type="main">dupont@example.com</email>
	</rdf:Description>
	<rdf:Description rdf:about="urn:id:bbb">
		<name>Dupond D.</name>
		<email type="main">dupond@exeample.com </email>
	</rdf:Description>
</rdf:RDF>
EOT;

$array = XML_Array::import($xml_input);
$xml_output = XML_array::export($array);
 
$xml_input = preg_replace(',\s+,', '', $xml_input);
$xml_output = preg_replace(',\s+,', '', $xml_output);

assert($xml_input == $xml_output);
?>

Tables de correspondance

Règles principales
ARRAY XML
key ⇒ array( key1 ⇒ value, ) <key key1="value/>
key ⇒ array( #text ⇒ value1, ) <key>value1</key>
key ⇒ array( array(…), array(…), ) <key>…</key><key>…</key>
0 ⇒ value <![CDATA[value]]>
key ⇒ value <row key="value" />
#comment ⇒ value <!--value-→
Clefs réservées
XML values key
Text node $t, _t, _text, #text
comment node $c, _c, _comment, #comment
xml:lang xmllang, xml:lang, xml$lang
xml:space xmlspace, xml:space, xml$space
xml:id xmlid, xml:id, xml$id
xml:idref xmlidref, xml:idref, xml$idref

Benchmark

Voici une petite comparaison de performance en chargeant en mémoire séquentiellement 196867 documents XML pour un volume total de 250 Mo.


xml2str   => 53,292876 Seconds 
--------------------------------
xml2array => 178,356342 Seconds 
--------------------------------
xml2dom   => 64,135433 Seconds 

Téléchargement et code source

Le code source est disponible sur GitHub : http://github.com/touv/xml_array

ou on peut directement l'installer avec PEAR en s'abonnant au Channel Respear :


% pear channel-discover pear.respear.net
% pear install respear/xml_array

Webographie

Aucun commentaire:

Publier un commentaire