XML en Prolog
Notes sur la bibliothèque SWI-Prolog SGML/XML parser
Transsformation de documents XML (fichiers) en termes Prolog.
- fichier -> terme (loading)
- terme -> fichier (writing)
- vérification qu'un terme donné est bien dans la forme requise (checking)
- Loading Structured Documents
- Principe
- Précisions
- Liste
- Rôle de la DTD
- En l'absence de DTD
- Réglage de l'imprimeur
- Exercice
- Writing documents
- Type checking
-
library(sgml)
Prédicats load_structure
et load_xml_file
-
Chaque
element
XML est représenté par un terme Prolog
ainsi construit :
- le foncteur est
element
, ternaire
- arg. 1 = le nom de la balise, en tant qu'atome
- arg. 2 = la liste des attributs
[attr1=val1,
attr2=val2,...]
- les noms d'attributs et les valeurs représentés par
des
atomes
- les namespaces traités comme des attributs
ordinaires de
nom
xmlns
- arg. 3 = la liste des fils,
- y compris les nœuds texte sous forme d'atomes
Exemple (artificiel mais complet !) :
XML :
<Ex:Balise xmlns:Ex="http://www.epita.com"
but="illustration" modalité="sans problème">
sans autre
<Ex:suite-1> cela reste à voir
</Ex:suite-1>
forme de
<Ex:suite2 />
procès
</Ex:Balise>
Prolog : element(
'Ex:Balise',
['xmlns:Ex'='http://www.epita.com', but=illustration, modalité='sans
problème'],
['sans autre',
element('Ex:suite-1', [], ['cela reste à voir']),
'forme de',
element('Ex:suite2', [], []),
procès
])
On note la présence de simple quotes autour des atomes dès que
- ils commencent par une majuscule (réservé aux variables
logiques)
- ou qu'ils contiennent un caractère non-alphanumérique,
- les lettres accentuées ne posent point de problème,
Prolog travaille en UTF-8.
-
-
Attention ! Le fichier tout entier est traduit par
une liste
contenant les instr. de traitement et l'élément racine !
-
En l'absence de DTD,
load_xml_file(NomFich,
Terme)
conserve comme
significatifs
tous les blancs, les tabs et
les sauts de ligne (normal vu les principes d'XML).
Exemple, avec un fichier XML reproduisant exactement les indentations
de l'exemple artificiel ci-dessus
[fichier Ex.xml]
?- use_module(library(sgml)).
?- load_xml_file('Ex.xml', Terme).
Terme = [element('Ex:Balise', ['xmlns:Ex'='http://www.epita.com',
but=illustration, modalité='sans problème'], ['\n\tsans autre\n\t',
element('Ex:suite-1', [], [' cela reste à voir ']), '\n\tforme de\n\t',
element('Ex:suite2', [], []), '\n\tprocès\n'])].
Mais en présence d'une DTD le même prédicat l'utilise pour ne conserver
que la structure spécifiée,
en rectifiant au passage des erreurs mineures.
Exemple avec les fichiers Voiture.xml
et Voiture.dtd
:
?- load_xml_file('Voiture.xml', Terme).
Warning: SGML2PL(xml): Voiture.xml:8: Ignored end-tag for "Cylindres"
which is not open
Terme = [element('Voiture', [marque='Renault', modèle='Safrane'],
[element('Carosserie', [couleur=rouge], [element('Capot', [], ['Un peu
cabossé'])]), element('Moteur', [], [element('Cylindres', [], []),
element('Allumage', [], ['Défectueux'])]), element('Transmission',
[type=automatique, nb_vitesses='5'], [element('Boîte', [], []),
element('TrainAV', [], []), element(..., ..., ...)])])].
-
Nous travaillerons sur des fichiers XML dépourvus de DTD (provenant du
site Jodhpur),
le contrôle structurel de ces fichers étant confié à
des schémas XML.
Pour éliminer les blancs, tabs et sauts de ligne "parasites", nous
utiliserons de préférence
load_structure(NomFich, Terme, [dialect(xml),space(remove)]).
Exemple avec le fichier-source qrd.xml
:
?- load_structure('qrd.xml', XmlSource,
[dialect(xml),space(remove)]).
XmlSource = [element('Prog', [], [element('Variables', [],
[element('Var', [name=a], []), element('Var', [name=b], []),
element('Var', [... = ...], []), element('Var', [...], []),
element(..., ..., ...)|...]), element('Main', [], [element('Read', [],
[element('Var', [...], [])]), element('Read', [], [element(..., ...,
...)]), element('Assignment', [], [...|...]), element(..., ...,
...)|...])])].
-
Pour ne pas nous encombrer avec un terme de grande
taille,
l'imprimeur de Prolog pratique l'ellipse ("...") des termes de
profondeur dépassant 5,
ce qui nous empêche de lire notre terme au complet.
Pour l'avoir tout entier, il convient de modifier les réglages de
l'imprimeur, en demandant :
set_prolog_flag(toplevel_print_options,[quoted(true),
portray(true), max_depth(0), attributes(portray)]).
?-
set_prolog_flag(toplevel_print_options,[quoted(true), portray(true),
max_depth(0), attributes(portray)]).
true.
?- load_structure('qrd.xml', XmlSource,
[dialect(xml),space(remove)]).
XmlSource=[element('Prog',[],[element('Variables',[],[element('Var',[name=a],[]),element('Var',[name=b],[]),element('Var',[name=t],[]),element('Var',[name=q],[]),element('Var',[name=r],[]),element('Var',[name=d],[])]),element('Main',[],[element('Read',[],[element('Var',[name=a],[])]),element('Read',[],[element('Var',[name=b],[])]),element('Assignment',[],[element('Var',[name=t],[]),element('VarExp',[],[element('Var',[name=b],[])])]),element('Loop',[],[element('Test',[op=
<=],[element('Bin',[op=
(-)],[element('VarExp',[],[element('Var',[name=t],[])]),element('VarExp',[],[element('Var',[name=a],[])])]),element('Cst',[val='0'],[])]),element('Assignment',[],[element('Var',[name=t],[]),element('Bin',[op=
(*)],[element('Cst',[val='2'],[]),element('VarExp',[],[element('Var',[name=t],[])])])])]),element('Assignment',[],[element('Var',[name=q],[]),element('Cst',[val='0'],[])]),element('Assignment',[],[element('Var',[name=r],[]),element('VarExp',[],[element('Var',[name=a],[])])]),element('Assignment',[],[element('Var',[name=d],[]),element('VarExp',[],[element('Var',[name=t],[])])]),element('Loop',[],[element('Test',[op=
(>)],[element('Cst',[val='0'],[]),element('Bin',[op=
(-)],[element('VarExp',[],[element('Var',[name=b],[])]),element('VarExp',[],[element('Var',[name=d],[])])])]),element('Sequence',[],[element('Assignment',[],[element('Var',[name=d],[]),element('Bin',[op=
(/)],[element('VarExp',[],[element('Var',[name=d],[])]),element('Cst',[val='2'],[])])]),element('Conditional',[],[element('Test',[op=
(>=)],[element('Bin',[op=
(-)],[element('VarExp',[],[element('Var',[name=r],[])]),element('VarExp',[],[element('Var',[name=d],[])])]),element('Cst',[val='0'],[])]),element('Sequence',[],[element('Assignment',[],[element('Var',[name=r],[]),element('Bin',[op=
(-)],[element('VarExp',[],[element('Var',[name=r],[])]),element('VarExp',[],[element('Var',[name=d],[])])])]),element('Assignment',[],[element('Var',[name=q],[]),element('Bin',[op=
(+)],[element('Bin',[op=
(*)],[element('Cst',[val='2'],[]),element('VarExp',[],[element('Var',[name=q],[])])]),element('Cst',[val='1'],[])])])]),element('Assignment',[],[element('Var',[name=q],[]),element('Bin',[op=
(*)],[element('Cst',[val='2'],[]),element('VarExp',[],[element('Var',[name=q],[])])])])])])]),element('Write',[],[element('VarExp',[],[element('Var',[name=q],[])])]),element('Space',[],[]),element('Write',[],[element('VarExp',[],[element('Var',[name=r],[])])]),element('Newline',[],[])])])].
-
Nous avons commencé en cours l'écriture et le test d'un vérificateur
structurel pour les termes issus de fichiers XML représentant des
programmes en syntaxe abstraite de la même farine que l'exemple
précédent.
fichier checkProg.pl
Mener cette écriture à son terme.
-
library(sgml_write)
xml_write(+Stream, +Term, +Options)
Write the XML header with encoding information and the content
of the
document as represented by Term
to Stream
.
This predicate deals with
XML with or without namespaces. If namespace identifiers are not
provided they are generated.
Ex. avec liste d'options vide
:- use_module(library(sgml_write)).
ecrire_terme(NomFich, T) :- open(NomFich, write, Str),
xml_write(Str, T, []), close(Str).
-
library(sgml)
xml_is_dom(@Term)
True if Term
is an SGML/XML term as produced by
one of the above
predicates and acceptable by xml_write/3
and friends.