L’objet de cette page Web est une approche pragmatique et progressive de eXtensible Markup Language -XML- pour gérer le « contenu » (i.e., les données) d'un système Product Lifecycle Management -PLM- ☛
Les technologies afférentes à XML suivantes sont étudiées : Document Type Definition -DTD-, XML Schema Definition -XSD-, XQuery, eXtensible Style Language Transformations -XSLT-, XML Linking language -XLink-, XPointer et XInclude.
XPath est quant à elle une technologie XML partagée.
![]()
- Machine virtuelle Java (ver. 17 ou plus) ☛
- Apache NetBeans pour vérifier (syntaxe XML), valider (conformité DTD et XSD) et transformer (XSLT)
- Librairie Java SAXON pour XQuery ☛
- Version d'essai d'Enterprise Architect pour la partie « méthodologie » ☛
- xmllint ☛
Windows
choco -y upgrade chocolatey (admin.) choco -y install xsltproc (admin.) xmllint --version
macOS
brew update brew upgrade brew install xmlstarlet xmllint --version
Il existe de nombreux outils permettant de « parser » du « code » XML. Le logiciel Apache NetBeans dispose d'un ensemble de fonctionnalités minimal pour construire, contrôler la syntaxe et surtout valider du contenu XML en regard d'un « modèle » (DTD ou XSD). Apache NetBeans permet également l'exécution de programmes XSLT.
A la découverte de Apache NetBeans pour XML…
L'ancêtre de XML est Standard Generalized Markup Language -SGML-, norme ISO alors que XML est une norme W3C. A ce titre, XML est lu nativement par les browser
Chrome,
Firefox…
Malgré une parenté notoire, HyperText Markup Language -HTML- n'a jamais vraiment eu une filiation parfaite avec XML étant attendu que HTML soit une instanciation de XML. HTML même dans sa version 5 reste permissif (comportement hétérogène des browser
Chrome,
Firefox…) alors que XML ne l'est pas.
eXtensible HyperText Markup Language -XHTML- pensé dans l'esprit XML n'incorpore pas les techno. novatrices de HTML 5 d'où le de facto abandon de ce premier…
Exemple (saut de ligne HTML)
<!-- Saut de ligne HTML : --> <br>
Exemple (saut de ligne XHTML/XML)
<!-- Saut de ligne XHTML/XML : --> <br/>
Exemple (saut de ligne XHTML/XML, variante)
<!-- Saut de ligne XHTML/XML : --> <br> </br>
Les balises XML bornent les données à encoder. L'utilisation de caractères spéciaux (escaped characters: <, >, &… ☛) pour contrôler l'encodage fait appel des stratégies dédiées d'encodage.
<!-- Age Julie < âge Julien & âge Julien > âge Julie --> <Donnees_problematiques>Age Julie < âge Julien & âge Julien > âge Julie</Donnees_problematiques>
Il est possible d'encoder des caractères HTML moins communs voire des données multimédia comme des sons, images, vidéos….
<!-- 🐉 --> <Dragon>🐉</Dragon>
<Documentation id="FB" name="FB" version="1" notes="FB" infoURI="BarbierDarnal.com"/> <Icon> <Image type="bitmap" xmlns:dt="urn:schemas-microsoft-com:datatypes" dt:dt="bin.base64">Qk12FAEAAAAAADYAAAAoAAAAigAAAKoAAAABABgAAAAAAEAUAQAlFgAAJRYA AAAAAAAAAAAALx4hIxgaGxYXGhgYGhUWGBITGRMUGxYXGRQVGBMUFxITFhES … </Image> </Icon>
XML autorise du « contenu mixte » où balises s'entrecroisent avec données ☛
<Game_of_Thrones>Les trois <Dragon>🐉</Dragon> sont le moyen du pouvoir</Game_of_Thrones>
![]()
1ère approche (attributs) PLM_internal_DTD_1.xml
![]()
2e approche (éléments) PLM_external_DTD.xml
![]()
![]()
1ère approche (par redondance)
2e approche (par référence des éléments)
3e approche (par référence des valeurs des attributs)
Exercice
A l'aide du logiciel Apache NetBeans, compléter le fichier PLM_internal_DTD_1.xml
avec les liens de nomenclature entre
CH005
etP004
ainsi queCH005
etES000
. Compléter avec le poste de charge600-930
☛ et la gamme de fabrication deCD100
☛Exercice
A l'aide du logiciel Apache NetBeans, compléter le fichier PLM_external_DTD.xml
avec les liens de nomenclature entre
CH005
etP004
ainsi queCH005
etES000
. Compléter avec le poste de charge600-930
☛ et la gamme de fabrication deCD100
☛
Une DTD décrit un format auquel doit obéir un document XML.
- Tutoriel DTD (w3schools) ☛
- Tutoriel DTD (Quackit) ☛
- Quelques exemples et astuces ☛
- Analogie DTD et SQL ☛
DTD externalisée dans un fichier PLM.dtd
![]()
La DTD a été générée dans Apache NetBeans à partir du fichier source XML PLM_external_DTD.xml
![]()
Exercice
A l'aide du logiciel Apache NetBeans, procéder à la validation du fichier source XML PLM_external_DTD.xml
![]()
Référence à la DTD de validation
1ère approche (focus sur les attributs)
2e approche (focus sur les éléments)
Exercice
A l'aide du logiciel Apache NetBeans, modifier la partie DTD du fichier PLM_internal_DTD_1.xml
en utilisant
IDREFS
plutôt queIDREF
pour la baliseLien_de_nomenclature
. Quel est le risque encouru ? Réponse : besoin d'une convention sur l'ordre des attributs…Exemple d'utilisation de
IDREFS
Exercice
A l'aide du logiciel Apache NetBeans, modifier la partie DTD du fichier PLM_internal_DTD_1.xml
de manière à intégrer la description du poste de charge
600-930
☛ et la gamme de fabrication deCD100
☛Note
La correspondance
IDREF
/ID
est limitée car seul un attribut peut être de typeID
. Ainsi, l'intégrité référentielle deOperation
versPoste de charge
est empêchée car seulnumero_section
est de typeID
dansPoste de charge
. L'utilisation deIDREFS
peut être un palliatif.Exercice
A l'aide du logiciel Apache NetBeans, modifier la partie DTD du fichier PLM_internal_DTD_2.xml
de manière à intégrer la description du poste de charge
600-930
☛ et la gamme de fabrication deCD100
☛
XSD produit un format auquel doit obéir un document XML. XSD est plus puissant que DTD par le typage, la possibilité d'expression de tranformation, le fait que XSD soit écrit en XML lui-même, etc.
Exemple
Confinement.xsd
(modèle)<?xml version="1.0"?> <xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> <xs:element name="Confinement" type="xs:date"/> </xs:schema>
Exemple
Confinement.xml
(instanciation)<?xml version="1.0" encoding="UTF-8"?> <Confinement xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Confinement.xsd"> 2020-03-17 </Confinement>
Exercice
A l'aide du logiciel Apache NetBeans, reconsidérer
Confinement.xml
en représentant les deux confinements français dans le cadre d'une balise racine<Covid_19>…</Covid_19>
. Etendre en suivant le fichierConfinement.xsd
dans cet esprit…Solution
Covid_19.xsd
(modèle)<?xml version="1.0"?> <xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> <xs:element name="Covid_19"> <xs:complexType> <xs:sequence> <xs:element name="Confinement" type="xs:date" minOccurs="2" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>
Solution
Covid_19.xml
(instanciation)<?xml version="1.0" encoding="UTF-8"?> <Covid_19 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Covid_19.xsd"> <Confinement>2020-03-17</Confinement> <Confinement>2020-10-30</Confinement> </Covid_19>
Un exemple de XSD pour l'Echange de Données Informatisé -EDI- avec EDF ☛
Exercice
A l'aide du logiciel Apache NetBeans, opérer la validation du fichier Debut_Fin.bpmn
au regard de la XSD BPMN20.xsd
xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL https://www.omg.org/spec/BPMN/20100501/BPMN20.xsd"
XSD autorise la gestion des contraintes d'intégrité référentielle de façon plus poussée que DTD.
1ère approche (focus sur les attributs) PLM_1.xsd
PLM_with_XSD_1_.xml
![]()
<?xml version="1.0"?> <!-- Espace de nom 'xs' doit être utilisé dans la déf. du schéma : --> <xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> <!-- Type déporté pour élément 'Lien_de_nomenclature' : --> <xs:complexType name="Type_lien_de_nomenclature"> <!-- Note that attributes have no order : --> <!-- DTD-like : --> <!-- <xs:attribute name="compose" type="xs:IDREF" use="required"/> --> <!-- <xs:attribute name="composant" type="xs:IDREF" use="required"/> --> <xs:attribute name="compose" type="xs:string" use="required"/> <xs:attribute name="composant" type="xs:string" use="required"/> <!-- Attention, certaines quantités de composition sont décimales ! => "xs:decimal" : --> <xs:attribute name="quantite_de_composition" type="xs:decimal" use="required"/> </xs:complexType> <xs:element name="PLM"> <xs:complexType> <!-- 'xs:all' si pas d'ordre --> <xs:sequence> <!-- Au moins 1 voire plusieurs (1-N) '<Article ... />' ('minOccurs="1"' par défaut) : --> <xs:element name="Article" minOccurs="1" maxOccurs="unbounded"> <!-- Type *NON* déporté : --> <xs:complexType> <!-- DTD-like ('xs:ID' signifie "primary key") : --> <!-- <xs:attribute name="reference" type="xs:ID" use="required"/> --> <xs:attribute name="reference" type="xs:string" use="required"/> <!-- 'default' => 'use="required"' : --> <xs:attribute name="designation" type="xs:string" default="désignation non définie"/> <xs:attribute name="type_fabrication_achat" type="xs:string" use="required"/> <xs:attribute name="unite_achat_stock" type="xs:string" use="required"/> <xs:attribute name="delai_en_semaine" use="required"> <xs:simpleType> <!-- Attention, nécessaire pour encapsuler une restriction --> <!-- "xs:positiveInteger" => "strictement positif", i.e., "> 0" : --> <xs:restriction base="xs:positiveInteger"> <xs:minInclusive value="1"/> <xs:maxInclusive value="6"/> </xs:restriction> </xs:simpleType> </xs:attribute> <!-- "optionel" par défaut : --> <xs:attribute name="prix_standard" type="xs:decimal"/> <xs:attribute name="lot_de_reapprovisionnement" type="xs:positiveInteger"/> <xs:attribute name="stock_mini" type="xs:positiveInteger"/> <xs:attribute name="stock_maxi" type="xs:positiveInteger"/> <xs:attribute name="pourcentage_de_perte" type="xs:unsignedLong"/> <xs:attribute name="inventaire" type="xs:positiveInteger"/> <xs:attribute name="PF_ou_MP_ou_Piece_ou_SE" use="required"> <xs:simpleType> <!-- 'xs:token' data type also contains characters, but the XML processor will remove line feeds, etc. : --> <xs:restriction base="xs:token"> <xs:enumeration value="PF"/> <xs:enumeration value="MP"/> <xs:enumeration value="Pi"/> <xs:enumeration value="SE"/> </xs:restriction> </xs:simpleType> </xs:attribute> </xs:complexType> <!-- Article --> </xs:element> <!-- Article --> <xs:element name="Lien_de_nomenclature" type="Type_lien_de_nomenclature" maxOccurs="unbounded"/> <xs:element name="Poste_de_charge" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> <!-- Eléments de PLM --> <!-- Il semblerait que les attributs de 'PLM' doivent être décrits *APRèS* ses éléments : --> <xs:attribute name="author" type="xs:string" fixed="Franck Barbier"/> <xs:attribute name="URL" type="xs:anyURI" fixed="https://franckbarbier.com/Enterprise_Architect/PLM/PLM.html"/> </xs:complexType> <!-- PLM --> <!-- Contraintes d'intégrité référentielle --> <xs:key name="Article_pk"> <!-- Chemin relatif de 'Article' dans 'PLM' : --> <xs:selector xpath="Article"/> <!-- "@" sélectionne un attribut : --> <xs:field xpath="@reference"/> </xs:key> <xs:unique name="Article_unique"> <!-- Chemin relatif de 'Article' dans 'PLM' : --> <xs:selector xpath="./Article"/> <xs:field xpath="@designation"/> </xs:unique> <xs:key name="Lien_de_nomenclature_pk"> <xs:selector xpath="Lien_de_nomenclature"/> <!-- Clef composée non supportée par DTD : --> <xs:field xpath="@compose"/> <xs:field xpath="@composant"/> </xs:key> <xs:keyref name="Lien_de_nomenclature_fk_1" refer="Article_pk"> <!--https://www.tutorialspoint.com/xpath/xpath_expression.htm--> <xs:selector xpath="./Lien_de_nomenclature"/> <xs:field xpath="@compose"/> </xs:keyref> <xs:keyref name="Lien_de_nomenclature_fk_2" refer="Article_pk"> <!--https://www.tutorialspoint.com/xpath/xpath_expression.htm--> <xs:selector xpath="./Lien_de_nomenclature"/> <xs:field xpath="@composant"/> </xs:keyref> <!-- Fin des contraintes d'intégrité référentielle --> </xs:element> <!-- PLM --> </xs:schema>
Exercice
Opérer la validation dans Apache NetBeans
Exercice
A l'aide du logiciel Apache NetBeans, étendre le fichier PLM_1.xsd
de manière à pouvoir ensuite décrire le poste de charge
600-930
☛ et la gamme de fabrication deCD100
☛ dans le fichier PLM_with_XSD_1_.xml![]()
2e approche (focus sur les éléments) PLM_2.xsd
PLM_with_XSD_2.xml
![]()
<?xml version="1.0"?> <!-- Espace de nom 'xsd' doit être utilisé dans la déf. du schéma ! --> <!-- Default name space: 'xmlns:BDi="https://barbierdarnal.com"' --> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="https://barbierdarnal.com" xmlns:BDi="https://barbierdarnal.com" version="1.0"> <!-- Type déporté pour élément 'Article' : --> <xsd:complexType name="Type_article"> <xsd:sequence> <xsd:element name="designation" type="xsd:string" default="désignation non définie"/> <xsd:element name="type_fabrication_achat" type="xsd:string"/> <xsd:element name="unite_achat_stock" type="xsd:string"/> <xsd:element name="delai_en_semaine"> <xsd:simpleType> <xsd:restriction base="xsd:positiveInteger"> <xsd:minInclusive value="1"/> <xsd:maxInclusive value="6"/> </xsd:restriction> </xsd:simpleType> </xsd:element> <!-- "optionel" ('maxOccurs="1"' par défaut) : --> <xsd:element name="prix_standard" type="xsd:decimal" minOccurs="0"/> <xsd:element name="lot_de_reapprovisionnement" type="xsd:positiveInteger" minOccurs="0"/> <xsd:element name="stock_mini" type="xsd:positiveInteger" minOccurs="0"/> <xsd:element name="stock_maxi" type="xsd:positiveInteger" minOccurs="0"/> <xsd:element name="pourcentage_de_perte" type="xsd:unsignedLong" minOccurs="0"/> <xsd:element name="inventaire" type="xsd:positiveInteger" minOccurs="0"/> <xsd:element name="PF_ou_MP_ou_Piece_ou_SE"> <xsd:complexType> <xsd:choice> <xsd:element name="PF" type="xsd:string"/> <xsd:element name="MP" type="xsd:string"/> <xsd:element name="Pi" type="xsd:string"/> <xsd:element name="SE" type="xsd:string"/> </xsd:choice> </xsd:complexType> </xsd:element> </xsd:sequence> <xsd:attribute name="reference" type="xsd:string" use="required"/> <xsd:attribute name="author" default="Franck Barbier" type="xsd:string"/> </xsd:complexType> <!-- Type déporté pour élément 'Lien_de_nomenclature' : --> <xsd:complexType name="Type_lien_de_nomenclature"> <xsd:sequence> <xsd:element name="compose" type="xsd:string"/> <xsd:element name="composant" type="xsd:string"/> <xsd:element name="quantite_de_composition" type="xsd:decimal"/> </xsd:sequence> </xsd:complexType> <xsd:element name="PLM"> <xsd:complexType> <xsd:sequence> <xsd:element name="Article" type="BDi:Type_article" maxOccurs="unbounded"/> <xsd:element name="Lien_de_nomenclature" type="BDi:Type_lien_de_nomenclature" maxOccurs="unbounded"/> </xsd:sequence> <xsd:attribute name="author" type="xsd:string" fixed="Franck Barbier"/> <xsd:attribute name="URL" type="xsd:anyURI" fixed="https://franckbarbier.com/Enterprise_Architect/PLM/PLM.html"/> <xsd:attribute name="version" type="xsd:string" fixed="1.0"/> </xsd:complexType> <!-- Contraintes d'intégrité référentielle --> <xsd:key name="Article_pk"> <xsd:selector xpath="BDi:Article"/> <!-- Le champ est relatif dans le scope, i.e., attribut de 'BDi:Article' : --> <xsd:field xpath="@reference"/> </xsd:key> <xsd:unique name="Article_unique"> <xsd:selector xpath="./BDi:Article"/> <xsd:field xpath="BDi:designation"/> </xsd:unique> <xsd:key name="Lien_de_nomenclature_pk"> <xsd:selector xpath="BDi:Lien_de_nomenclature"/> <xsd:field xpath="BDi:compose"/> <xsd:field xpath="BDi:composant"/> </xsd:key> <xsd:keyref name="Lien_de_nomenclature_fk_1" refer="BDi:Article_pk"> <xsd:selector xpath="./BDi:Lien_de_nomenclature"/> <xsd:field xpath="BDi:compose"/> </xsd:keyref> <xsd:keyref name="Lien_de_nomenclature_fk_2" refer="BDi:Article_pk"> <xsd:selector xpath="./BDi:Lien_de_nomenclature"/> <xsd:field xpath="BDi:composant"/> </xsd:keyref> <!-- Fin des contraintes d'intégrité référentielle --> </xsd:element> </xsd:schema>
Exercice
Opérer la validation dans Apache NetBeans
Exercice
A l'aide du logiciel Apache NetBeans, étendre le fichier PLM_2.xsd
de manière à pouvoir ensuite décrire le poste de charge
600-930
☛ et la gamme de fabrication deCD100
☛ dans le fichier PLM_with_XSD_2.xml![]()
Solution Exercice_PLM.xsd
Exercice_PLM.xml
![]()
Exercice
A l'aide du logiciel Apache NetBeans, revoir le fichier PLM_2.xsd
en créant le type
MP
à partir du type (pré-existant)Article
: reconsidérer l'élémentPF_ou_MP_ou_Piece_ou_SE
et utilser la balisecomplexContent
. Que peut-on faire alors de l'élémentpourcentage_de_perte
?Exercice
Soit le fichier de données de détenus et de décisions prises à leur égard (Condamnation-1, Réduction de peine-2, Libération définitive-3). Si on enlève les commentaires des lignes 18 à 23, on veut que la validation échoue, à savoir « une décision de même type (1, 2 ou 3) ne peut pas être prise pour le même détenu le même jour ». Modifier le fichier
Prison.xsd
en conséquence…<?xml version="1.0"?> <Prison xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Prison.xsd"> <Detenu> <n_ecrou>111111</n_ecrou> <prenom>Belzébuth</prenom> </Detenu> <Detenu> <n_ecrou>999999</n_ecrou> <prenom>Lucifer</prenom> </Detenu> <Condamnation> <n_type_decision>1</n_type_decision> <n_ecrou>111111</n_ecrou> <date_decision>2020-10-30</date_decision> <duree>10</duree> </Condamnation> <!-- Duplicate key value [1,111111,2020-10-30] declared for identity constraint "Condamnation_key" of element "Prison" : --> <!--<Condamnation>--> <!--<n_type_decision>1</n_type_decision>--> <!--<n_ecrou>111111</n_ecrou>--> <!--<date_decision>2020-10-30</date_decision>--> <!--<duree>20</duree>--> <!--</Condamnation>--> <Condamnation> <n_type_decision>1</n_type_decision> <n_ecrou>999999</n_ecrou> <date_decision>2020-10-30</date_decision> <duree>20</duree> </Condamnation> <Reduction_peine> <n_type_decision>2</n_type_decision> <n_ecrou>111111</n_ecrou> <date_decision>2020-10-30</date_decision> <duree>5</duree> </Reduction_peine> <Liberation_definitive> <n_type_decision>3</n_type_decision> <n_ecrou>111111</n_ecrou> <date_decision>2020-10-30</date_decision> <date_liberation>2021-01-04</date_liberation> </Liberation_definitive> </Prison>
Fichier
Prison.xsd
<?xml version="1.0"?> <!-- Prison.xsd --> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" version="1.0"> <xsd:complexType name="Detenu_type"> <xsd:sequence> <xsd:element name="n_ecrou" type="xsd:string" minOccurs="1" maxOccurs="1"/> <xsd:element name="prenom" type="xsd:string"/> </xsd:sequence> </xsd:complexType> <xsd:complexType name="Decision_type"> <xsd:sequence> <xsd:element name="n_type_decision"> <xsd:simpleType> <xsd:restriction base="xsd:positiveInteger"> <xsd:minInclusive value="1"/> <xsd:maxInclusive value="3"/> </xsd:restriction> </xsd:simpleType> </xsd:element> <xsd:element name="n_ecrou" type="xsd:string"/> <xsd:element name="date_decision" type="xsd:date"/> <xsd:element name="duree" type="xsd:positiveInteger" minOccurs="0" maxOccurs="0"/> </xsd:sequence> </xsd:complexType> <xsd:complexType name="Condamnation_type"> <xsd:complexContent> <xsd:restriction base="Decision_type"> <xsd:sequence> <xsd:element name="n_type_decision"> <xsd:simpleType> <xsd:restriction base="xsd:positiveInteger"> <xsd:minInclusive value="1"/> <xsd:maxInclusive value="1"/> </xsd:restriction> </xsd:simpleType> </xsd:element> <xsd:element name="n_ecrou" type="xsd:string"/> <xsd:element name="date_decision" type="xsd:date"/> <xsd:element name="duree" type="xsd:positiveInteger" minOccurs="1" maxOccurs="1"/> </xsd:sequence> </xsd:restriction> </xsd:complexContent> </xsd:complexType> <xsd:complexType name="Reduction_peine_type"> <xsd:complexContent> <xsd:restriction base="Decision_type"> <xsd:sequence> <xsd:element name="n_type_decision"> <xsd:simpleType> <xsd:restriction base="xsd:positiveInteger"> <xsd:minInclusive value="2"/> <xsd:maxInclusive value="2"/> </xsd:restriction> </xsd:simpleType> </xsd:element> <xsd:element name="n_ecrou" type="xsd:string"/> <xsd:element name="date_decision" type="xsd:date"/> <xsd:element name="duree" type="xsd:positiveInteger" minOccurs="1" maxOccurs="1"/> </xsd:sequence> </xsd:restriction> </xsd:complexContent> </xsd:complexType> <xsd:complexType name="Liberation_definitive_type"> <xsd:complexContent> <xsd:restriction base="Decision_type"> <xsd:sequence> <xsd:element name="n_type_decision"> <xsd:simpleType> <xsd:restriction base="xsd:positiveInteger"> <xsd:minInclusive value="3"/> <xsd:maxInclusive value="3"/> </xsd:restriction> </xsd:simpleType> </xsd:element> <xsd:element name="n_ecrou" type="xsd:string"/> <xsd:element name="date_decision" type="xsd:date"/> <xsd:element name="date_liberation" type="xsd:date"/> </xsd:sequence> </xsd:restriction> </xsd:complexContent> </xsd:complexType> <xsd:element name="Prison"> <xsd:complexType> <xsd:sequence> <xsd:element name="Detenu" type="Detenu_type" maxOccurs="unbounded"/> <xsd:element name="Condamnation" type="Condamnation_type" maxOccurs="unbounded"/> <xsd:element name="Reduction_peine" type="Reduction_peine_type" maxOccurs="unbounded"/> <xsd:element name="Liberation_definitive" type="Liberation_definitive_type" maxOccurs="unbounded"/> </xsd:sequence> <xsd:attribute name="author" default="Franck Barbier" type="xsd:string"/> <xsd:attribute name="URL" default="https://BarbierDarnal.com/Enterprise_Architect/Prison_de_Nantes/Prison_de_Nantes.html" type="xsd:anyURI"/> <xsd:attribute name="version" type="xsd:string" fixed="1.1"/> </xsd:complexType> <xsd:key name="Detenu_key"> <xsd:selector xpath="./Detenu"/> <xsd:field xpath="./n_ecrou"/> </xsd:key> <xsd:key name="Condamnation_key"> <!-- ? --> </xsd:key> <xsd:keyref name="Condamnation_fk" refer="Detenu_key"> <xsd:selector xpath="Condamnation"/> <xsd:field xpath="n_ecrou"/> </xsd:keyref> <xsd:key name="Reduction_peine_key"> <!-- ? --> </xsd:key> <xsd:keyref name="Reduction_peine_fk" refer="Detenu_key"> <xsd:selector xpath="Reduction_peine"/> <xsd:field xpath="n_ecrou"/> </xsd:keyref> <xsd:key name="Liberation_definitive_key"> <!-- ? --> </xsd:key> <xsd:keyref name="Liberation_definitive_fk" refer="Detenu_key"> <xsd:selector xpath="Liberation_definitive"/> <xsd:field xpath="n_ecrou"/> </xsd:keyref> </xsd:element> </xsd:schema>
Les espaces de nommage permettent d'organiser la sépcification des données et en corollaire de gérer les conflits de nommage dès lors que les données proviennent de sources différentes.
Exemple FB.xsd
FB.xml
![]()
<?xml version="1.0"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="FranckBarbier"> <!-- 'xsd:annotation' a pour principe d'expliquer la nature et la finalité de la XSD --> <xsd:annotation> <xsd:appinfo>Intro. à la notion d'espace de nommage...</xsd:appinfo> <xsd:documentation xml:lang="fr"> La balise 'SALUTATION' appartient à l'espace de nommage 'FranckBarbier' </xsd:documentation> </xsd:annotation> <xsd:element name="SALUTATION" type="xsd:string"/> </xsd:schema>
<?xml version="1.0" encoding="UTF-8"?> <!-- L'espace de nommage 'FB' est introduit en référence à l'espace de nommage 'FranckBarbier' --> <FB:SALUTATION xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:FB="FranckBarbier" xsi:schemaLocation="FranckBarbier FB.xsd">Bonjour !</FB:SALUTATION>
targetNamespace
L'absence de
targetNamespace
simplifie les choses.Exemple FB_.xsd
FB_.xml
![]()
<?xml version="1.0"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="SALUTATION" type="xsd:string"/> </xsd:schema>
<?xml version="1.0" encoding="UTF-8"?> <SALUTATION xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FB_.xsd">Bonjour !</SALUTATION>
elementFormDefault="qualified"
L'attribut
elementFormDefault
de la baliseschema
est par défaut fixé à la valeur"unqualified"
.Exemple A.xsd
A.xml
![]()
<?xml version="1.0" encoding="UTF-8"?> <!-- https://stackoverflow.com/questions/1463138/what-does-elementformdefault-do-in-xsd --> <!-- If 'elementFormDefault="qualified"' is absent then the default unqualified value means that *locally declared elements, e.g., 'assignment' are in no namespace* --> <!-- Test 'A.xml' and next add 'elementFormDefault="qualified"' --> <!-- Les espaces de nommage 'COUCOU' et 'BDi' sont introduits et utilisés --> <COUCOU:schema xmlns:COUCOU="http://www.w3.org/2001/XMLSchema" xmlns:BDi="https://barbierdarnal.com" targetNamespace="https://barbierdarnal.com"> <COUCOU:element name="assignments"> <COUCOU:complexType> <COUCOU:sequence> <COUCOU:element name="assignment" type="BDi:assignment_data" minOccurs="1" maxOccurs="unbounded"/> </COUCOU:sequence> </COUCOU:complexType> </COUCOU:element> <COUCOU:complexType name="assignment_data"> <COUCOU:sequence> <COUCOU:element name="name" type="COUCOU:string"/> </COUCOU:sequence> <COUCOU:attribute name="what" type="COUCOU:string" use="required"/> </COUCOU:complexType> </COUCOU:schema>
<?xml version="1.0" encoding="UTF-8"?> <assignments xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="https://barbierdarnal.com" xsi:schemaLocation="https://barbierdarnal.com A.xsd"> <!-- 'assignment' n'est pas dans un espace de nommage --> <!-- Supprimer 'xmlns=""' si 'elementFormDefault="qualified"' dans XSD --> <assignment what="formation XML" xmlns=""> <name>Franck Barbier</name> </assignment> </assignments>
Modularité ⤳
import
L'idée et l'intérêt sont de segmenter la définiion de la XSD en plusieurs fichiers résultant probablement d'analyses antérieures et/ou séparées.
Exemple Voyageurs.xsd
Voyageur.xsd
Adresses.xsd
Voyageurs.xml
![]()
<?xml version="1.0" encoding="utf-16"?> <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="https://BarbierDarnal.com" xmlns:V="V" attributeFormDefault="qualified" elementFormDefault="qualified"> <import schemaLocation="Voyageur.xsd" namespace="V"/> <element name="Voyageurs"> <complexType> <sequence> <element name="Voyageur" type="V:Voyageur_type"/> </sequence> </complexType> </element> </schema>
<?xml version="1.0" encoding="utf-16"?> <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="V" xmlns:A="A" attributeFormDefault="qualified" elementFormDefault="qualified"> <import schemaLocation="Adresses.xsd" namespace="A"/> <complexType name="Voyageur_type"> <sequence> <element name="Nom" type="string"/> <element name="Residence_FR" type="A:FR_adresse_type" minOccurs="0"/> <element name="Residence_US" type="A:US_adresse_type" minOccurs="0"/> </sequence> </complexType> </schema>
<?xml version="1.0" encoding="UTF-16"?> <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="A" attributeFormDefault="qualified" elementFormDefault="qualified"> <!-- 'FR_adresse_type' et 'US_adresse_type' appartiennent a l'espace de nommmage 'A' --> <complexType name="FR_adresse_type"> <sequence> <element name="Numero_rue" type="string"/> <element name="Rue" type="string"/> <element name="Code_postal" type="positiveInteger"/> <element name="Ville" type="string"/> </sequence> </complexType> <complexType name="US_adresse_type"> <attribute name="street_number" type="string" use="required"/> <attribute name="street" type="string" use="required"/> <attribute name="zip_code" type="positiveInteger" use="required"/> <attribute name="city" type="string" use="required"/> <attribute name="state" use="required"> <simpleType> <restriction base="token"> <enumeration value="Alabama"/> <enumeration value="Nevada"/> <enumeration value="South Dakota"/> <enumeration value="Texas"/> <!-- Etc. --> </restriction> </simpleType> </attribute> </complexType> </schema>
<?xml version="1.0" encoding="utf-16"?> <BDi:Voyageurs xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://BarbierDarnal.com Voyageurs.xsd" xmlns:BDi="https://BarbierDarnal.com" xmlns:V="V" xmlns:A="A"> <BDi:Voyageur> <V:Nom>Franck Barbier</V:Nom> <V:Residence_FR> <A:Numero_rue>3</A:Numero_rue> <A:Rue>Alexander Taylor</A:Rue> <A:Code_postal>64000</A:Code_postal> <A:Ville>Pau</A:Ville> </V:Residence_FR> </BDi:Voyageur> </BDi:Voyageurs>
Exercice
A l'aide du logiciel Apache NetBeans, créer un fichier
Moyen_transport.xsd
décrivant le typeMoyen_transport_type
(valeurs possibles :Avion
etBateau
) dans l'espace de nommageM
. Amender le fichierVoyageur.xsd
pour spécifier qu'une donnée de typeVoyageur_type
possède un élément unique de typeMoyen_transport_type
. Finalement, modifier le fichierVoyageurs.xml
de sorte qu'il n'y ait pas d'erreur à la validation.Solution
<?xml version="1.0" encoding="utf-16"?> <BDi:Voyageurs xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://BarbierDarnal.com Voyageurs.xsd" xmlns:BDi="https://BarbierDarnal.com" xmlns:V="V" xmlns:A="A"> <BDi:Voyageur> <V:Nom>Franck Barbier</V:Nom> <V:Residence_FR> <A:Numero_rue>3</A:Numero_rue> <A:Rue>Alexander Taylor</A:Rue> <A:Code_postal>64000</A:Code_postal> <A:Ville>Pau</A:Ville> </V:Residence_FR> <V:Moyen_de_transport>Avion</V:Moyen_de_transport> </BDi:Voyageur> </BDi:Voyageurs>
<?xml version="1.0" encoding="utf-16"?> <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="V" xmlns:A="A" xmlns:M="M" attributeFormDefault="qualified" elementFormDefault="qualified"> <import schemaLocation="Adresses.xsd" namespace="A"/> <import schemaLocation="Moyen_de_transport.xsd" namespace="M"/> <complexType name="Voyageur_type"> <sequence> <element name="Nom" type="string"/> <element name="Residence_FR" type="A:FR_adresse_type" minOccurs="0"/> <element name="Residence_US" type="A:US_adresse_type" minOccurs="0"/> <element name="Moyen_de_transport" type="M:Moyen_transport_type"/> </sequence> </complexType> </schema>
<?xml version="1.0" encoding="utf-16"?> <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="M" attributeFormDefault="qualified" elementFormDefault="qualified"> <simpleType name="Moyen_transport_type"> <restriction base="string"> <enumeration value="Avion"/> <enumeration value="Bateau"/> </restriction> </simpleType> </schema>
Modularité ⤳
ref
L'idée et l'intérêt sont de réutiliser des spécifications de type « élémentaire » dans d'autres types plus « complexes ».
Exemple
<?xml version="1.0"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> <xsd:element name="Dish_option" type="xsd:string"/> <xsd:element name="Dessert" substitutionGroup="Dish_option"/> <xsd:element name="Starter" substitutionGroup="Dish_option"/> <xsd:element name="Dish"> <xsd:complexType> <xsd:sequence> <xsd:element ref="Starter" minOccurs="0"/> <xsd:element name="Main_course" type="xsd:string"/> <xsd:element ref="Dessert" minOccurs="0"/> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema>
<?xml version="1.0" encoding="UTF-8"?> <Dish xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Dish.xsd"> <Main_course>Hamburger</Main_course> <Dessert>Tiramisu</Dessert> </Dish>
Modularité ⤳
include
Exercice
A l'aide du logiciel Apache NetBeans, télécharger le fichier Dish.xsd
puis créer un fichier
Day.xsd
et, en utilisantinclude
, décrire l'élémentDay
comme une suite de troisDish
à savoirBreakfast
,Lunch
puisDinner
.Exemple Dish.xsd
Dish.xml
![]()
<?xml version="1.0"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="D" elementFormDefault="qualified" xmlns:Dish_name_space="D"> <xsd:element name="Dish_option" type="xsd:string"/> <xsd:element name="Dessert" substitutionGroup="Dish_name_space:Dish_option"/> <xsd:element name="Starter" substitutionGroup="Dish_name_space:Dish_option"/> <xsd:element name="Dish"> <xsd:complexType> <xsd:sequence> <xsd:element ref="Dish_name_space:Starter" minOccurs="0"/> <xsd:element name="Main_course" type="xsd:string"/> <xsd:element ref="Dish_name_space:Dessert" minOccurs="0"/> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema>
<?xml version="1.0" encoding="UTF-8"?> <Dish:Dish xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="D Dish.xsd" xmlns:Dish="D"> <Dish:Main_course>Hamburger</Dish:Main_course> <Dish:Dessert>Tiramisu</Dish:Dessert> </Dish:Dish>
Solution Day.xsd
Day.xml
![]()
<?xml version="1.0"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="D" elementFormDefault="qualified" xmlns:Day_name_space="D"> <!-- https://stackoverflow.com/questions/2357943/whats-the-difference-between-xsdinclude-and-xsdimport --> <!-- L'espace de nommage 'D' de 'Dish.xsd' doit être maintenu via 'include' --> <xsd:include schemaLocation="Dish.xsd"/> <xsd:element name="Breakfast" substitutionGroup="Day_name_space:Dish"/> <xsd:element name="Lunch" substitutionGroup="Day_name_space:Dish"/> <xsd:element name="Dinner" substitutionGroup="Day_name_space:Dish"/> <xsd:element name="Day"> <xsd:complexType> <xsd:sequence> <xsd:element ref="Day_name_space:Breakfast" minOccurs="0"/> <xsd:element ref="Day_name_space:Lunch"/> <xsd:element ref="Day_name_space:Dinner" minOccurs="0"/> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema>
<?xml version="1.0"?> <Data:Day xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="D Day.xsd" xmlns:Data="D"> <Data:Breakfast> <Data:Starter>Orange juice</Data:Starter> <Data:Main_course>Coffee</Data:Main_course> </Data:Breakfast> <Data:Lunch> <Data:Main_course>Lasagna</Data:Main_course> <Data:Dessert>Banana</Data:Dessert> </Data:Lunch> <Data:Dinner> <Data:Main_course>Soup</Data:Main_course> </Data:Dinner> </Data:Day>
XQuery est un langage de requêtes disposant d'une syntaxe propre et de fonctions pour « interroger » un document XML. Le résultat est un autre document XML qui n'est rien d'autre que le résultat d'une transformation. A ce titre, comme XSLT, XQuery peut produire du HTML, JavaScript Object Notation -JSON-, SQL ou encore YAML Ain't Markup Language -YAML- qui est un sur-ensemble de JSON.
Une comparaison entre JSON et XML est présentée ☛
XQuery utiliseXPath. Accès aux éléments d'un document XML avecXPath :
La nécessité d'un système d'exécution de XQuery (absent de Apache NetBeans) impose l'utilisation d'outils idoines comme Saxon.
Exemple (cf. fichier
Articles.xml
)(: The doc() function is used to open the "Articles.xml" file: :) (: Requête : extraire tous les produits finis... :) doc("./data/Articles.xml")/Articles/Article[@PF_ou_MP_ou_Piece_ou_SE = 'PF']
Exemple (SQL-compliant)
SELECT * FROM Article WHERE PF_ou_MP_ou_Piece_ou_SE = 'PF';
Exemple (cf. fichier
Articles.xml
)(: Requête : extraire la désignation de tous les produits finis... :) (: La fonction 'data' est obligatoire... :) doc("./data/Articles.xml")/Articles/Article[@PF_ou_MP_ou_Piece_ou_SE = 'PF']/data(./@designation)
Exemple (SQL-compliant)
SELECT designation FROM Article WHERE PF_ou_MP_ou_Piece_ou_SE = 'PF';
XQuery offre les expressions FLWOR (
For Let Where Order Return
) pour écrire des requêtes complexes.Exemple (cf. fichier
Articles.xml
)(: Requête : extraire toutes les références des produits finis par ordre alphabétique inverse de leur désignation... :) for $a in doc("./data/Articles.xml")/Articles/Article where $a/@PF_ou_MP_ou_Piece_ou_SE = 'PF' order by $a/@designation descending (: La fonction 'data' est obligatoire... :) return data($a/@reference)
Exemple (SQL-compliant)
SELECT reference FROM Article ORDER BY designation DESC WHERE PF_ou_MP_ou_Piece_ou_SE = 'PF';
Exercice
Opérer les requêtes dans Apache NetBeans
Outre les expressions FLWOR, la structure de contrôle (
if () then () else ()
) peut (aussi) être utile pour écrire des requêtes ou transformations complexes.Exemple (fichier source Articles_.xml
)
(: Composants (rôle)... :) (: '//' signifie qu'on balaie tous les éléments '<Article>' quelque soit leur niveau de profondeur :) let $articles := doc("./data/Articles_.xml")//Article let $liens_de_nomenclature := doc("./data/Articles_.xml")//Lien_de_nomenclature return <table><tr><th>Réference=</th><th>Désignation</th><th>Type</th></tr> { for $article in $articles where true() return <tr> { (: Attention, les composants apparaîtront plusieurs fois, voir la fonction 'distinct-values' :) for $lien_de_nomenclature in $liens_de_nomenclature return if (data($lien_de_nomenclature/composant) = data($article/@reference)) (: Attention à la virgule à l'intérieur du 'then' :) then ( <td>{data($article/@reference)}</td>, <td>{data($article/designation)}</td>, (: '*' signifie tous les éléments fils puis on prend le 1er... :) <td>{name($article/PF_ou_MP_ou_Piece_ou_SE/*[1])}</td>) else () } </tr> } </table>
Résultat
Réference Désignation Type CH005 chassis monte SE CH005 chassis monte SE ES000 essieu monte SE ROUE50 roue de camion Pi Exercice
Opérer les requêtes dans Apache NetBeans
Exercice
Ecrire en fonction du fichier source Articles_.xml
la requête XQuery « Quels sont les composés (référence et désignation) dans lequel entre
CH005
comme composant et avec quelle quantité ? ».Indication (fonction
concat
)(: Requête : extraire tous les couples référence/désignation des articles... :) let $Reference := "Référence : " let $Designation := "Désignation : " for $a in doc("./data/Articles.xml")/Articles/Article return concat($Reference,data($a/@reference)," ",$Designation,data($a/@designation))
Solutions
for $lien_de_nomenclature in doc("./data/Articles_.xml")//Lien_de_nomenclature where $lien_de_nomenclature/composant = "CH005" return concat($lien_de_nomenclature/compose," en utilise ",$lien_de_nomenclature/quantite_de_composition)
let $filtre := doc("./data/Articles_.xml")//Lien_de_nomenclature[./composant = 'CH005'] for $lien_nomclature in $filtre return concat($lien_nomclature/compose," en utilise ",$lien_nomclature/quantite_de_composition)
XQuery ⤳ XML to XML Comme XSLT, XQuery autorise des transformations de XML vers XML.
- Tutoriel XQuery sur la construction d'éléments et d'attributs ☛
Exemple (fichier source
data/PLM_source.xml
dans le programme Java Saxon)(: Transformation 'PLM_source_TO_PLM_target.xqy'... :) <PLM> { (: Better: 'for $article in doc("./data/PLM_source.xml")/*/Article' :) for $article in doc("./data/PLM_source.xml")/PLM/Article (: Construction d'un élément (https://www.altova.com/training/xquery3/constructors)... :) return element {$article/name()} { (: Tous les attributes... :) for $attribut_de_article in $article/@* return (: 'reference' doit rester un attribut contrairement aux autres attributs qui deviennent des éléments :) if ($attribut_de_article/name() = "reference") then attribute {$attribut_de_article/name()} {data($attribut_de_article)} else (: 'PF_ou_MP_ou_Piece_ou_SE' devient un élément avec sous élément :) if ($attribut_de_article/name() = "PF_ou_MP_ou_Piece_ou_SE") then element {$attribut_de_article/name()} { let $attribut_devient_sous_element := data($attribut_de_article) (: Element vide... :) return element {$attribut_devient_sous_element} {} } else element {$attribut_de_article/name()} {data($attribut_de_article)} } } </PLM>
Exercice
Opérer la transformation dans Apache NetBeans
Exercice
La transformation XQuery précédente gère l'élément
<PLM> ... </PLM>
« en dur ». Remplacer cette gestion par la production automatique d'un élément dont le nom est le calcul XQuery du nom de la racine du fichier source XML.(: Transformation 'PLM_source_TO_PLM_target_.xqy'... :) element {doc("./data/PLM_source.xml")/*/name()} { … }
Exercice
Ecrire la transformation inverse de PLM_target.xml
vers PLM_source.xml
![]()
Solution
eXtensible Style Language Transformations -XSLT- ⤳ XML to HTML XSLT (a.k.a. XSL) est un langage impératif et donc doté de structures de contrôle pour transformer un document XML en un autre. Il est possible d'effectuer d'autres transformations vers CVS, JSON, HTML, LDIF, RTF, SQL, YAML, etc.
XSLT s'appuie foncièrement surXPath pour établir la manière dont tout élément ou ensemble d'éléments XML est transformé vers un « motif » de code cible. Note : XSLT etXQuery tous deux utilisentXPath comme sous-langage.
Exemple PLM_with_XSD_1_.xml
![]()
<?xml version="1.0" encoding="UTF-8"?> <PLM xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="PLM_1.xsd"> <Article reference="CD100" designation="camion demenagement bleu" type_fabrication_achat="fabr. par lot" unite_achat_stock="unite" delai_en_semaine="2" lot_de_reapprovisionnement="200" stock_maxi="600" PF_ou_MP_ou_Piece_ou_SE="PF"/> <Article reference="CH005" designation="chassis monte" type_fabrication_achat="fabr. par lot" unite_achat_stock="unite" delai_en_semaine="2" lot_de_reapprovisionnement="200" stock_maxi="600" PF_ou_MP_ou_Piece_ou_SE="SE"/> <Article reference="H000" designation="conteneur bleu" type_fabrication_achat="fabr. par lot" unite_achat_stock="unite" delai_en_semaine="1" lot_de_reapprovisionnement="150" stock_mini="350" stock_maxi="800" PF_ou_MP_ou_Piece_ou_SE="SE"/> <Lien_de_nomenclature compose="CD100" composant="CH005" quantite_de_composition="1"/> <Lien_de_nomenclature compose="CD100" composant="H000" quantite_de_composition="1"/> </PLM>
Cible HTML
Transformation PLM_with_XSD_1_TO_WEB.xsl
![]()
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="html"/> <!-- The '<xsl:template>' element contains rules to apply when a specified node is matched… --> <!-- 'match="/"' defines the whole document: --> <xsl:template match="/"> <html> <head> <title>PLM_with_XSD_1_TO_WEB.xsl</title> </head> <body> <!--<h2>Source: <a href="./PLM_with_XSD_1_.xml">PLM_with_XSD_1_.xml</a>--> <!--<br/>Transformation: <a href="./PLM_with_XSD_1_TO_WEB.xsl">PLM_with_XSD_1_TO_WEB.xsl</a>--> <!--</h2>--> <xsl:variable name="PLM"/> <xsl:choose> <xsl:when test="not($PLM)"> <!-- No value at all... --> <h3 style="padding: 10px 10px 10px 10px;">PLM</h3> </xsl:when> <xsl:otherwise> <h3 style="padding: 25px 25px 25px 25px;"> <xsl:value-of select="$PLM"/> </h3> </xsl:otherwise> </xsl:choose> <table border="1"> <tr> <th style="background-color: aqua;"> <!-- Get the name of the element instead of the element's value --> <xsl:value-of select="local-name(PLM/Article)"/> </th> <th style="background-color: powderblue;"> <xsl:value-of select="local-name(PLM/Lien_de_nomenclature/@quantite_de_composition)"/> </th> <th style="background-color: powderblue;"> <xsl:value-of select="local-name(PLM/Lien_de_nomenclature/@composant)"/> </th> </tr> <xsl:for-each select="PLM/Article"> <!-- Variables in XSLT may only be assigned a value once: --> <xsl:variable name="reference_courante" select="./@reference"/> <!-- Attention chemin relatif car le contexte est 'Article' : --> <xsl:for-each select="../Lien_de_nomenclature"> <!-- Ou alors : '<xsl:for-each select="/PLM/Lien_de_nomenclature">' --> <xsl:choose> <xsl:when test="./@compose = $reference_courante and position() = 1"> <tr> <td> <!-- XPath attribute access: --> <xsl:value-of select="$reference_courante"/> <!-- Ou alors : '<xsl:value-of select="./@reference"/>' --> </td> <td style="text-align:center;"> <xsl:value-of select="@quantite_de_composition"/> </td> <td> <xsl:value-of select="@composant"/> </td> </tr> </xsl:when> <!-- 'not(position() = 1)' as well: --> <xsl:when test="./@compose = $reference_courante and position() != 1"> <tr> <td></td> <td style="text-align:center;"> <xsl:value-of select="@quantite_de_composition"/> </td> <td> <xsl:value-of select="@composant"/> </td> </tr> </xsl:when> <xsl:otherwise> <xsl:if test="position() = 1"> <tr> <td> <xsl:value-of select="$reference_courante"/> </td> <td></td> <td></td> </tr> </xsl:if> </xsl:otherwise> </xsl:choose> </xsl:for-each> </xsl:for-each> </table> </body> </html> </xsl:template> </xsl:stylesheet>
Exercice
Opérer la transformation dans Apache NetBeans
eXtensible Style Language Transformations -XSLT- ⤳ XML to XML La transformation XML à XML est la plus « requise » dans le cadre de traitement massif de données : extraction, enrichissement, comparaison, fusion…
Exemple PLM_source.xml
![]()
<?xml version="1.0" encoding="UTF-8"?> <!-- L'ouverture de ce source XML dans un browser compatible XSLT provoque la transformation : --> <?xml-stylesheet type="text/xsl" href="PLM_source_TO_PLM_target.xsl"?> <PLM> <Article reference="CD100" designation="camion demenagement bleu" type_fabrication_achat="fabr. par lot" unite_achat_stock="unite" delai_en_semaine="2" lot_de_reapprovisionnement="200" stock_maxi="600" PF_ou_MP_ou_Piece_ou_SE="PF"/> <Article reference="CH005" designation="chassis monte" type_fabrication_achat="fabr. par lot" unite_achat_stock="unite" delai_en_semaine="2" lot_de_reapprovisionnement="200" stock_maxi="600" PF_ou_MP_ou_Piece_ou_SE="SE"/> <!-- ... --> <Lien_de_nomenclature compose="CD100" composant="CH005" quantite_de_composition="1"/> <!-- ... --> </PLM>
Cible XML PLM_target.xml
![]()
<?xml version="1.0" encoding="UTF-8"?> <PLM> <Article reference="CD100"> <designation>camion demenagement bleu</designation> <type_fabrication_achat>fabr. par lot</type_fabrication_achat> <unite_achat_stock>unite</unite_achat_stock> <delai_en_semaine>2</delai_en_semaine> <lot_de_reapprovisionnement>200</lot_de_reapprovisionnement> <stock_maxi>600</stock_maxi> <PF_ou_MP_ou_Piece_ou_SE> <PF/> </PF_ou_MP_ou_Piece_ou_SE> </Article> <Article reference="CH005"> <designation>chassis monte</designation> <type_fabrication_achat>fabr. par lot</type_fabrication_achat> <unite_achat_stock>unite</unite_achat_stock> <delai_en_semaine>1</delai_en_semaine> <lot_de_reapprovisionnement>300</lot_de_reapprovisionnement> <stock_maxi>900</stock_maxi> <PF_ou_MP_ou_Piece_ou_SE> <SE/> </PF_ou_MP_ou_Piece_ou_SE> </Article> <!-- ... --> <Lien_de_nomenclature> <compose>CD100</compose> <composant>CH005</composant> <quantite_de_composition>1</quantite_de_composition> </Lien_de_nomenclature> <!-- ... --> </PLM>
Transformation PLM_source_TO_PLM_target.xsl
![]()
<?xml version="1.0" encoding="UTF-8"?> <!-- '<xsl:stylesheet>' and '<xsl:transform>' are completely synonymous: --> <xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <!-- La cible est du XML : --> <xsl:output method="xml" indent="yes"/> <!-- The 'match' attribute is used to associate a template with an XML element, say '/' as the root: --> <xsl:template match="/PLM"> <PLM> <xsl:apply-templates select="Article"/> <xsl:text disable-output-escaping="yes"><!-- ... --></xsl:text> <xsl:apply-templates select="Lien_de_nomenclature"/> <xsl:text disable-output-escaping="yes"><!-- ... --></xsl:text> </PLM> </xsl:template> <xsl:template match="Article"> <xsl:element name="{local-name()}"> <!-- Ajout d'un attribut à l'élément : --> <xsl:attribute name="reference"> <xsl:value-of select="@reference"/> </xsl:attribute> <!--First sub-element:--> <!--<designation>--> <!--<xsl:value-of select="@designation"/>--> <!--</designation>--> <!-- Itération sur tous (i.e., '*') les attributs (i.e., '@') : --> <xsl:for-each select="@*"> <!-- Pas terrible... on exclut le 1er attribut, e.g., 'reference' : --> <!-- Revoir ce test car les attributs sont par définition non ordonnés : --> <xsl:if test="position() != 1"> <xsl:element name="{local-name(.)}"> <xsl:choose> <xsl:when test="local-name(.) = 'PF_ou_MP_ou_Piece_ou_SE'"> <xsl:element name="{.}"> </xsl:element> </xsl:when> <xsl:otherwise> <xsl:value-of select="."/> </xsl:otherwise> </xsl:choose> </xsl:element> </xsl:if> </xsl:for-each> </xsl:element> </xsl:template> <xsl:template match="Lien_de_nomenclature"> <xsl:element name="{local-name()}"> <xsl:for-each select="@*"> <xsl:element name="{local-name(.)}"> <xsl:value-of select="."/> </xsl:element> </xsl:for-each> </xsl:element> </xsl:template> </xsl:transform>
Exercice
Opérer la transformation dans Apache NetBeans
Exercice
A l'aide du logiciel Apache NetBeans, écrire la transformation inverse de PLM_target.xml
vers PLM_source.xml
![]()
Solution PLM_target_TO_PLM_source.xsl
<?xml version="1.0" encoding="UTF-8"?> <xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml" indent="yes"/> <!-- The 'match' attribute is used to associate a template with an XML element, say '/' as the root: --> <xsl:template match="/PLM"> <PLM> <xsl:apply-templates select="Article"/> <xsl:text disable-output-escaping="yes"><!-- ... --></xsl:text> <xsl:apply-templates select="Lien_de_nomenclature"/> <xsl:text disable-output-escaping="yes"><!-- ... --></xsl:text> </PLM> </xsl:template> <xsl:template match="Article"> <!-- L'élément 'Article' reste en tant que tel : --> <xsl:element name="{local-name()}"> <!-- Conservation de l'attribut 'reference' pour l'élément 'Article' : --> <xsl:attribute name="reference"> <xsl:value-of select="@reference"/> </xsl:attribute> <!-- Ajout de l'attribut 'designation' à l'élément 'Article' à partir du sous-élément 'designation' : --> <xsl:attribute name="designation"> <xsl:value-of select="designation"/> </xsl:attribute> <!-- On itère sur tous les sous-éléments (bien que 'designation' soit traité juste avant pas de duplication néanmoins : --> <xsl:for-each select="*"> <!-- '{local-name()}' ou '{local-name(.)}' pour accéder au nom de l'élément courant : --> <xsl:attribute name="{local-name()}"> <!-- Problème d'un sous-élément unique pour l'élément 'PF_ou_MP_ou_Piece_ou_SE' --> <xsl:choose> <!-- On teste si l'élément courant a un sous-élément, en l'occurrence seul l'élément 'PF_ou_MP_ou_Piece_ou_SE' est dans ce cas : --> <xsl:when test="*"> <!-- Le *NOM* du (premier) sous-élément est accédé via Xpath : --> <xsl:value-of select="name(./*[1])"/> </xsl:when> <xsl:otherwise> <!-- La valeur de l'élément courant est exprimée via Xpath : --> <xsl:value-of select="."/> </xsl:otherwise> </xsl:choose> </xsl:attribute> </xsl:for-each> </xsl:element> </xsl:template> <xsl:template match="Lien_de_nomenclature"> <!-- L'élément 'Lien_de_nomenclature' reste en tant que tel : --> <xsl:element name="{local-name()}"> <xsl:for-each select="*"> <xsl:attribute name="{local-name()}"> <xsl:value-of select="."/> </xsl:attribute> </xsl:for-each> </xsl:element> </xsl:template> </xsl:transform>
XML Linking language -XLink- et XPointer
- XLink (relativement obsolète) et XPointer sont des outils XML « connexes » qui permettent de « relier » des éléments XML entre eux par navigation (liens hyper-texte) ou par référence
- Pour XLink, les attributs des éléments (liens hyper-texte) construits obéissent aux règles décrites ☛
- XPointer s'appuie lui sur XPath pour cibler tout élément ou ensemble d'éléments d'un document XML. En fait, contrairement à XLink, XPointer vise à lier des parties spécifiques du document XML
Exemple XLink PLM_XLink.xml
CD100.xml
CH005.xml
![]()
<?xml version="1.0" encoding="UTF-8"?> <!-- Acces au "name space" 'xlink' : --> <PLM_ xmlns:xlink="https://www.w3.org/1999/xlink"> <!-- 'xlink:type="extended"': https://docstore.mik.ua/orelly/xml/xmlnut/ch10_04.htm --> <Articles_Liens_de_nomenclature xlink:type="extended" xlink:title="Articles et nomenclature de fabrication"> <Articles xlink:type="simple" xlink:href="https://barbierdarnal.com/Enterprise_Architect/PLM/PLM.html#Articles"/> <Liens_de_nomenclature xlink:type="simple" xlink:href="https://barbierdarnal.com/Enterprise_Architect/PLM/PLM.html#Nomenclature_de_fabrication"/> <!-- 'xlink:label="..."' est un nom local pour creer ensuite les arcs : --> <Article xlink:type="locator" xlink:label="CD100" xlink:href="CD100.xml"/> <Article xlink:type="locator" xlink:label="CH005" xlink:href="CH005.xml"/> <Lien_de_nomenclature xlink:type="arc" xlink:from="CD100" xlink:to="CH005"> <quantite_de_composition>1</quantite_de_composition> </Lien_de_nomenclature> </Articles_Liens_de_nomenclature> </PLM_>
Exemple XPointer PLM_XPointer.xml
![]()
<?xml version="1.0" encoding="UTF-8"?> <!-- Acces au "name space" 'xlink' : --> <PLM xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xi="http://www.w3.org/2001/XInclude"> <Articles xlink:type="simple" xlink:href="https://barbierdarnal.com/Enterprise_Architect/PLM/PLM.html#Articles"> <author xlink:type="simple" xlink:href="https://franckbarbier.com/img/Common/Franck.jpg"/> <!-- 'xlink:show="embed"' : le lien s'ouvre de facon embarquee --> <Type_CD100 xlink:type="simple" xlink:href="CD100.xml#xpointer(Article[@reference = 'CD100']/PF_ou_MP_ou_Piece_ou_SE)" xlink:show="embed"/> <!-- It relies on '<CH005 id="CH005">': --> <Article xlink:type="simple" xlink:href="CH005.xml#CH005" xlink:show="embed"/> <!-- ... --> </Articles> <xi:include href="CH005.xml" xpointer="xpointer()"/> <Liens_de_nomenclature xlink:type="simple" xlink:href="https://barbierdarnal.com/Enterprise_Architect/PLM/PLM.html#Nomenclature_de_fabrication"> <Lien_de_nomenclature> <compose xlink:type="simple" xlink:href="CD100.xml#xpointer(Article/designation[text()])"/> <!-- '|' means 'and': --> <composant xlink:type="simple" xlink:href="CH005.xml#xpointer(CH005/designation | CH005/PF_ou_MP_ou_Piece_ou_SE)"/> <quantite_de_composition>1</quantite_de_composition> </Lien_de_nomenclature> <!-- ... --> </Liens_de_nomenclature> <Postes_de_charge xlink:type="simple" xlink:href="https://barbierdarnal.com/Enterprise_Architect/PLM/PLM.html#Postes_de_charge"/> <Gammes_de_fabrication xlink:type="simple" xlink:href="https://barbierdarnal.com/Enterprise_Architect/PLM/PLM.html#Gammes_de_fabrication"/> <Mouvements_de_stock xlink:type="simple" xlink:href="https://barbierdarnal.com/Enterprise_Architect/PLM/PLM.html#Mouvements_de_stock_et_inventaire"/> </PLM>
XInclude XInclude est l'inclusion « physique » d'éléments XML.
Exemple XInclude Saxon_XML.Java.zip
![]()
<?xml version="1.0" encoding="UTF-8"?> <PLM xmlns:xi="http://www.w3.org/2001/XInclude"> <!-- Toute l'arborescence et donc '<Articles> ... </Articles>' compris : --> <xi:include href="Articles.xml" parse="xml"> <xi:fallback>'Articles.xml' raises problems?</xi:fallback> </xi:include> <!-- Apache Xerces in Java only supports xpointer="element(...)" --> <!-- La racine, i.e., 'Liens_de_nomenclature' : --> <!--<xi:include href="Liens_de_nomenclature.xml" parse="xml" xpointer="element(/1)"/>--> <!-- Le 1er élément sous 'Liens_de_nomenclature' : --> <xi:include href="Liens_de_nomenclature.xml" parse="xml" xpointer="element(/1/1)"/> </PLM>
xmllint --xinclude .\PLM.xml
Articles.xml
<?xml version="1.0" encoding="UTF-8"?> <Articles> <Article reference="CD100" designation="camion demenagement bleu" type_fabrication_achat="fabr. par lot" unite_achat_stock="unite" delai_en_semaine="2" lot_de_reapprovisionnement="200" stock_maxi="600" PF_ou_MP_ou_Piece_ou_SE="PF"/> <Article reference="CH005" designation="chassis monte" type_fabrication_achat="fabr. par lot" unite_achat_stock="unite" delai_en_semaine="2" lot_de_reapprovisionnement="200" stock_maxi="600" PF_ou_MP_ou_Piece_ou_SE="SE"/> <!-- ... --> </Articles>
Liens_de_nomenclature.xml
<?xml version="1.0" encoding="UTF-8"?> <Liens_de_nomenclature xml:id="RACINE"> <!-- Attention à bien conserver le suffixe 'xml:' devant 'id' --> <Lien_de_nomenclature xml:id="CD100-CH005" compose="CD100" composant="CH005" quantite_de_composition="1"> <FICTIF> <!-- Test pour 'xpointer="element(CD100-CH005/1)' --> <FICTIF>FICTIF</FICTIF> </FICTIF> </Lien_de_nomenclature> <!-- ... --> </Liens_de_nomenclature>
Exercice : tous les sous-éléments de la racine
Liens_de_nomenclature
<xi:include href="Liens_de_nomenclature.xml" parse="xml" xpointer="xpointer(/Liens_de_nomenclature/*)"/>
Exercice : le 1er sous-élément (
*
⤳ tous) de l'élément ayant pour identitéRACINE
<xi:include href="Liens_de_nomenclature.xml" parse="xml" xpointer="element(RACINE/1)"/>
Exercice : le 1er sous-élément de l'élément ayant pour identité
CD100-CH005
(bogue si aucun sous-élément !)<xi:include href="Liens_de_nomenclature.xml" parse="xml" xpointer="element(CD100-CH005/1)"/>
Exercice : tous les éléments
FICTIF
quelque soit leur niveau d'emboîtement ⤳ redondance !<xi:include href="Liens_de_nomenclature.xml" parse="xml" xpointer="xpointer(//FICTIF)"/>
Exercice : l'élément
Lien_de_nomenclature
dont la valeur de l'attributcompose
estCD1000
<xi:include href="Liens_de_nomenclature.xml" xpointer="xpointer(/Liens_de_nomenclature/Lien_de_nomenclature[@compose="CD100"])"/>
Exercice : l'élément
Lien_de_nomenclature
dont la valeur de l'attributcompose
estCD1000
et… ⤳ condition sur le contenu<xi:include href="Liens_de_nomenclature.xml" xpointer="xpointer(/Liens_de_nomenclature/Lien_de_nomenclature[@compose="CD100" and ./FICTIF/FICTIF/text()="FICTIF"])"/>
<xi:include href="Liens_de_nomenclature.xml" xpointer="xpointer(/Liens_de_nomenclature/Lien_de_nomenclature[@compose="CD100" and ./FICTIF/FICTIF[contains(.,"FICTIF")]])"/>
Exercice : tous les éléments
Lien_de_nomenclature
quelque soit leur niveau ayant un sous-élémentFICTIF
lui même ayant un sous-élémentFICTIF
unique<xi:include href="Liens_de_nomenclature.xml" xpointer="xpointer(//Lien_de_nomenclature/FICTIF[count(FICTIF) = 1])"/>
Persistance Système de gestion de base de données XML
Exemple JavaDB
CREATE TABLE PLM_XML_data(XML_data XML); INSERT INTO PLM_XML_data(XML_data) VALUES(XMLPARSE(DOCUMENT '<PLM> <CD100> <reference>CD100</reference> <designation>camion demenagement bleu</designation> <type_fabrication_achat>fabr. par lot</type_fabrication_achat> <unite_achat_stock>unite</unite_achat_stock> <delai_en_semaine>2</delai_en_semaine> <!--<prix_standard></prix_standard>--> <lot_de_reapprovisionnement>200</lot_de_reapprovisionnement> <!--<stock_mini></stock_mini>--> <stock_maxi>600</stock_maxi> <!--<pourcentage_de_perte></pourcentage_de_perte>--> <!--<inventaire></inventaire>--> <PF_ou_MP_ou_Piece_ou_SE>PF</PF_ou_MP_ou_Piece_ou_SE> </CD100> <!--Etc.--> </PLM>' PRESERVE WHITESPACE)); -- 'CLOB' <=> "Character Large OBject" SELECT XMLSERIALIZE(XML_data AS CLOB) FROM PLM_XML_data;
Serialization XML
Exercice : tester l'API Java de serialization XML ☛ avec un objet de type
Article
public class Article implements java.io.Serializable { transient public final String non_persistant = "Essai attribut 'transient'..."; public enum Type_article { PF, MP, Piece, SE } // Default values for 'CD100': private final String _reference; private final String _designation; private String _type_fabrication_achat = "fabr. par lot"; private String _unite_achat_stock = "unite"; private int _delai_en_semaine = 2; private Float _prix_standard = null; private Integer _lot_de_reapprovisionnement = 200; private Integer _stock_mini = null; private Integer _stock_maxi = 600; private Float _pourcentage_de_perte = null; private String _inventaire = null; private Type_article _PF_ou_MP_ou_Piece_ou_SE = Type_article.PF; public Article(final String reference, final String designation) { _reference = reference; _designation = designation; } // Getters and setters here... }