Gestion de Production Assistée par Ordinateur (GPAO) avec eXtensible Markup Language (XML)

Copyright

Préambule

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 de Gestion de Production Assistée par Ordinateur (GPAO) : ici

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.

Sujets
Outillage

Il existe de nombreux outils permettant de « parser » du « code » XML. Le logiciel 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, XSD…). NetBeans permet également l'exécution de programmes XSLT.

A la découverte de NetBeans pour XML…

Histoire

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 browsers :  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>
Expression XML des données (articles)

1ère approche (attributs) GPAO_internal_DTD_1.xml

2e approche (éléments) GPAO_external_DTD.xml

Expression XML des relations entre données (articles et liens de nomenclature)

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 1

A l'aide du logiciel NetBeans, compléter le fichier GPAO_internal_DTD_1.xml  avec quelques données : d'autres articles, d'autres liens de nomenclature ainsi que des postes de charge (ici…), des gammes de fabrication (ici…) et (éventuellement) des mouvements de stock (ici…). Note : la rubrique inventaire est déjà prise en compte dans les articles.

Exercice 2

A l'aide du logiciel NetBeans, compléter le fichier GPAO_external_DTD.xml  avec quelques données : d'autres articles, d'autres liens de nomenclature ainsi que des postes de charge (ici…), des gammes de fabrication (ici…) et (éventuellement) des mouvements de stock (ici…). Note : la rubrique inventaire est déjà prise en compte dans les articles.

Espaces de nommage

Les espaces de nommage permettent de gérer les conflits de nommage dès lors que les données XML proviennent de plusieurs sources, souvent hétérogènes.

Exemple

<?xml version="1.0" encoding="UTF-8"?>
<!-- The namespace URI is not used by the parser to look up information: --> 
<GPAO xmlns:slide_3="https://barbierdarnal.com/GPAO_slide_3" xmlns:slide_11="https://barbierdarnal.com/GPAO_slide_11">
    <slide_3:Article reference="C004"
                     designation="chassis"/>
    <!-- Autres attributs trouvés sur le slide 3 -->  
    <slide_11:Article reference="C004"
                      inventaire="500"/>
</GPAO>
Document Type Definition (DTD)

Une DTD décrit un format auquel doit obéir un document XML.

  1. Tutoriel DTD (w3schools)
  2. Tutoriel DTD (Quackit)
  3. Quelques exemples et astuces
  4. Analogie DTD et SQL

DTD externalisée dans un fichier GPAO.dtd 

La DTD a été générée dans NetBeans à partir de ce fichier source XML.

Validation GPAO_external_DTD.xml 

1ère approche (Focus sur les attributs)

2e approche (Focus sur les éléments)

Exercice DTD 1

A l'aide du logiciel NetBeans, compléter le fichier GPAO_internal_DTD_1.xml  en schématisant les données des postes de charge (ici…) et des gammes de fabrication (ici…).

Exercice DTD 2

A l'aide du logiciel NetBeans, compléter le fichier GPAO_internal_DTD_2.xml  en schématisant les données des postes de charge (ici…) et des gammes de fabrication (ici…).

Note

La correspondance IDREF/ID est limitée. Typiquement, l'intégrité référentielle de composant vers reference empêche celle, par exemple, de Operation vers Poste de charge si on a une propriété réputée ID pour Poste de charge. Bricolage possible : 2 fichiers DTD différents. Sous-note : l'utilisation de IDREFS n'apporte rien à ce problème.

XML Schema Definition (XSD)

Le langage XSD produit un format auquel doit obéir un document XML. XSD est plus puissant que le langage DTD par le typage*, la possibilité d'expression de tranformation, le fait que XSD soit écrit en XML lui-même, etc.

  1. Tutoriel XSD (w3schools)
  2. Tutoriel XSD (tutorialspoint)

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 XSD 0

A l'aide du logiciel 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 fichier Confinement.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 ici….

