Files
JIMRI/help/fr/html/apps/DecoderPro/TransformDecoder.shtml
T
2026-06-17 14:00:51 +02:00

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 &gt; 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>
&lt;?transform-xslt href="http://jmri.org/xml/decoders/scom.xsl"?&gt;
</code>
<p>Ainsi, l'en-tête du modèle de décodeur ressemblerait à ceci :</p>
<div class="wide"><pre>
&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;?transform-xslt href="http://jmri.org/xml/decoders/scom.xsl"?&gt;
&lt;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" &gt;
&lt;decoder&gt;
...
</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>&lt;variables&gt;</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>
&lt;variables&gt;
&lt;variable CV="1" item="Short Address" default="100" &gt;
&lt;splitVal highCV="9" upperMask="XXXXXVVV" factor="1" offset="0" /&gt;
&lt;label&gt;Decoder Address:&lt;/label&gt;
&lt;tooltip&gt;Accessory decoder address. CV1 - LSB. CV9 - MSB.&lt;/tooltip&gt;
&lt;/variable&gt;
&lt;/variable&gt;
</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 &lt;volet&gt;</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>
&lt;xsl:template name="generate-masts"&gt;
&lt;xsl:variable name="cvStart" select="string(//pane[name/text() ='__Aspects']/display[@item='mastcount']/@tooltip)"/&gt;
&lt;xsl:variable name="outputs" select="string(//pane[name/text() ='__Aspects']/display[@item='outputs']/@label)"/&gt;
&lt;xsl:for-each select="//pane[name/text() ='__Aspects']/display[@item='masts']/label"&gt;
...
&lt;/xsl:for-each&gt;
&lt;/xsl:template&gt;
</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>
&lt;xsl:template name="generate-masts"&gt;
&lt;xsl:param name="root"/&gt;
&lt;xsl:variable name="cvStart" select="string($root/display[@item='mastcount']/@tooltip)"/&gt;
&lt;xsl:variable name="outputs" select="string($root/display[@item='outputs']/@label)"/&gt;
&lt;xsl:for-each select="$root/display[@item='masts']/label"&gt;
...
&lt;/xsl:for-each&gt;
&lt;/xsl:template&gt;
</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>
&lt;xsl:call-template name="generate-masts"&gt;
&lt;xsl:with-param name="root" select="//pane[name/text() ='__Aspects']//display[position() = 1]/.."/&gt;
&lt;/xsl:call-template&gt;
</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>
&lt;xsl:variable name="root" select="//pane[name/text() = '__Aspects']//display[position() = 1]/.."/&gt;
</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>
&lt;display item="mastcount" label="15" tooltip="128"/&gt;
</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>
&lt;xsl:variable name="cvStart" select="string($root/display[@item='mastcount']/@tooltip)"/&gt;
</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>&lt;label&gt;</strong> sous-éléments d'un élément <strong>&lt;display&gt;</strong> :</p>
<div class="wide"><pre>
&lt;display item="masts" tooltip="512"&gt;
&lt;label&gt;0&lt;/label&gt;&lt;label&gt;1&lt;/label&gt;&lt;label&gt;2&lt;/label&gt;&lt;label&gt;3&lt;/label&gt;&lt;label&gt;4&lt;/label&gt;&lt;label&gt;5&lt;/label&gt;&lt;label&gt;6&lt;/label&gt;&lt;label&gt;7&lt;/label&gt;.
&lt;label&gt;8&lt;/label&gt;&lt;label&gt;9&lt;/label&gt;&lt;label&gt;10&lt;/label&gt;&lt;label&gt;11&lt;/label&gt;&lt;label&gt;12&lt;/label&gt;&lt;label&gt;13&lt;/label&gt;&lt;label&gt;14&lt;/label&gt;&lt;label&gt;15&lt;/label&gt;.
&lt;/affichage&gt;
</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>
&lt;xsl:template name="generate-panes"&gt;
&lt;xsl:param name="racine"/&gt;
&lt;xsl:for-each select="$root/display[@item='masts']/label"&gt;
&lt;xsl:variable name="mât" select="string(./text())"/&gt;
&lt;xsl:call-template name="mast-pane"&gt;
&lt;xsl:with-param name="root" select="$root"/&gt;
&lt;xsl:with-param name="mast" select="$mast"/&gt;
&lt;/xsl:call-template&gt;
&lt;/xsl:for-each&gt;
&lt;/xsl:template&gt;
</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, "&gt;"
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>
&lt;xsl:template name="generate-one-panes"&gt;
&lt;xsl:param name="root"/&gt;
&lt;xsl:param name="index"/&gt;
&lt;xsl:variable name="mast" select="string($root/display[@item='masts']/label[position() = $index]/text())"/&gt;
&lt;xsl:call-template name="mast-pane"&gt;
&lt;xsl:with-param name="root" select="$root"/&gt;
&lt;xsl:with-param name="mast" select="$mast"/&gt;
&lt;/xsl:call-template&gt;
&lt;/xsl:template&gt;
</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>
&lt;xsl:template name="generate-panes"&gt;
&lt;xsl:param name="root"/&gt;
<strong>&lt;-- The loop count is controlled by the number of <em>label</em> variables --&gt;</strong>
&lt;xsl:for-each select="$root/display[@item='masts']/label"&gt;
&lt;xsl:variable name="mast" select="string(./text())"/&gt;
&lt;xsl:call-template name="mast-pane"&gt;
&lt;xsl:with-param name="root" select="$root"/&gt;
&lt;xsl:with-param name="mast" select="$mast"/&gt;
<strong>&lt;-- We use the current label's element <em>position</em> to derive the
"loop control variable" value --&gt;</strong>
&lt;xsl:with-param name="index" select="./position()"/&gt;
&lt;/xsl:call-template&gt;
&lt;/xsl:for-each&gt;
&lt;/xsl:template&gt;
</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>
&lt;xsl:template name="AllLEDGroups"&gt;
<strong>&lt;-- 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 --&gt;</strong>.
&lt;xsl:param name="CV1" select="633"/&gt;
&lt;xsl:param name="CV2" select="513"/&gt;
&lt;xsl:param name="CV3" select="537"/&gt;
<strong>&lt;-- C'est la variable de contrôle de la boucle --&gt;</strong>.
&lt;xsl:param name="index" select="1"/&gt;
<strong>&lt;!-- La ligne suivante contrôle le nombre --&gt;</strong>
&lt;xsl:if test="24 &gt;= $index"&gt;
&lt;xsl:call-template name="OneLEDGroup"&gt;
&lt;xsl:with-param name="CV1" select="$CV1"/&gt;
&lt;xsl:with-param name="CV2" select="$CV2"/&gt;
&lt;xsl:with-param name="CV3" select="$CV3"/&gt;
&lt;xsl:with-param name="index" select="$index"/&gt;
&lt;/xsl:call-template&gt;
&lt;-- itérer jusqu'à ce que ce soit fait --&gt;
<strong>&lt;-- 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 &gt; 24 --&gt;</strong>.
&lt;xsl:call-template name="AllLEDGroups"&gt;
&lt;xsl:with-param name="CV1" select="$CV1 +1"/&gt;
&lt;xsl:with-param name="CV2" select="$CV2 +1"/&gt;
&lt;xsl:with-param name="CV3" select="$CV3 +2"/&gt;
<strong>&lt;-- S'appelle lui-même, mais avec la variable de contrôle un plus haut, donc en comptant
le nombre de cycles--&gt;</strong>
&lt;xsl:with-param name="index" select="$index+1"/&gt;
&lt;/xsl:call-template&gt;
&lt;/xsl:if&gt;
&lt;/xsl:template&gt;
</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>
&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;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"&gt;
&lt;xsl:output method="xml" encoding="utf-8" indent="yes"/&gt;
&lt;xsl:strip-space elements=""/&gt;
&lt;xsl:preserve-space elements="text"/&gt;
&lt;/xsl:stylesheet&gt;
</pre>
<p>Ce qui suit va <strong>copier les éléments, et leurs attributs</strong> vers la sortie :</p>
<pre>
&lt;xsl:template match="@*|node()"&gt;
&lt;xsl:copy&gt;
&lt;xsl:apply-templates select="@*|node()"/&gt;
&lt;/xsl:copy&gt;
&lt;/xsl:template&gt;
</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>&lt;variables&gt;</code>. La feuille de style peut ensuite <strong>appliquer les
variables générées</strong> à la fin :</p>
<div class="wide"><pre>
&lt;xsl:template match="variables"&gt;
&lt;variables&gt;
&lt;xsl:copy-of select="node()"/&gt;
&lt;-- instructions d'appel de modèle, qui génèrent le contenu ; l'exemple suit --&gt;
&lt;xsl:call-template name="generate-masts"&gt;
&lt;xsl:with-param name="root" select="//pane[name/text() = '__Aspects']//display[position() = 1]/.."/&gt;
&lt;/xsl:call-template&gt;
&lt;xsl:call-template name="generate-aspects"&gt;
&lt;xsl:with-param name="root" select="//pane[name/text() = '__Aspects']//display[position() = 1]/.."/&gt;
&lt;/xsl:call-template&gt;
&lt;/variables&gt;
&lt;/xsl:template&gt;
</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>
&lt;xsl:template match="pane[name='__Aspects']" priority="100"&gt;
&lt;-- instructions d'appel de modèle pour les groupes individuels de panneaux à générer ; l'exemple suit --&gt;.
&lt;xsl:call-template name="generate-panes"&gt;
&lt;xsl:with-param name="root" select="//pane[name/text() = '__Aspects']//display[position() = 1]/.."/&gt;
&lt;/xsl:call-template&gt;
&lt;/xsl:template&gt;
</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>&lt;pane&gt;</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>
&lt;variable item="Aspect{$index} LED1 Out" CV="{$CV2}" mask="XXXVVVVV" default="0"&gt;
&lt;xi:include href="http://jmri.org/xml/decoders/tvd/LedOutput.xml"/&gt;
&lt;/variable&gt;
</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>
&lt;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>.
&gt;
</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>