532 lines
29 KiB
Plaintext
532 lines
29 KiB
Plaintext
<!DOCTYPE html>
|
|
<html lang="fr">
|
|
<head>
|
|
<meta name="generator" content="HTML Tidy for HTML5 for Apple macOS version 5.8.0">
|
|
<!-- Copyright Bob Jacobsen 2008 -->
|
|
<title>JMRI: DecoderPro User Guide - Use XSLT Transformation for complex decoders File</title>
|
|
<!--#include virtual="/help/fr/parts/Style.shtml" -->
|
|
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
|
</head>
|
|
|
|
<body>
|
|
<!--#include virtual="/help/fr/parts/Header_fr.shtml" -->
|
|
|
|
<div id="mBody">
|
|
<!--#include virtual="Sidebar.shtml" -->
|
|
|
|
<div id="mainContent">
|
|
<h1>JMRI : Guide d'Utilisation de DecoderPro</h1>
|
|
|
|
<h2>Utiliser la transformation XSLT pour les décodeurs complexes</h2>
|
|
|
|
<p>Certains décodeurs contiennent des <strong>blocs répétés</strong> de CV, par exemple pour
|
|
définir le comportement de plusieurs accessoires, chacun contrôlé par plusieurs CVs. Un
|
|
décodeur d'aiguillages avancé peut par exemple définir plusieurs chemins, contenant chacun
|
|
plusieurs aiguillages et leur position souhaitée pour former le chemin de déplacement sur le
|
|
réseau.</p>
|
|
|
|
<p>Bien que le fichier du décodeur doive définir des dizaines, voire des centaines, de CV et
|
|
leur apparence sur les volets au total, seule une fraction des CV ou des affichages sont
|
|
réellement uniques : le reste peut être <strong>généré à partir d'un modèle</strong>. Bien
|
|
que la création d'un modèle et la recette de transformation soit <strong>beaucoup plus
|
|
complexe</strong> que de copier-coller des définitions de CV, l'avantage est <strong>une
|
|
maintenance beaucoup plus facile</strong>. Une fois que le plus dur est fait : chaque
|
|
changement se propage de manière cohérente à toutes les parties générées.</p>
|
|
|
|
<p>Pour donner un exemple de simplification possible - prenons le fichier du décodeur.
|
|
<code>Public_Domain_dccdoma_ARD_SCOM_MX.xm</code>. Il configure un décodeur, capable
|
|
d'afficher les aspects des signaux sur plusieurs mâts de signalisation. La configuration
|
|
contient plus de 500 CV - pourtant l'idée de base de la configuration est très simple :</p>
|
|
|
|
<ul>
|
|
<li>un aspect par défaut pour chaque mât de signaux</li>
|
|
|
|
<li>pour chaque mât de signaux ET pour chacun des 32 aspects possibles, le nombre de
|
|
signaux à afficher, interprété par le décodeur lui-même</li>
|
|
</ul>
|
|
|
|
<p>Quelques statistiques :</p>
|
|
|
|
<ul>
|
|
<li>Définition originale du décodeur : <strong>870 kByte</strong> 20608 lignes.</li>
|
|
|
|
<li>Fichier de feuilles de style : <strong>12 kByte</strong>, 257 lignes.</li>
|
|
|
|
<li>Modèle de fichier décodeur : <strong>18 kByte</strong>, 390 lignes.</li>
|
|
</ul>
|
|
|
|
<p>Pour JMRI lui-même ou la vitesse de fonctionnement du DecoderPro, ces deux approches sont
|
|
les mêmes : le modèle de fichier est transformé (expansé) en interne en définition de
|
|
décodage en XML et traité comme s'il était écrit entièrement à la main. Pour la
|
|
<strong>maintenance</strong>, il est bien plus facile de maintenir ~600 lignes de XML que
|
|
20600.</p>
|
|
|
|
<p>JMRI fournit une option pour appliquer une <strong>feuille de style XSLT</strong> à un
|
|
fichier décodeur, <strong>avant</strong> que le fichier soit chargé dans DecoderPro et avant
|
|
qu'il soit interprété comme variables et panneaux de CV. Cela permet d'écrire à la main des
|
|
définitions de CV uniques et leurs panneaux, et <strong>d'ajouter du contenu généré</strong>
|
|
le cas échéant.</p>
|
|
|
|
<h2>Exemples de fichiers</h2>
|
|
|
|
<p>Pour illustrer les techniques décrites ici, quelques fichiers d'exemple sont fournis ;
|
|
tous les fichiers sont sous licence GNU GPL.</p>
|
|
|
|
<ul>
|
|
<li><strong><a href="resources/decoder-template.xml">decoder-template.xml</a></strong> -
|
|
l'<strong>exemple</strong> de définition du décodeur.</li>
|
|
|
|
<li><strong><a href="resources/scom.xsl">scom.xsl</a></strong> - la feuille de style</li>
|
|
</ul>
|
|
|
|
<p>Le modèle de décodeur doit être placé dans le dossier <strong>xml/decoders</strong> de
|
|
l'installation de JMRI. Il est <strong>basé sur le modèle de Petr Sidlo. dccdoma.cz -
|
|
ARD-SCOM-MX decoder</strong> - génère les mêmes panneaux de décodeur que l'original (à partir
|
|
de 12/2019). La feuille de style (<strong>scom.xsl</strong>) doit être placée également dans
|
|
le dossier <strong><code>xml/decoder</code></strong> de l'installation JMRI.</p>
|
|
|
|
<p>Le modèle peut être traité à partir de la ligne de commande pour générer le XML du
|
|
décodeur, afin que vous puissiez inspecter les effets de la modification de la feuille de
|
|
style et/ou des données intégrées dans le modèle de décodeur. La ligne de commande pour Linux
|
|
:</p>
|
|
|
|
<code>
|
|
xsltproc scom.xsl decoder-template.xml > decoder-gen.xml
|
|
</code>
|
|
<p>N'oubliez pas de remplacer les fichiers par leurs noms ou emplacements réels ; pour
|
|
expérimenter à partir de la ligne de commande, le mieux est de placer le modèle de fichier du
|
|
décodeur ET sa feuille de style dans un certain répertoire et d'y travailler. Plus tard,
|
|
déplacez la feuille de style et le modèle dans les dossiers comme décrit ci-dessus.</p>
|
|
|
|
<h2>Appliquer la feuille de style au fichier décodeur.</h2>
|
|
|
|
<p>Une <strong>instruction pour traiter le fichier comme un modèle</strong> doit être
|
|
présente dans le fichier, afin d'agir comme un modèle. Sinon, JMRI le prendrait comme une
|
|
définition de décodeur "ordinaire" - tous les éléments d'affichage (voir ci-dessous)
|
|
"détournés" pour contenir les données pour le traitement du modèle. apparaîtraient dans
|
|
l'interface utilisateur !</p>
|
|
|
|
<p>L'instruction de traitement doit apparaître au début de la définition du décodeur :</p>
|
|
|
|
<code>
|
|
<?transform-xslt href="http://jmri.org/xml/decoders/scom.xsl"?>
|
|
</code>
|
|
<p>Ainsi, l'en-tête du modèle de décodeur ressemblerait à ceci :</p>
|
|
|
|
<div class="wide"><pre>
|
|
<?xml version="1.0" encoding="utf-8"?>
|
|
<?transform-xslt href="http://jmri.org/xml/decoders/scom.xsl"?>
|
|
<decoder-config xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
xsi:noNamespaceSchemaLocation="http://jmri.org/xml/schema/decoder.xsd" showEmptyPanes="no" >
|
|
<decoder>
|
|
...
|
|
</pre></div>
|
|
|
|
<h2>Fournir des métadonnées à la feuille de style</h2>
|
|
|
|
<p>L'un des points critiques est de savoir comment générer les numéros de CV ou d'autres
|
|
variables : Le langage XSLT fournit des calculs numériques simples, mais les fonctions plus
|
|
sophistiquées fonctions ne sont généralement pas accessibles (par défaut). Certains contenus
|
|
générés sont est composé d'une liste de chaînes de caractères (c'est-à-dire que les noms des
|
|
aspects du signal sont répétés pour chaque mât de signal). chaque mât de signal), et nous
|
|
devons fournir une telle entrée à la feuille de style. Le fichier décodeur est <strong>la
|
|
seule entrée</strong> fournie pour la feuille de style par le cadre JMRI.</p>
|
|
|
|
<p>Le fichier de modèle de décodeur est <strong>encore interprété comme une définition de
|
|
décodeur</strong> et doit adhérer strictement au schéma XML <code>decoder.xsd</code>. Pour
|
|
les parties que nous voulons générer à partir du modèle, les éléments prescrits doivent être
|
|
<strong>consciencieusement détournés</strong> pour fournir des informations sur le
|
|
modèle.</p>
|
|
|
|
<ul>
|
|
<li>des points d'ancrage, où le contenu généré sera inséré</li>
|
|
<li>des données d'entrée pour la feuille de style</li>
|
|
</ul>
|
|
|
|
<p>Il y a plusieurs façons d'aborder le problème, je vais présenter une façon que je
|
|
considère comme plus ou moins propre (bien qu'elle abuse d'éléments pour fournir des données
|
|
différentes de celles qu'ils devraient formellement !). Le guide doit être vu comme une
|
|
recommandation pour garder les décodeurs générés quelque peu cohérents. S'il vous plaît
|
|
<strong>n'hésitez pas à contribuer et à fournir des approches plus simples</strong>.</p>
|
|
|
|
<h3>Ajout de variables</h3>
|
|
|
|
<p>Le simple ajout de variables est simple, et ne nécessite <strong>aucun
|
|
placeholder</strong> supplémentaire dans le fichier du décodeur. Cependant, l'élément
|
|
<strong><code><variables></code></strong> doit être présent, afin que la technique
|
|
décrite ci-dessous pour générer des variables fonctionne. L'élément pourrait ressembler à cet
|
|
exemple :</p>
|
|
|
|
<div class="wide"><pre>
|
|
<variables>
|
|
<variable CV="1" item="Short Address" default="100" >
|
|
<splitVal highCV="9" upperMask="XXXXXVVV" factor="1" offset="0" />
|
|
<label>Decoder Address:</label>
|
|
<tooltip>Accessory decoder address. CV1 - LSB. CV9 - MSB.</tooltip>
|
|
</variable>
|
|
</variable>
|
|
</pre></div>
|
|
<p>Le contenu supplémentaire généré sera <strong>appliqué</strong> à l'intérieur de cet
|
|
élément.</p>
|
|
|
|
<h3>Volet du détenteur de données</h3>
|
|
|
|
<p>Alors que la définition de l'élément <strong><code>variable</code></strong> est plutôt
|
|
stricte, les définitions de l'interface utilisateur semblent les plus détendues, donc nous en
|
|
en abusons. La section suivante décrit quelques types de données typiques, comment elles
|
|
peuvent être <strong>représentées</strong> dans le décodeur afin que le texte soit conforme
|
|
aux règles obligatoires de <code>decoder.xsd</code>. Et enfin comment ils peuvent être
|
|
<strong>accessibles</strong> à partir de la feuille de style.</p>
|
|
|
|
<p><strong>Toutes les données</strong> (pas les définitions des panneaux de l'interface
|
|
utilisateur) seront placées dans un <strong>élément unique <volet></strong>. Le nom du
|
|
volet peut être arbitraire, mais doit être <strong>unique</strong> afin qu'un volet défini
|
|
par le système ou un <strong>vrai</strong> volet personnalisé ne soit pas remplacé
|
|
accidentellement. Dans notre exemple, le nom <strong>__Aspects</strong> est utilisé. Je
|
|
recommande de préfixer le nom du panneau par deux traits de soulignement. Le nom nom du volet
|
|
<strong>doit être utilisé</strong> dans les sélecteurs - donc si vous inventez votre propre
|
|
nom, remplacez le texte des exemples par le nom de votre choix.</p>
|
|
|
|
<h4>Passage de la racine des données</h4>
|
|
|
|
<p>Chaque fois, qu'une valeur doit être lue par la feuille de style, elle doit être
|
|
<strong>sélectionnée</strong> par une expression XPath. Par exemple :</p>
|
|
|
|
<div class="wide"><pre>
|
|
<xsl:template name="generate-masts">
|
|
<xsl:variable name="cvStart" select="string(//pane[name/text() ='__Aspects']/display[@item='mastcount']/@tooltip)"/>
|
|
<xsl:variable name="outputs" select="string(//pane[name/text() ='__Aspects']/display[@item='outputs']/@label)"/>
|
|
<xsl:for-each select="//pane[name/text() ='__Aspects']/display[@item='masts']/label">
|
|
...
|
|
</xsl:for-each>
|
|
</xsl:template>
|
|
</pre></div>
|
|
|
|
<p>Le sélecteur contient toujours la partie préfixe commun, qui trouve le volet "détenteur de
|
|
données" dans le fichier modèle du décodeur. Nous pouvons économiser la frappe en passant cet
|
|
élément comme <strong>paramètre</strong> :</p>
|
|
|
|
<div class="wide"><pre>
|
|
<xsl:template name="generate-masts">
|
|
<xsl:param name="root"/>
|
|
<xsl:variable name="cvStart" select="string($root/display[@item='mastcount']/@tooltip)"/>
|
|
<xsl:variable name="outputs" select="string($root/display[@item='outputs']/@label)"/>
|
|
<xsl:for-each select="$root/display[@item='masts']/label">
|
|
...
|
|
</xsl:for-each>
|
|
</xsl:template>
|
|
</pre></div>
|
|
<p>L'invocation d'un tel modèle générateur <strong>doit passer le paramètre</strong> :</p>
|
|
|
|
<div class="wide"><pre>
|
|
<xsl:call-template name="generate-masts">
|
|
<xsl:with-param name="root" select="//pane[name/text() ='__Aspects']//display[position() = 1]/.."/>
|
|
</xsl:call-template>
|
|
</pre></div>
|
|
<p>Notez le suffixe étrange. C'est parce que les éléments d'affichage ne peuvent pas être
|
|
imbriqués directement dans l'élément <strong>pane</strong>, ils doivent être dans une sorte
|
|
de colonne, de ligne, de groupe, etc. Le sélecteur étrange à la fin trouvera le
|
|
<strong>premier élément d'affichage imbriqué</strong> et prendra son <strong>élément
|
|
parent</strong> comme racine de données.</p>
|
|
|
|
<p>Une <strong>variable globale</strong> peut être définie de manière similaire - placez
|
|
directement cet élément comme élément de premier niveau dans la feuille de style :</p>
|
|
|
|
<code>
|
|
<xsl:variable name="root" select="//pane[name/text() = '__Aspects']//display[position() = 1]/.."/>
|
|
</code>
|
|
<p>Les templates peuvent maintenant référencer la racine des données par la seule expression
|
|
<strong>$root</strong>.</p>
|
|
|
|
<h4>Constantes, valeurs max/min, valeurs uniques.</h4>
|
|
|
|
<p>Une constante peut être utilisée, par exemple, comme un nombre maximum d'éléments, un
|
|
numéro de CV spécifique, .... Je recommande l'utilisation de l'élément
|
|
<strong>display</strong>. pour définir une constante. Cet élément a deux attributs de forme
|
|
libre : <strong>label</strong> et <strong>tooltip</strong>. Nous pouvons donc définir en fait
|
|
deux constantes dans un seul élément ! Cela peut être utile, s'il y a des valeurs étroitement
|
|
liées entre elles, par exemple. Les constantes, qui définissent le nombre maximum d'aspects
|
|
gérés par l'interface utilisateur et le CV de départ peuvent être écrits comme :</p>
|
|
|
|
<code>
|
|
<display item="mastcount" label="15" tooltip="128"/>
|
|
</code>
|
|
<p>Le "<strong>mastcount</strong>" est un nom arbitraire (mais unique). Nommez-le ainsi après
|
|
la signification de la valeur pour votre décodeur. Il sera utilisé dans les
|
|
<em>sélecteurs</em> pour accéder à la valeur comme ceci :</p>
|
|
|
|
<code>
|
|
<xsl:variable name="cvStart" select="string($root/display[@item='mastcount']/@tooltip)"/>
|
|
</code>
|
|
<ul>
|
|
<li><strong>$root</strong> est le paramètre / variable qui contient la racine des
|
|
données.</li>
|
|
|
|
<li><strong>mastcount</strong> est le nom de l'élément <strong>display</strong> - votre
|
|
valeur.</li>
|
|
|
|
<li><strong>@tooltip</strong> signifie que le sélecteur lira l'attribut
|
|
<strong>tooltip</strong>. Vous pouvez utiliser @label pour accéder à l'autre.</li>
|
|
</ul>
|
|
|
|
<h4>Enumérations, séquences, listes</h4>
|
|
|
|
<p>Il faut parfois générer une CV (variable, élément d'affichage) pour, par exemple, chaque
|
|
sortie identifiée par un nom, ou un numéro. La liste peut être codée comme une série de
|
|
<strong><label></strong> sous-éléments d'un élément <strong><display></strong> :</p>
|
|
|
|
<div class="wide"><pre>
|
|
<display item="masts" tooltip="512">
|
|
<label>0</label><label>1</label><label>2</label><label>3</label><label>4</label><label>5</label><label>6</label><label>7</label>.
|
|
<label>8</label><label>9</label><label>10</label><label>11</label><label>12</label><label>13</label><label>14</label><label>15</label>.
|
|
</affichage>
|
|
</pre></div>
|
|
<p>Nous pouvons ensuite soit itérer ces éléments un par un, soit y accéder par
|
|
indice/position selon les besoins. Les exemples suivants sélectionnent les élément de données
|
|
<strong>mâts</strong> sous la racine des données (voir ci-dessus pour la racine des données).
|
|
Pour <strong>chacun des éléments</strong> il appelle un autre modèle (non représenté ici), et
|
|
transmet la valeur de l'élément (encodée dans le contenu de l'élément label) au modèle en
|
|
tant que paramètre <strong>mast</strong> :</p>
|
|
|
|
<div class="wide"><pre>
|
|
<xsl:template name="generate-panes">
|
|
<xsl:param name="racine"/>
|
|
|
|
<xsl:for-each select="$root/display[@item='masts']/label">
|
|
<xsl:variable name="mât" select="string(./text())"/>
|
|
<xsl:call-template name="mast-pane">
|
|
<xsl:with-param name="root" select="$root"/>
|
|
<xsl:with-param name="mast" select="$mast"/>
|
|
</xsl:call-template>
|
|
</xsl:for-each>
|
|
</xsl:template>
|
|
</pre></div>
|
|
<p>Notez, que l'élément <strong>content</strong> est utilisé comme valeur ici - cela permet
|
|
d'utiliser tous les caractères gênants comme les guillemets, les doubles guillemets, ">"
|
|
et d'autres caractères non autorisés dans les attributs.</p>
|
|
|
|
<p>Les éléments individuels peuvent être accédés par leur index (qui est passé en paramètre)
|
|
:</p>
|
|
|
|
<div class="wide"><pre>
|
|
<xsl:template name="generate-one-panes">
|
|
<xsl:param name="root"/>
|
|
<xsl:param name="index"/>
|
|
|
|
<xsl:variable name="mast" select="string($root/display[@item='masts']/label[position() = $index]/text())"/>
|
|
<xsl:call-template name="mast-pane">
|
|
<xsl:with-param name="root" select="$root"/>
|
|
<xsl:with-param name="mast" select="$mast"/>
|
|
</xsl:call-template>
|
|
</xsl:template>
|
|
</pre></div>
|
|
<p>Vous pouvez facilement utiliser la liste d'étiquettes ci-dessus pour faire une boucle de 1
|
|
à 15, ce qui n'est directement pas possible en XSLT. Au lieu de contrôler la boucle par une
|
|
<em>variable d'indice de contrôle</em>, nous contrôlons la boucle par <em>les données qui
|
|
doivent s'appliquer dans les itérations individuelles du cycle</em> et dériver la variable
|
|
d'index à partir d'elles. Voici l'exemple modifié :</p>
|
|
|
|
<div class="wide"><pre>
|
|
<xsl:template name="generate-panes">
|
|
<xsl:param name="root"/>
|
|
<strong><-- The loop count is controlled by the number of <em>label</em> variables --></strong>
|
|
<xsl:for-each select="$root/display[@item='masts']/label">
|
|
<xsl:variable name="mast" select="string(./text())"/>
|
|
<xsl:call-template name="mast-pane">
|
|
<xsl:with-param name="root" select="$root"/>
|
|
<xsl:with-param name="mast" select="$mast"/>
|
|
<strong><-- We use the current label's element <em>position</em> to derive the
|
|
"loop control variable" value --></strong>
|
|
<xsl:with-param name="index" select="./position()"/>
|
|
</xsl:call-template>
|
|
</xsl:for-each>
|
|
</xsl:template>
|
|
</pre></div>
|
|
|
|
<h3>Cycles et boucles</h3>
|
|
|
|
<p>Le langage XSLT est un langage déclaratif, et les variables, une fois assignées, ne
|
|
peuvent pas être modifiées - il n'a donc pas de construction de <strong>boucle</strong> comme
|
|
le font la plupart des langages de programmation. Parfois, un cycle peut être remplacé de
|
|
manière plus illustrative par une itération sur le contenu. Parfois, ce n'est pas possible :
|
|
vraiment un certain nombre fixe d'itérations doit être fait, comme <strong>générer des CV
|
|
séquentiels</strong> avec la même structure - seuls le numéro de séquence et l'indice de la
|
|
fonction représentée différeront.</p>
|
|
|
|
<p>Cela peut être fait par la <strong>tail recursion</strong>( récursion de queue), qui
|
|
remplace les boucles en invoquant un modèle à partir de ce modèle lui-même. La seule mise en
|
|
garde est que le nombre d'itérations est <strong>limité</strong> à environ 100 ( ?), avant
|
|
que l'espace de la pile ne soit épuisé. L'exemple se trouve dans <code><a href=
|
|
"https://github.com/JMRI/JMRI/blob/master/xml/decoders/TamValleyDepot_QuadLn_S_11.xsl">TamsValleyDepot_QuadLn_s_11.xsl</a></code>,
|
|
cherchez le modèle <code>AllLEDGroups</code> :</p>
|
|
|
|
<div class="wide"><pre>
|
|
<xsl:template name="AllLEDGroups">
|
|
<strong><-- Utilisez l'attribut <em>select=""</em> pour choisir une valeur initiale pour le cycle.
|
|
S'applique si le modèle n'obtient pas de paramètre lors de la (première) invocation --></strong>.
|
|
<xsl:param name="CV1" select="633"/>
|
|
<xsl:param name="CV2" select="513"/>
|
|
<xsl:param name="CV3" select="537"/>
|
|
<strong><-- C'est la variable de contrôle de la boucle --></strong>.
|
|
<xsl:param name="index" select="1"/>
|
|
<strong><!-- La ligne suivante contrôle le nombre --></strong>
|
|
<xsl:if test="24 >= $index">
|
|
<xsl:call-template name="OneLEDGroup">
|
|
<xsl:with-param name="CV1" select="$CV1"/>
|
|
<xsl:with-param name="CV2" select="$CV2"/>
|
|
<xsl:with-param name="CV3" select="$CV3"/>
|
|
<xsl:with-param name="index" select="$index"/>
|
|
</xsl:call-template>
|
|
<-- itérer jusqu'à ce que ce soit fait -->
|
|
<strong><-- Le <em>if</em> quelques lignes plus haut fait en sorte que, ce <em>modèle d'appel</em>
|
|
ne sera pas exécuté pour i > 24 --></strong>.
|
|
<xsl:call-template name="AllLEDGroups">
|
|
<xsl:with-param name="CV1" select="$CV1 +1"/>
|
|
<xsl:with-param name="CV2" select="$CV2 +1"/>
|
|
<xsl:with-param name="CV3" select="$CV3 +2"/>
|
|
<strong><-- S'appelle lui-même, mais avec la variable de contrôle un plus haut, donc en comptant
|
|
le nombre de cycles--></strong>
|
|
<xsl:with-param name="index" select="$index+1"/>
|
|
</xsl:call-template>
|
|
</xsl:if>
|
|
</xsl:template>
|
|
</pre></div>
|
|
|
|
<h2>Création de la feuille de style</h2>
|
|
|
|
<h3>Un "boilerplate"</h3>
|
|
|
|
<p>Le modèle est susceptible de contenir des instructions de type " boilerplate ". Les
|
|
déclarations suivantes devraient se trouver en haut, définissant comment la sortie sera
|
|
générée :</p>
|
|
|
|
<pre>
|
|
<?xml version="1.0" encoding="utf-8"?>
|
|
<xsl:stylesheet version="1.0"
|
|
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
|
xmlns:db="http://docbook.org/ns/docbook"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude"
|
|
|
|
exclude-result-prefixes="db">
|
|
|
|
|
|
<xsl:output method="xml" encoding="utf-8" indent="yes"/>
|
|
<xsl:strip-space elements=""/>
|
|
<xsl:preserve-space elements="text"/>
|
|
</xsl:stylesheet>
|
|
</pre>
|
|
<p>Ce qui suit va <strong>copier les éléments, et leurs attributs</strong> vers la sortie :</p>
|
|
|
|
<pre>
|
|
<xsl:template match="@*|node()">
|
|
<xsl:copy>
|
|
<xsl:apply-templates select="@*|node()"/>
|
|
</xsl:copy>
|
|
</xsl:template>
|
|
</pre>
|
|
|
|
<h3>Générer du contenu aux points d'insertion</h3>
|
|
|
|
<p>Les définitions de variables sont généralement générées par la feuille de style. Les
|
|
variables de base et fixes doivent être fournies, comme d'habitude, dans l'élément
|
|
<code><variables></code>. La feuille de style peut ensuite <strong>appliquer les
|
|
variables générées</strong> à la fin :</p>
|
|
|
|
<div class="wide"><pre>
|
|
<xsl:template match="variables">
|
|
<variables>
|
|
<xsl:copy-of select="node()"/>
|
|
<-- instructions d'appel de modèle, qui génèrent le contenu ; l'exemple suit -->
|
|
<xsl:call-template name="generate-masts">
|
|
<xsl:with-param name="root" select="//pane[name/text() = '__Aspects']//display[position() = 1]/.."/>
|
|
</xsl:call-template>
|
|
|
|
<xsl:call-template name="generate-aspects">
|
|
<xsl:with-param name="root" select="//pane[name/text() = '__Aspects']//display[position() = 1]/.."/>
|
|
</xsl:call-template>
|
|
</variables>
|
|
</xsl:template>
|
|
</pre></div>
|
|
<p>Notez que, dans cet exemple, l'élément <code>pane</code> avec un nom spécial
|
|
(<code>__Aspects</code>) est utilisé comme un support pour les données d'entrée pour la
|
|
génération. Alors que <code>//pane[name/text() == '__Aspects']</code> sélectionne le support
|
|
de données, l'élément <code>//display[</code> est utilisé comme support de données pour la
|
|
génération. <code>//display[position() = 1]/..</code> sélectionne un élément
|
|
<strong>intérieur</strong> à l'élément XML du volet porteur. <strong>Faites attention aux
|
|
erreurs de frappe</strong> dans les chaînes de caractères, sinon les clauses de sélection
|
|
sélectionnent des données vides, et rien - ou un contenu invalide - ne sera généré.</p>
|
|
|
|
<p>Pour les <strong>Panneaux d'interface</strong>, je recommande de
|
|
<strong>remplacer</strong> le détenteur des données par la séquence des panneaux générés.
|
|
Dans mon exemple , les données sont fournies par le panneau nommé <strong>__Aspects</strong>,
|
|
que nous ne voulons absolument pas <strong>afficher</strong> dans DecoderPro car ce ... n'est
|
|
pas un panneau de l'interface utilisateur, après tout. Ce qui suit va
|
|
<strong>remplacer</strong> le support de données (un VPanneau de niveau supérieur) avec des
|
|
panneaux générés par la feuille de style :</p>
|
|
|
|
<div class="wide"><pre>
|
|
<xsl:template match="pane[name='__Aspects']" priority="100">
|
|
<-- instructions d'appel de modèle pour les groupes individuels de panneaux à générer ; l'exemple suit -->.
|
|
<xsl:call-template name="generate-panes">
|
|
<xsl:with-param name="root" select="//pane[name/text() = '__Aspects']//display[position() = 1]/.."/>
|
|
</xsl:call-template>
|
|
</xsl:template>
|
|
</pre></div>
|
|
<p>La clause <code>match</code> va réagir sur l'élément <code>__Aspect</code> du volet du
|
|
détenteur de données, mais contrairement aux variables point d'insertion, <strong>aucune
|
|
instruction de copie n'est présente</strong>. L'ancien contenu sera donc jeté (l'élément
|
|
<code><pane></code> entier !), remplacé par les éléments que les instructions
|
|
<code>call-template</code> génèrent.</p>
|
|
|
|
<h2>Utilisation des fragments XML</h2>
|
|
|
|
<p>Si une partie du contenu généré <strong>ne change pas</strong> d'un endroit à l'autre, il
|
|
est possible de la préparer comme un <strong>fragments XML</strong> à être inclus : il ne
|
|
fera pas partie de la feuille de style XSL avec toutes ces étranges instructions
|
|
<em>xsl:xxx</em>, mais sera stocké comme un morceau séparé, petit et propre morceau de XML.
|
|
Cela peut être utile pour les <strong>valeurs de choix</strong>, ou même les <strong>panneaux
|
|
d'interface utilisateur</strong> répétés sans contenu variable. Un exemple d'utilisation est
|
|
à nouveau dans <code><a href=
|
|
"https://github.com/JMRI/JMRI/blob/master/xml/decoders/TamValleyDepot_QuadLn_S_11.xsl">TamsValleyDepot_QuadLn_s_11.xsl</a></code>.
|
|
(LedPaneHeader)</p>
|
|
|
|
<p>Les variables individuelles sont générées à l'aide de <em>xsl:template</em>, mais la
|
|
partie valeur, la plupart du temps un <em>choix</em> est incluse depuis un fichier séparé.
|
|
Notez que le <em>xi:include</em> sera généré dans le XML résultant, donc c'est le lecteur du
|
|
panneau DecoderPro, qui fait l'inclusion du contenu, et non le générateur. Le modèle
|
|
substitue les parties variables de la définition :</p>
|
|
|
|
<div class="wide"><pre>
|
|
<variable item="Aspect{$index} LED1 Out" CV="{$CV2}" mask="XXXVVVVV" default="0">
|
|
<xi:include href="http://jmri.org/xml/decoders/tvd/LedOutput.xml"/>
|
|
</variable>
|
|
</pre></div>
|
|
<p>Il y a deux choses importantes. Lorsque vous utilisez le préfixe <em>xi:</em>, ce
|
|
<strong>préfixe doit être déclaré</strong> en haut du document (peut être dans n'importe quel
|
|
élément parent, mais par convention, les préfixes sont rassemblés au début). Utilisez
|
|
exactement la même URL (valeur de l'attribut), sinon l'instruction ne sera pas reconnue.</p>
|
|
|
|
<div class="wide"><pre>
|
|
<xsl:stylesheet version="1.0"
|
|
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
|
xmlns:db="http://docbook.org/ns/docbook"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude" <strong>-- c'est la déclaration du préfixe</strong>.
|
|
>
|
|
</pre></div>
|
|
<p>Le deuxième problème est que le <em>xi:include</em> doit utiliser des URLs que JMRI est
|
|
capable de <strong>résoudre localement</strong>. Dans le cas contraire, le DecoderPro
|
|
tenterait de télécharger des parties de la définition depuis Internet, ce qui nécessite une
|
|
connexion en ligne - et est lent. Le préfixe <strong>http://jmri.org/xml</strong> est garanti
|
|
pour résoudre dans le répertoire <strong>xml</strong> de votre installation locale de JMRI.
|
|
Pour plus de cartographie, veuillez consulter les autres documents JMRI.</p>
|
|
|
|
<p>Traduction 2021-03-25</p>
|
|
<!--#include virtual="/help/fr/parts/Footer_fr.shtml" -->
|
|
</div>
|
|
<!-- close #mainContent -->
|
|
</div>
|
|
<!-- close #mBody -->
|
|
<script src="/js/help.js"></script>
|
|
</body>
|
|
</html>
|