Satimage Précédent
Tutoriel sur XML
Accueil Documentation Smile XML et property lists Tutoriel sur XML  
À propos du tutoriel

Ce tutoriel présente quelques exemples d'utilisation des commandes du moteur XML, sur un vrai fichier. Nous allons manipuler le tableau périodique des éléments chimiques (c'est ainsi qu'on appelle la liste de tous les atomes connus avec leurs principales propriétés physiques). Vous pourrez afficher les fichiers XML dans votre navigateur.

A tout moment vous pouvez copier les scripts sur votre machine et les tester. Pour importer les scripts, cliquez le lien ci-dessous :
-- étape 1: ouverture du document XML Retour | Précédent | Suivant

Nous manipulons le tableau périodique des éléments. Pour afficher le fichier XML dans une nouvelle page de votre navigateur, cliquez ici : allelements.txt.

À cette étape nous allons simplement ouvrir le document et obtenir une référence au nœud racine. Notez que l'instruction XMLOpen peut nécessiter plusieurs secondes : elle lit un fichier de 112Ko sur un serveur distant puis construit la table interne qui lui permettra de répondre rapidement à nos requêtes.
set the_URL to "http://www.satimage.fr/software/samples/allelements.xml"
set the_doc to XMLOpen the_URL
  --  «data XMLR0000000100000000»

set the_root to XMLRoot the_doc
  --  «data XMLR0000000104739D80»
La suite du tutoriel utilise les variables définies ci-dessus.

Le fichier XML ci-dessus ne déclare pas sa DTD : il n'est en effet pas obligatoire de déclarer un DTD. Vous pouvez en avoir confirmation en exécutant la ligne suivante :

XMLValidate the_doc
qui affichera un message d'erreur.

-- étape 2: navigation dans l'arbre XML Retour | Précédent | Suivant
Explorons rapidement quelques éléments de l'arbre :
XMLCount the_root
  --  112
  --  le tableau contient 112 atomes

set the_child to XMLChild the_root index 1
  --  «data XMLR0000000104739DC0»
  --  the_child est une référence "opaque"
  --  utilisons XMLNodeInfo pour connaître son type

XMLNodeInfo the_child
  --  {kind:"ELEMENT_NODE", name:"ATOM"}
  --  l'atome lui-même possède des nœuds XML enfants :

set the_child_2 to XMLChild the_child index 1
XMLNodeInfo the_child_2
  --  {kind:"ELEMENT_NODE", name:"NAME"}
  --  le premier nœud XML enfant du premier atome est le nom de l'atome

XMLGetText the_child_2
  --  "Actinium"

set the_child_2 to XMLNextSibling the_child_2
XMLNodeInfo the_child_2
  --  {kind:"ELEMENT_NODE", name:"ATOMIC_WEIGHT"}
  --  le deuxième nœud enfant du premier atome est sa masse atomique

XMLGetText the_child_2
  --  "227"
  --  l'Actinium est un atome lourd !
-- étape 3: recherche de l'atome d'Hydrogène dans l'arbre Retour | Précédent | Suivant
Maintenant supposons que nous devions retrouver la masse atomique de l'Hydrogène.

Du fait qu'il n'y ait pas de DTD pour notre fichier XML, il faut afficher le fichier pour savoir sous quelle forme la masse atomique est stockée : il est possible d'ouvrir directement le fichier (cliquez ici) car il s'agit d'un simple fichier texte, mais on peut aussi utiliser XMLDisplayXML :

XMLDisplayXML the_child
  --  Result:
  <ATOM>
    <NAME>Actinium</NAME>
    <ATOMIC_WEIGHT>227</ATOMIC_WEIGHT>
    <ATOMIC_NUMBER>89</ATOMIC_NUMBER>
    etc.
  </ATOM>