XSD autorise la gestion des contraintes d'intégrité référentielle de façon plus poussée que DTD.

  1. Clés primaires, étrangères et unicités
  2. xsd:key

1ère approche (Focus sur les attributs) GPAO_1.xsd  GPAO_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="GPAO">
        <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 GPAO -->
            <!-- Il semblerait que les attributs de 'GPAO' 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="http://109.26.133.25/fbarbier/Modeling/GPAO.html"/> 
        </xs:complexType> <!-- GPAO -->

        <!-- Contraintes d'intégrité référentielle -->
        <xs:key name="Article_pk">
            <!-- Chemin relatif de 'Article' dans 'GPAO' : -->
            <xs:selector xpath="Article" />
            <!-- "@" sélectionne un attribut : -->
            <xs:field xpath="@reference" />
        </xs:key>
        
        <xs:unique name="Article_unique">
            <!-- Chemin relatif de 'Article' dans 'GPAO' : -->
            <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> <!-- GPAO -->
</xs:schema>

A faire…

Opérer la validation dans NetBeans.

2e approche (Focus sur les éléments) GPAO_2.xsd  GPAO_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:FB="https://barbierdarnal.com"' -->
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
            targetNamespace="https://barbierdarnal.com" xmlns:FB="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="GPAO">
        <xsd:complexType>
            <xsd:sequence>
                <xsd:element name="Article" type="FB:Type_article" maxOccurs="unbounded"/>
                <xsd:element name="Lien_de_nomenclature" type="FB: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="http://109.26.133.25/fbarbier/Modeling/GPAO.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="FB:Article" />
            <!-- Le champ est relatif dans le scope, i.e., attribut de 'FB:Article' : -->
            <xsd:field xpath="@reference" />
        </xsd:key>
        
        <xsd:unique name="Article_unique">
            <xsd:selector xpath="./FB:Article" />
            <xsd:field xpath="FB:designation" />
        </xsd:unique>
        
        <xsd:key name="Lien_de_nomenclature_pk">
            <xsd:selector xpath="FB:Lien_de_nomenclature"/>
            <xsd:field xpath="FB:compose"/>
            <xsd:field xpath="FB:composant"/>
        </xsd:key>
        
        <xsd:keyref name="Lien_de_nomenclature_fk_1" refer="FB:Article_pk">
            <xsd:selector xpath="./FB:Lien_de_nomenclature" />
            <xsd:field xpath="FB:compose" />
        </xsd:keyref>
        
        <xsd:keyref name="Lien_de_nomenclature_fk_2" refer="FB:Article_pk">
            <xsd:selector xpath="./FB:Lien_de_nomenclature" />
            <xsd:field xpath="FB:composant" />
        </xsd:keyref>
        <!-- Fin des contraintes d'intégrité référentielle -->
    </xsd:element> 
</xsd:schema>

A faire…

Opérer la validation dans NetBeans.

Exercice XSD 1

A l'aide du logiciel NetBeans, compléter le fichier GPAO_2.xsd  en schématisant les données des postes de charge (ici…) et des gammes de fabrication (ici…).

Exercice XSD 2

A l'aide du logiciel NetBeans, revoir le fichier GPAO_1.xsd  en créant le type PF à partir du type (pré-existant) Article à reconsidérer. Utiliser la méta-balise complexContent.

XQuery est à XML ce que Structured Query Language (SQL) est aux bases de données relationnelles

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 ici.

  1. Tutoriel XQuery (w3schools)
  2. Tutoriel XQuery (tutorialspoint)
  3. (Encore un…) tutoriel XQuery

XQuery utilise XPath. Rappel sur l'accès aux éléments d'un document XML avec XPath :

La nécessité d'un système d'exécution de XQuery (absent de NetBeans) impose l'utilisation d'outils idoines comme Saxon.

Exemple (voir fichier Articles.xml précédent)

