XmlStruct : Extraire et comparer la structure de
documents xml
https://codes-sources.commentcamarche.net/source/47888
Documentation : XmlStruct.html
Code source : XmlStruct.vbproj.html
Par Patrice Dargenton : patrice.dargenton@free.fr
http://patrice.dargenton.free.fr/CodesSources/index.html
13/09/2008
Ca fait un
bout de temps que je cherche à faire une version française du célèbre Robot de
discussion Alice. Il existe certes des jeux AIML en français, mais je
n'ai jamais réussi à les faire fonctionner. Or depuis Septembre 2007, il existe
une version DotNet d'Alice avec les sources en C#,
j'ai converti le code en VB ici :
http://patrice.dargenton.free.fr/ia/alice/alicechatbot.html
Une nouvelle
tentative est donc possible, et pour la première fois avec les sources
complètes en VB, ce qui devrait permettre d'aller plus loin dans le
diagnostique de la version française. L'idée de base est d'analyser la
structure des documents aiml qui fonctionne
effectivement en anglais, avec l'objectif de vérifier et d'appliquer, le cas
échéant, la structure correcte aux fichiers aiml en
français. Il se trouve qu'il existe un schéma xsd
officiel pour valider les fichiers aiml, mais en
pratique, aucun des jeux testés ne respectent complètement le schéma officiel !
(voir la doc. d'AliceVB).
Une solution
plus pragmatique consiste donc à déduire le schéma selon le dernier jeu AIML
qui fonctionne. Pour cela, il faut fusionner l'ensemble des fichiers aiml afin d'avoir la liste complète des formats rencontré
(un simple copy /b *.aiml Cumul.aiml
suffit, à condition de retirer la balise d'entête et de fin de chaque fichier,
cela fonctionne si l'encodage des fichiers est identique).
En répétant la
manipulation avec les fichiers en français, on obtient cette fois le schéma
utilisé en français. Cependant, la comparaison des schémas Anglais et Français
est à peu près illisible via l'utilitaire WinDiff. D'où l'idée de comparer
plutôt via le DTD
(Document Type Definition), lequel est un schéma
simplifié beaucoup plus lisible. Le seul problème est que le DTD ne permet pas
de gérer l'aspect récursif (hiérarchique) des fichiers aiml.
Cependant, on peut contourner cette limite en renommant avec un numéro les
balises susceptibles d'apparaître à plusieurs niveaux, de façon à les dissocier
et à faire disparaître complètement l'aspect récursif de la structure AIML. Les
fichiers AIML ainsi mis à plat ne fonctionneront plus avec le robot de
discussion, mais on pourra alors extraire la DTD et vérifier, d'une part que
les fichiers transformés respectent bien leur DTD (pour voir si l'extraction
DTD est juste), et ensuite comparer leur DTD plus facilement qu'avec leur
schéma xsd. Je n'ai pas trouvé de logiciel pour
extraire le DTD (sauf peut être TRANG),
alors j'en ai conçu un, mais en ignorant les attributs dans cette première
version.
Voici donc un
ensemble d'utilitaires pour comparer la structure de fichiers xml via WinDiff.
Table des matières
Normaliser
la casse des balises Xml
Extraire
la structure au format DTD
Extraire
la structure simple au format DTD
Technique
pour comparer des documents xml via leur DTD
Version
1.01 du 07/09/2008 : Première version
Il suffit
d'installer les menus contextuels : pour cela lancer simplement XmlStruct, puis
cliquez sur OK pour "Ajouter les menus contextuels".
Ensuite il
suffit d'utiliser les menus qui apparaissent lorsque l'on sélectionne un
fichier Xml avec le bouton droit de la souris dans
l'explorateur de fichiers de Windows. J'ai ajouté aussi la prise en compte des
fichiers aiml comme des fichiers xml,
il est possible d'ajouter facilement dans le code d'autres types de document xml avec une extension différente de xml.
Pour
désinstaller (ou réinstaller XmlStruct en cas de déplacement), relancer
simplement XmlStruct et cliquez sur OK pour "Enlever les menus
contextuels.".
Mode multi-fichier : les messages ne sont affichés qu'une fois
(au maximum, et parfois pas du tout), ce qui permet de lancer autant d'instance
de XmlStruct qu'il y a de fichier à traiter. Par exemple, vous pouvez vérifier la
validité de structure de l'ensemble des fichiers sélectionnés : un fichier
erreur sera généré pour chaque fichier contenant des erreurs, et pas pour les
fichiers respectant leur schéma DTD ou xsd.
Pour comparer
le contenu de deux fichiers ou répertoire, voir l'utilitaire WinDiff (gratuit).
Utiliser ce
menu pour changer la présentation (indentation) des fichiers pour Windows,
notamment en ce qui concerne les sauts de ligne, afin de les adapter à Windows
(par exemple pour leur consultation via le bloc-notes).
Code menu :
Indenter
Notes :
- Ce menu
ne fonctionne pas pour certains encodages (un fichier .bak est donc généré à
chaque fois) ;
- La
correction de la présentation n'est pas très poussée, par exemple elle ne
traite pas les balises à l'intérieur d'un texte, je n'ai pas réussi à faire
mieux en testant les différentes options possibles dans le code.
Utiliser ce
menu pour normaliser la casse des balises en minuscules, afin de pouvoir
vérifier et comparer la structure xml du fichier dans
le cas où il existerait des variations dans la casse : Une version distincte du
fichier avec le suffixe "_Norm" sera générée
(même s'il n'y a pas de différence avec l'original, cependant la présentation
pourra être corrigée aussi).
Code menu :
Normaliser
Utiliser ce
menu pour retirer les attributs dans le fichier xml.
Une version distincte du fichier avec le suffixe "_SansAttr"
sera générée (même s'il n'y a pas de différence avec l'original, cependant la
présentation pourra être corrigée aussi). Cette opération peut être longue,
compter plusieurs minutes pour les fichiers de plusieurs Mo.
Code menu : SupprAttr
Utiliser ce
menu pour extraire la structure au format DTD (les attributs sont ignorés dans
le DTD). Si le fichier ne contient pas d'attribut, alors on peut maintenant le
valider via ce DTD, en ajoutant par exemple la ligne :
<!DOCTYPE aiml
SYSTEM 'aiml_deduit.dtd'>
Code menu :
Xml2DTD
Notes :
- Il ne
doit pas y avoir de commentaire avant la 1ère balise racine (car il n'y a pas
de boucle sur le premier noeud) ;
- Ne pas
indiquer de DTD avant de l'extraire (si on fait plusieurs tentatives), sinon
une version sans DTD sera produite à l'occasion ;
- Les
signes ?, + ou * peuvent être indiqués pour chaque
élément enfant d'une liste :
? = 0 ou 1
élément
+ = Au moins 1
élément
* = 0 ou
plusieurs éléments
Ces signes
peuvent être appliqués à un élément enfant ou bien à une liste d'éléments
enfants :
- Un et
un seul élément :
<!ELEMENT element-name
(child-name)>
- Au
moins 1 élément :
<!ELEMENT element-name
(child-name+)>
- 0 ou
plus d'un élément :
<!ELEMENT element-name
(child-name*)>
- 0 ou 1
élément :
<!ELEMENT element-name
(child-name?)>
- Plusieurs
types d'enfant (ou) :
<!ELEMENT element-name
(child1, child2, ...)>
- Contenu
mixte : 0 ou plusieurs occurrences de child1 ou child2 :
<!ELEMENT element-name
(child1, child2)*>
- Imbrication :
<!ELEMENT note (to, from,
header, (message | body))>
- Mixage
des signes (possible ?) :
<!ELEMENT element-name
(child1+, child2*)>
J'avais
commencé à implémenter ce niveau de détail, mais je suis arrivé à une erreur de
validation comme quoi on ne pouvait mélanger les signes + et * au sein d'une
liste, du coup j'ai simplement indiqué le signe * pour l'ensemble des éléments
de la liste, ce qui fonctionne toujours, mais est moins précis (on peut
réactiver le code en commentaire, mais il faut trouver exactement ce qui ne
fonctionne pas, en particulier voir si c'est une limite de la spécification ou
bien de l'implémentation du validateur dans Visual
Studio ou Internet Explorer).
Utiliser ce
menu pour extraire la structure au format DTD simple (les attributs sont
ignorés dans le DTD), c'est-à-dire en évitant de numéroter les balises qui
apparaissent de façon récursive (ou hiérarchique). Ce menu ne sert que pour la
comparaison de structure, car le DTD ne permet plus de valider le document dans
ce cas.
Code menu :
Xml2DTDComp
Le fichier
doit référencer un DTD pour pouvoir être validé, il doit apparaître sur la
seconde ligne après l'encodage, par exemple :
<!DOCTYPE aiml
SYSTEM 'aiml_deduit.dtd'>
Code menu : VerifierDTD
Le fichier
doit référencer un schéma xsd pour pouvoir être
validé, il doit apparaître sur la seconde ligne après l'encodage, par
exemple :
<aiml xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
xsi:noNamespaceSchemaLocation="aiml_deduit.xsd">
Code menu : VerifierSchema
Une fois le
schéma précisé, l'éventuelle liste des erreurs produites (dans un fichier
texte) est identique à celle produite par Visual
Studio.
Notes :
- Pour
extraire (déduire) un schéma depuis un fichier xml
existant, voir Xml2Schema ;
- Le
schéma xsd sur le web ne fonctionne pas toujours, on
obtient parfois l'avertissement : "Le délai d'attente de l'opération a
expiré". Une solution est de remplacer les références par une référence
locale, en téléchargeant le schéma xsd au préalable,
mais ce n'est pas toujours possible, par exemple s'il y a un préfixe html dans
les espaces de nommage.
Voici la
technique pour comparer des documents xml via leur
DTD avec XmlStruct. Comme XmlStruct extrait le DTD en ignorant les attributs
dans cette première version du logiciel, si on veut ensuite valider le document
selon le DTD, il faut le tester sur une version du document sans attribut,
voici donc la procédure complète avec un exemple :
1°) Prendre un
fichier xml sans schéma ni dtd,
par exemple Music.aiml
(Tester au préalable si le fichier est un
fichier xml valide, par exemple en l'ouvrant dans Visual Studio ; on peut vérifier aussi si le fichier est
valide selon un schéma existant ou déduit, pour s'assurer que l'on va comparer
les bonnes versions de fichier).
2°) Enlever
les attributs (cela peut être long, plusieurs minutes pour les fichiers de
plusieurs Mo) :
Music.xml -> Music_SansAttr.xml
3°) Normaliser
la casse des balises :
Music_SansAttr.xml
-> Music_SansAttr_Norm.xml
4°) Extraire
la structure DTD : il indique qu'une version plate a été générée (cf. doublon
<set>) :
Music_SansAttr_Norm.xml
-> Music_SansAttr_Norm_Dedoub.xml
5°) Extraire
la structure DTD : Music_SansAttr_Norm_Dedoub.dtd
6°) Ajouter le
DTD dans le document, en ligne n°2, juste après la ligne 1 : <?xml ... ?> :
<!DOCTYPE aiml
SYSTEM 'Music_SansAttr_Norm_Dedoub.dtd'>
7°) Vérifier
le fichier selon son DTD : Music_SansAttr_Norm_Dedoub.xml
: valide !
8°) Enlever le
DTD et refaire le DTD sans dédoublonner cette fois
les noeuds (DTD simple)
afin de
faciliter la comparaison de structure
Fichier original (Music.aiml) :
<aiml>
<category><pattern>BEETHOVEN *</pattern><template>It's amazing that he composed music while deaf.
<think><set name="he"><set name="topic">BEETHOVEN</set></set></think>
</template></category>
<category><pattern>WHAT WAS THE * BEETHOVEN *</pattern><template>Fidelio.</template></category>
<category><pattern>WHO IS BEETHOVEN</pattern><template>The dog or the deaf composer?</template></category>
<category><pattern>WHO IS LUDWIG BEETHOVEN</pattern><template><srai>WHO IS BEETHOVEN </srai></template></category>
</aiml>
Suppression des attributs :
<aiml>
<category>
<pattern>BEETHOVEN *</pattern>
<template>It's amazing that he composed music while deaf.
<think><set><set>BEETHOVEN</set></set></think></template>
</category>
<category>
<pattern>WHAT WAS THE * BEETHOVEN *</pattern>
<template>Fidelio.</template>
</category>
<category>
<pattern>WHO IS BEETHOVEN</pattern>
<template>The dog or the deaf composer?</template>
</category>
<category>
<pattern>WHO IS LUDWIG BEETHOVEN</pattern>
<template>
<srai>WHO IS BEETHOVEN </srai>
</template>
</category>
</aiml>
La balise <set> est présente à plusieurs niveaux, une mise à plat est requise :
aiml\category\template\think\set\set\ <> aiml\category\template\think\set\ -> set__1
<aiml>
<category>
<pattern>BEETHOVEN *</pattern>
<template>It's amazing that he composed music while deaf.
<think><set><set__1>BEETHOVEN</set__1></set></think></template>
</category>
...
</aiml>
Extraction du DTD :
<!ELEMENT aiml
(
category
)*>
<!ELEMENT category
(
pattern
|
template
)*>
<!ELEMENT pattern
(
#PCDATA )>
<!ELEMENT template
(
#PCDATA |
srai
|
think
)*>
<!ELEMENT srai
(
#PCDATA )>
<!ELEMENT think
(
set
)>
<!ELEMENT set
(
set__1
)>
<!ELEMENT set__1
(
#PCDATA )>
Version non dédoublonnée (pour comparaison seulement, ne fonctionne pas à cause du doublon set) :
<!ELEMENT aiml
(
category
)*>
<!ELEMENT category
(
pattern
|
template
)*>
<!ELEMENT pattern
(
#PCDATA )>
<!ELEMENT template
(
#PCDATA |
srai
|
think
)*>
<!ELEMENT srai
(
#PCDATA )>
<!ELEMENT think
(
set
)>
<!ELEMENT set
(
set
)>
<!ELEMENT set
(
#PCDATA )> (L'élément global 'set' a déjà été déclaré.)
Pour que le
schéma extrait soit pertinent, il faut que le document source dont il est
extrait soit représentatif des données. C'est d'autant plus vrai en ce qui
concerne les balises récursives (ou hiérarchiques) : il sera plus difficile
d'obtenir un document capable de représenter toutes les combinaisons possibles,
de sorte qu'ensuite, la vérification d'un autre document selon le schéma déduit
provoquera des erreurs qui ne seront peut être que des nouveaux cas possibles
qui n'avaient pas été prévus dans le document de référence. Il faudra donc
faire la part des erreurs dues au manque de représentativité, des vraies
erreurs de structure.
- AliceVB : Interface pour l'AIMLBot
: Robot de discussion de type Alice
- Xml2Schema : XML to Schema
Tool for Visual Basic 2008
http://msdn2.microsoft.com/vbasic/bb840042.aspx
- DTD :
http://fr.wikipedia.org/wiki/Document_Type_Definition
http://en.wikipedia.org/wiki/Document_Type_Definition
http://zvon.developpez.com/tutoriels/dtd
- Comparaison
DTD, XML Schema et autres :
http://en.wikipedia.org/wiki/XML_Schema_Language_Comparison
- Schematron : + puissant que schéma :
http://xml.ascc.net/schematron/
Because
it uses paths rather than grammars,
it can be
used to assert many constraints that cannot be
expressed by DTDs or XML Schemas.
- RelaxNG : http://www.relaxng.org/
Forme
compact : http://www.relaxng.org/compact-20021121.html
Intro
à RelaxNG : http://www-106.ibm.com/developerworks/library/x-matters25.html
Validateur
JAXP pour RelaxNG : http://www.apache.org/~andyc/neko/doc/relaxng/index.html
Trang : Multi-format schema converter based on RELAX NG (dont DTD et XML Schema)
www.thaiopensource.com/relaxng/trang.html
Déduire un RelaxNG
à partir d'une instance XML : http://examplotron.org/