Comme nous le voyons, ATOM n'a pas d'attributs : nous aurions pu penser que chaque atome avait un attribut NAME, mais ce n'est pas le cas (au lieu de cela, l'élément ATOM possède un élément NAME). Il nous faut donc utiliser un XPATH pour récupérer l'élément d'Hydrogène (sinon il aurait été plus simple d'utiliser XMLFind). La requête XPATH ci-dessous recherche un élément du type ATOM ayant un élément NAME dont la valeur est "Hydrogen": ATOM[NAME:="Hydrogen"]. Puis nous utilisons XLMFind pour obtenir la valeur de la masse atomique.
set {the_atom} to XMLXpath the_root with "ATOM[NAME=\"Hydrogen\"]"
set the_weight to XMLFind the_atom name "ATOMIC_WEIGHT"
XMLGetText the_weight
  --  "1.00794"
Il est possible d'effectuer une requête XPATH plus compliquée pour obtenir directement ATOMIC_WEIGHT d'un ATOM (ATOM/ATOMIC_WEIGHT) en donnant une condition sur son parent (../): ATOM/ATOMIC_WEIGHT[../NAME="Hydrogen"].
set the_weight to XMLXpath the_root with "ATOM/ATOMIC_WEIGHT[../NAME=\"Hydrogen\"]"
XMLGetText the_weight
  --  "1.00794"
L'Actinium n'a pas d'attribut, mais l'Hydrogène en a un :
XMLNodeInfo the_atom
  --  {kind:"ELEMENT_NODE", name:"ATOM", attribute:{"STATE", "GAS"}}
Il est possible d'utiliser XMLFind pour obtenir la liste de tous les éléments gazeux de la table (plus précisément, tous les atomes ayant un attribut "STATE" valant "GAS").
set the_gases to XMLFind the_root key "STATE" value "GAS" with all occurrences
  --  {«data XMLR0000000102BDA210», «data XMLR00000001058360D0», «data XMLR0000000105837530», «data XMLR0000000105880080»}

repeat with the_gas in the_gases
    msg(XMLGetText (XMLChild the_gas index 1))
end repeat
-- Result:
    Argon
    Hydrogen
    Helium
    Xenon

-- étape 4 : affichage d'un nœud Retour | Précédent | Suivant
Nous avons déjà utilisé XMLNodeInfo, XMLDisplayXML et XMLGetText. Insistons sur la différence entre XMLNodeInfo et XMLDisplayXML : XMLNodeInfo affiche les informations d'un nœud XML, sous la forme d'un record contenant le nom du nœud (son "tag"), son type ainsi que ses attributs s'il en a. XMLDisplayXML affiche l'ensemble du nœud sous forme de texte.
XMLNodeInfo the_atom
  --  {kind:"ELEMENT_NODE", name:"ATOM", attribute:{"STATE", "GAS"}}

XMLDisplayXML the_atom
  --  Result:
  <ATOM STATE=\"GAS\">
    <NAME>Hydrogen</NAME>
    <ATOMIC_WEIGHT>1.00794</ATOMIC_WEIGHT>
    <ATOMIC_NUMBER>1</ATOMIC_NUMBER>
    etc.
  </ATOM>
XMLGetText s'applique à un nœud élémentaire :
XMLGetText the_weight
  --  "1.00794"
Vous pouvez également l'utiliser sur un nœud plus complexe, mais le résultat risque d'être illisible :
XMLGetText the_atom
  --  Result:
    Hydrogen1.007941120.2813.81H
    0.0899
    1s1 0.322.12.08
    etc.
XMLGetText (ainsi que XMLNodeInfo et XMLDisplayXML) acceptent les listes. Supposons que nous voulions la liste des masses atomiques de tous les atomes. Nous allons récupérer en premier la liste de tous les nœuds XML correspondant aux masses atomiques :
set the_nodes to XMLXpath the_root with "ATOM/ATOMIC_WEIGHT"
  --  {«data XMLR000000010471D940», «data XMLR0000000104746810», «data XMLR0000000104726350», etc.}
puis nous allons récupérer les valeurs de ces nœuds XML sous forme de texte avec XMLGetText :
set the_weights to XMLGetText (the_nodes)
  --  {"227", "26.98154", "243", "121.757", etc.}
-- étape 5 : création et suppression d'un élément Retour | Précédent | Suivant
Nous allons maintenant créer un nouvel élément. Supposons que vous ayez découvert un atome inconnu, et que vous l'ayez baptisé Smilium. La chose la plus urgente à faire est de lui trouver un symbole. Construisons la liste des symboles déjà pris :
set the_symbols to XMLGetText (XMLXpath the_root with "ATOM/SYMBOL")
-- {"Ac", "Al", "Am",[...],"Sc", "Se", "Sg", "Si", "Sm", "Sr", "Ta",[...]}
"Sm" étant déjà utilisé, choisissons comme symbole Sl.
Puisque la liste est (à peu près) dans l'ordre alphabétique, une bonne idée serait d'insérer le Smilium après Si (le Silicium).
set {the_si} to XMLXpath the_root with "ATOM[SYMBOL=\"Si\"]"
XMLGetText (XMLChild the_si index 1)
  --  "Silicon"
Maintenant que nous savons où insérer le nouvel élément, définissons ce que nous voulons insérer.
Au minimum nous voudrons définir le nom et le symbole. Construisons ces données "manuellement" :
set the_data to "<ATOM>
<NAME>Smilium</NAME>
<SYMBOL>Sl</SYMBOL>"
set the_smilium to XMLNewSibling the_data after the_si
Aïe. Le script renvoie une erreur ! Effectivement notre nouvel élément était mal défini, le tag ATOM n'était pas fermé.
set the_data to "<ATOM>
<NAME>Smilium</NAME>
<SYMBOL>Sl</SYMBOL>
</ATOM>"
set the_smilium to XMLNewSibling the_data after the_si
  --  «data XMLR00000001032708E0»

Ajoutons maintenant quelques informations supplémentaires.

Un nouvel élément se doit d'être plus gros que tous les autres. Construisons une petite fonction qui calcule la valeur maximale d'un élément arbitraire. A partir du nom de l'élément, XMLGetText renvoie en texte une liste des valeurs. Pour obtenir le maximum de ces valeurs, il nous faut créer la liste des nombres. Les fonctions AppleScript de base ne permettent pas de traduire une liste de textes en une liste de nombres : utilisons les fonctions scientifiques de Smile. En effectuant addlist 0 sur la liste de textes on obtient une liste de nombres. Puis utilisons statlist pour récupérer les statistiques sur cette liste.
on GetMaxValue(the_root, the_element)
    set the_xpath to "ATOM/" & the_element
    set the_nodes to XMLXpath the_root with the_xpath
    set the_values to XMLGetText the_nodes
    set the_numbers to addlist 0 with the_values
    return maximum of (statlist the_numbers)
end GetMaxValue

GetMaxValue(the_root, "ATOMIC_NUMBER")
  --  112.0
GetMaxValue(the_root, "ATOMIC_WEIGHT")
  --  277.0
GetMaxValue(the_root, "ATOMIC_RADIUS")
  --  2.700000047684
Maintenant nous pouvons renseigner quelques informations supplémentaires sur le Smilium :
XMLNewChild "<ATOMIC_NUMBER>144</ATOMIC_NUMBER>" at the_smilium
XMLNewChild "<ATOMIC_WEIGHT>321</ATOMIC_WEIGHT>" at the_smilium
XMLNewChild "<ATOMIC_RADIUS>3.14</ATOMIC_RADIUS>" at the_smilium
... et enfin afficher notre nouvel élément :
XMLDisplayXML the_smilium
  --  Result:
  <ATOM>
    <NAME>Smilium</NAME>
    <SYMBOL>Sl</SYMBOL>
    <ATOMIC_NUMBER>144</ATOMIC_NUMBER>
    <ATOMIC_WEIGHT>321</ATOMIC_WEIGHT>
    <ATOMIC_RADIUS>3.14</ATOMIC_RADIUS>
  </ATOM>"
En guise d'exercice, retirons l'entrée de l'élément Silicium.
XMLRemove the_si
set the_si to 0
Prenez l'habitude de remettre à zéro une variable qui contient un XLRef une fois l'entité en question détruite. En effet, utiliser une référence à un objet qui n'existe plus peut faire crasher Smile.

Nous pouvons maintenant enregistrer le nouveau tableau dans un fichier local (sur le bureau).

set the_path to ((path to desktop) as text) & "future_elements.xml"
XMLSave the_doc in file the_path
set the_file to the_path as alias

-- étape 6 : documents, fichiers et URLs Retour | Précédent | Suivant
Dans les étapes précédentes, nous avons ouvert un URL stocké dans the_URL et Smile nous a retourné un XMLRef que nous avons stocké dans the_doc. Puis nous avons ajouté un élément à the_root (le nœud XML racine de the_doc) et enregistré the_doc dans un fichier local, the_path. Cependant, le document XML enregistré dans the_path n'est pas ouvert, seul the_URL est ouvert. Pour en avoir la confirmation, exécutez la ligne suivante :
XMLDocument the_file
Le script renvoie une erreur : il n'y a pas de XMLRef valide se référant à ce document. La ligne suivante retourne la référence de fichier stockée dans the_doc:
XMLDocument the_URL
  --  «data XMLR0000000100000000»
Il peut être pratique lorsque vous modifiez une base de données de travailler sur une copie locale. Pour faire cela, fermons la connexion à the_URL, et ouvrons à la place la copie locale.
XMLClose the_doc
set the_doc to XMLOpen the_file
  --  «data XMLR0000000200000000»
Vérifions :
XMLURL the_doc
-- alias "Macintosh HD:Users:<login>:Desktop:future_elements.xml"
Nous pouvons maintenant travailler localement. Pour enregistrer les modifications il suffit d'écrire :
XMLSave the_doc
-- étape 7 : affichage dans une page web Retour | Précédent | Suivant

Pour faire de notre document XML une page html (en réalité, xhtml) pour la publier sur Internet, il faut utiliser une feuille de styles (stylesheets, le standard XSLT).

En guise d'exemple simple, créons une liste et affichons un résumé pour chaque élément :
Ac
Actinium, Z=89
Al
Aluminum, Z=13
Am
Americium, Z=95
etc.

Le fichier xsl correspondant est très simple. Pour visualiser le fichier xsl dans une nouvelle fenêtre de votre navigateur, cliquez sur ce lien : elements_xsl.html.

Générons le fichier html sur le bureau et ouvrons-le dans Safari.

Le fichier de feuille de styles correspondant est lui-même un fichier XML, ouvrons-le :

set the_ss_URL to "http://www.satimage.fr/software/samples/elements.xsl"
set the_ss to XMLOpen the_ss_URL
Appliquons maintenant la feuille de styles
set the_html to XMLTransform the_doc with the_ss
the_html est un XMLRef, nous pouvons utiliser XMLSave pour en faire un fichier. Nous aurions également pu utiliser XMLDisplayXML pour générer une représentation en texte de the_html. Affichez-le dans une fenêtre Unicode et enregistrez-le sur votre disque par les moyens usuels.
set the_html_path to ((path to desktop) as text) & "elements.html"
XMLSave the_html in file the_html_path
Voyons maintenant comment le résultat s'affiche.
set the_html_file to the_html_path as alias
tell application "Safari" to open the_html_file
Pour voir le source html du résultat (dans une nouvelle fenêtre de votre navigateur) cliquez sur ce lien : elements_html.html.
Pour voir le résultat dans une page web html (dans une nouvelle fenêtre de votre navigateur) cliquez sur ce lien : elements.html.

-- étape 8 : libérer la mémoire Retour | Précédent | Suivant
Les arbres XML peuvent utiliser de grandes quantités de mémoire. Il est préférable de fermer ceux que vous n'utilisez plus.
XMLClose the_doc
XMLClose the_ss
XMLClose the_html
English version
Copyright ©2008 Paris, Satimage