(: 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 (voir fichier Articles.xml précédent)

(: 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 (voir fichier Articles.xml précédent)

(: 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'; 

A faire…

Opérer les requêtes dans NetBeans.

XQuery
XML to HTML

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 ici…)

(: 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>

A faire…

Opérer les requêtes dans NetBeans.

Exercice XQuery 1

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))
XQuery
XML to XML

Comme XSLT, XQuery autorise des transformations de XML vers XML.

  1. Tutoriel XQuery sur la construction d'éléments et d'attributs

Exemple (Source XML : data/GPAO_source.xml dans le programme Java Saxon)

(: Transformation 'GPAO_source_TO_GPAO_target.xqy'... :)
<GPAO>
{
    (: Better: 'for $article in doc("./data/GPAO_source.xml")/*/Article' :)
    for $article in doc("./data/GPAO_source.xml")/GPAO/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)}
    }
}
</GPAO>

A faire…

Opérer la transformation dans NetBeans.

Exercice XQuery 2

La transformation XQuery précédente gère l'élément <GPAO> ... </GPAO> « 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 'GPAO_source_TO_GPAO_target_.xqy'... :)

element {doc("./data/GPAO_source.xml")/*/name()}
{
    …
}

Exercice XQuery 3

Ecrire la transformation inverse de GPAO_target.xml  vers GPAO_source.xml .

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 sur XPath 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 et XQuery tous deux utilisent XPath comme sous-langage.

  1. Tutoriel XSLT (w3schools)
  2. Tutoriel XSLT (MDN)

Exemple

Source XML GPAO_with_XSD_1_.xml 

<?xml version="1.0" encoding="UTF-8"?>
<GPAO xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="GPAO_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"/>
</GPAO>

Cible HTML

Transformation GPAO_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>GPAO_with_XSD_1_TO_WEB.xsl</title>
            </head>
            <body>
                <!--<h2>Source: <a href="./GPAO_with_XSD_1_.xml">GPAO_with_XSD_1_.xml</a>-->
                <!--<br/>Transformation: <a href="./GPAO_with_XSD_1_TO_WEB.xsl">GPAO_with_XSD_1_TO_WEB.xsl</a>-->
                <!--</h2>-->
                <xsl:variable name="GPAO"/>
                <xsl:choose>
                    <xsl:when test="not($GPAO)"> <!-- No value at all... -->
                        <h3 style="padding: 10px 10px 10px 10px;">GPAO</h3>
                    </xsl:when>
                    <xsl:otherwise>
                        <h3 style="padding: 25px 25px 25px 25px;">
                            <xsl:value-of select="$GPAO" />
                        </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(GPAO/Article)"/>
                        </th>
                        <th style="background-color: powderblue;">
                            <xsl:value-of select="local-name(GPAO/Lien_de_nomenclature/@quantite_de_composition)"/>
                        </th>
                        <th style="background-color: powderblue;">
                            <xsl:value-of select="local-name(GPAO/Lien_de_nomenclature/@composant)"/>
                        </th>
                    </tr>
                    <xsl:for-each select="GPAO/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="/GPAO/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>

A faire…

Opérer la transformation dans 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

Source XML GPAO_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="GPAO_source_TO_GPAO_target.xsl"?>
<GPAO>
    <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"/>
    <!-- ... -->
</GPAO>

Cible XML GPAO_target.xml 

<?xml version="1.0" encoding="UTF-8"?>
<GPAO>
    <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>
    <!-- ... -->
</GPAO>

Transformation GPAO_source_TO_GPAO_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="/GPAO">
        <GPAO>
            <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> 
        </GPAO>
    </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>

A faire…

Opérer la transformation dans NetBeans.

Exercice XSLT 1

A l'aide du logiciel NetBeans, écrire la transformation inverse de GPAO_target.xml  vers GPAO_source.xml .

XML Linking language (XLink), XPointer et XInclude

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 ici

XPointer s'appuie lui sur XPath pour cibler tout élément ou ensemble d'éléments d'un document XML.

XInclude quant à lui est l'inclusion « physique » d'éléments XML.

  1. Tutoriel (w3schools)
  2. Tutoriel (autre)
  3. Tutoriel (autre autre)

Exemple (XLink)

<!-- Accès au "name space" 'xlink' : -->
<GPAO_ xmlns:xlink="http://www.w3.org/1999/xlink">
    <!-- 'xlink:type="extended"': https://docstore.mik.ua/orelly/xml/xmlnut/ch10_04.htm -->
    <Articles_Liens_de_nomenclature xlink:title="Articles & liens de nomenclature" xlink:type="extended">
        <Articles xlink:type="simple" xlink:href="http://109.26.133.25/fbarbier/Modeling/GPAO_.html#2"/>
        <Liens_de_nomenclature xlink:type="simple" xlink:href="http://109.26.133.25/fbarbier/Modeling/GPAO_.html#3"/>
        <!-- 'xlink:label="..."' est un nom local pour créer 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>
</GPAO_>

Exemple (XPointer)

<!-- Accès au "name space" 'xlink' : -->
<GPAO_ xmlns:xlink="http://www.w3.org/1999/xlink">
    <Articles xlink:type="simple" xlink:href="http://109.26.133.25/fbarbier/Modeling/GPAO_.html#2">
        <author xlink:type="simple" xlink:href="http://109.26.133.25/fbarbier/Modeling/img/Common/Franck.jpg"/>
        <!-- 'xlink:show="embed"' : le lien s'ouvre de façon embarquée -->
        <Article xlink:type="simple" xlink:href="CD100.xml#xpointer(reference('CD100'))" xlink:show="embed"/>
        <!-- It relies on '<CH005 id="CH005">': -->
        <Article xlink:type="simple" xlink:href="CH005.xml#CH005" xlink:show="embed"/>
        <!-- ... -->
    </Articles>
    <Liens_de_nomenclature xlink:type="simple" xlink:href="http://109.26.133.25/fbarbier/Modeling/GPAO_.html#3">
        <Lien_de_nomenclature>
            <compose xlink:type="simple" xlink:href="CD100.xml#xpointer(reference('CD100'))"/>
            <composant xlink:type="simple" xlink:href="CH005.xml"/>
            <quantite_de_composition>1</quantite_de_composition>
        </Lien_de_nomenclature>
        <!-- ... -->
    </Liens_de_nomenclature>
    <Postes_de_charge xlink:type="simple" xlink:href="http://109.26.133.25/fbarbier/Modeling/GPAO_.html#5"/>
    <Gammes_de_fabrication xlink:type="simple" xlink:href="http://109.26.133.25/fbarbier/Modeling/GPAO_.html#6"/>
    <Mouvements_de_stock xlink:type="simple" xlink:href="http://109.26.133.25/fbarbier/Modeling/GPAO_.html#8"/>
</GPAO_>

Exemple (XInclude)

<?xml version="1.0" encoding="UTF-8"?>
<GPAO 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>
    <!-- Tous les éléments 'Lien_de_nomenclature' quelque soit le niveau dans l'arborescence : -->
    <xi:include href="Liens_de_nomenclature.xml" parse="xml" xpointer="element(//Lien_de_nomenclature"/>
</GPAO>

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>
    <Lien_de_nomenclature compose="CD100"
                  composant="CH005"
                  quantite_de_composition="1"/>
    <!-- ... -->
</Liens_de_nomenclature>
Persistance

Exemple JavaDB

CREATE TABLE GPAO_XML_data(XML_data XML);
INSERT INTO GPAO_XML_data(XML_data) VALUES(XMLPARSE(DOCUMENT '<GPAO>
    <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.-->
</GPAO>' PRESERVE WHITESPACE));
-- 'CLOB' <=> "Character Large OBject"
SELECT XMLSERIALIZE(XML_data AS CLOB) FROM GPAO_XML_data;