Validation des schémas XML en PHP

applications internet utilitaires

Ce site ne sera plus alimenté de contenu après août 2014. Tous les nouveaux articles seront redigés pour www.waitingforcode.com
En feuilletant mon bouquin sur les web services ("SOA and Web Services Interface Design" de James Bean), je me suis arrêté sur le chapitre consacré aux schémas XML (XML schema). Certains pensent que XML est un langage basique, quelques balises à droite, quelques-unes à gauche et basta. Cependant ce n'est pas ça du tout et grâce aux schémas on peut aller vraiment loin.

On commencera par la définition des schémas XML. On y présentera des simpleTypes (types simples) et des complexTypes (types complexes). On abordera également la question des namespaces (espaces de noms). Dans la deuxième partie de l'article on passera à des exemples des schémas XML.

De la simplicité complexifiée
La démocratisation de l'usage du XML a été perçue comme la pluie au milieu d'un désert. Il devait révolutionner le monde d'échange des données grâce à sa simplicité et sa portabilité. Mais avec le temps les problèmes apparaissaient. La question de validation d'un document XML a été abordée à plusieurs reprises. Afin de remédier à ces problèmes, le consortium W3C a publié une recommandation d'utilisation des schémas XML.

Les schémas XML sont des documents XML qui imposent une structure et un format des données à un autre document XML (celui qui est par exemple transmis au client d'un web service). Grâce aux schémas on peut indiquer au parseur XML que la balise <color /> doit, par exemple, être une chaîne de caractères avec "green" comme valeur par défaut dans le cas d'une balise vide. On peut aller encore plus loin et, avec l'utilisation des expressions régulières, signaler quels caractères peut avoir cette balise. On effectue toutes ces opérations grâce aux types simples et complexes.

Les types simples (simpleTypes) se réfèrent à un élément (balise) ou à son attribut. On peut valider ainsi des chaînes de caractères (string), des chiffres (float, double, decima), des booléans (boolean), le temps (dateTime, date) et même les URLs (anyURI). Un validateur du type simple peut se présenter ainsi :


<xs:simpleType name="bornYear">
<xs:restriction base="xs:gYear">
<xs:maxInclusive value="2001" />
<xs:maxExclusive value="2011" />
</xs:restriction>
</xs:simpleType>

Dans cet exemple on valide un élément <bornYear /> qui doit être la représentation d'une année (restriction gYear). En plus, l'année indiquée doit se trouver entre 2001 et 2011.

Les types complexes (complexTypes) se rapportent à quelques éléments et sont complémentaires à simpleTypes. On peut illustrer cela par la structure XML suivante :


<address>
<street>State Street
<zipcode>60602
<city>Chicago
<state>Illinois
<country>USA
</address>

On voit bien qu'un élément-parent <address /> est composé de 5 éléments-enfants (<street />, <zipcode />, <city />, <state />, <country />).
Sa validation en tant qu'un complexType va se présenter de la manière suivante :


<xs:element name="address">
<xs:complexType>
<xs:sequence>
<xs:element name="street" minOccurs="1" maxOccurs="1" />
<xs:element name="zipcode" minOccurs="1" maxOccurs="1" />
<xs:element name="city" minOccurs="1" maxOccurs="1" />
<xs:element name="state" minOccurs="1" maxOccurs="1" />
<xs:element name="country" minOccurs="1" maxOccurs="1" />
</xs:sequence>
</xs:complexType>
</xs:element>

Grâce à ce code on spécifie qu'un groupe des éléments dont l'élément-parent est <address /> doit contenir les sous-éléments suivants :
<street />, <zipcode />, <city />, <state />, <country />. Toutes ces balises doivent apparaître au moins et au maximum 1 fois. Donc le
document avec deux balises <street /> pour ce groupe sera invalide.

On passe maintenant au troisième concept, celui des espaces des noms (namespaces). Un document XML peut contenir plusieurs balises portant le
même nom. D'où le risque des collisions dans les schémas XML. Pour s'assurer que chaque élément sera validé par le schéma lui destiné, on a introduit la
notion des namespaces. Pour notre exemple on utilisera l'expédition d'un colis depuis la France (et uniquement la France) vers l'étranger. La validation sur
le pays sera donc différente pour les deux groupes. Le document va se présenter ainsi :


<EXPEDITION xmlns:SHIPPER="http://exemple/schema_shipper"
xmlns:RECIPIENT="http://exemple/schema_recipient">
<SHIPPER:info>
<SHIPPER:address>
<SHIPPER:country>FR
<SHIPPER:city>Nancy
</SHIPPER:address>
</SHIPPER:info>
<RECIPIENT:info>
<RECIPIENT:address>
<RECIPIENT:country>CA
<RECIPIENT:city>Toronto
</RECIPIENT:address>
</RECIPIENT:info>
</EXPEDITION>

On remarque la présence des deux espaces des noms : SHIPPER (pour expéditeur) et RECIPIENT (pour destinataire). Ils sont déterminés grâce
aux déclarations dans la balise <EXPEDITION /> par xmlns:SHIPPER et xmlns:RECIPIENT.

Validation XML en PHP
La validation d'un schéma XML en PHP peut être réalisée avec la méthode schemaValidate() appartenant à la classe DOMDocument. Cependant, pour aller un peu plus loin et récupérer les éléments invalides, on est obligé de faire un peu plus de développement. Il faut alors utiliser libxml, accessible depuis la version 5.1.0 du PHP.

La récupération des erreurs de validation d'un schéma XML se déroule grâce via la méthode libxml_get_errors().
Voici un exemple de validation d'un schéma XML :

// enable error handling
libxml_use_internal_errors(true);
$xdoc = new DOMDocument;
// load your XML document into DOMDocument object
$xdoc->load($_SERVER['DOCUMENT_ROOT'].'/xml/example.xml');
// validation part - add @ if you don't want to see the validation warnings
if (!@$xdoc->schemaValidate($_SERVER['DOCUMENT_ROOT'].'/xml/schema.xsd'))
{
echo "Document example.xml doesn't correspond to his XML schema, defined in schema.xsd file";
$errors = libxml_get_errors();
foreach($errors as $error)
{
echo 'Line: '.$error->line.' ===> '.$error->message.'
';
}
}

Les fichiers d'exemple à télécharger se trouvent dans le package.

En savoir plus :
- documentation de W3C sur les types de données

L'article écrit en rythme de:
Slaï - La dernière danse
Bartosz KONIECZNY 26-07-2011 14:07 applications web
Moi

Développeur d'applications Internet et journaliste passionné par l'adjectif français. Un aigle polonais orienté vers la progression, volant très haut et écoutant du zouk après les matches du foot français.

Vous appréciez mon travail ?

Pour contribuer au développement de ce site, ou pour remercier pour des articles rédigés, vous pouvez faire un don.

Un conseil PHP

Comment créer un base string pour OAuth

Création d'un base string pour OAuth consiste à récupérer 3 éléments et les concaténer. Il s'agit de : - la méthode HTTP d'appel de la ressource (GET ou POST) - l'url de l'appel (sans paramètres) - les paramtères utilisés dans la requête (il ne faut pas inclure oauth_signature car elle n'est pas encore générée) Tous les 3 éléments doivent être normalisés et concaténés avec un ampersand (&). L'ampersand ne peut pas subir l'encodage. Une méthode pour générer un base string peut se présenter ainsi :

function setBaseString($method, $url, $paramsList)
{
  $paramsString = array();
  foreach($paramsList as $p => $param)
  {
    $paramsString[] = $p.'='.$param;
  }
  return str_replace('%7E', '~', rawurlencode($method)).'&'.str_replace('%7E', '~', rawurlencode($url)).'&'.str_replace('%7E', '~', rawurlencode(implode('&', $paramsString)));
}