Bonjour,
Dans le cadre d'un projet d'éditeur xml "générique" se basant sur un schéma relaxNG, j'ai besoin de déterminer pour chaque élément, quels élément-fils on peut ajouter.
Ce "calcul" dépend à la fois du schéma relaxNG et du document qui est édité (nombre d'occurence des éléments).
Le Schéma RelaxNG est restreint aux éléments suivants : start, element, attribute, text, group, interleave, oneOrMore, et ZeroOrMore.
par exemple :
<start name="A" >
<group>
<interleave>
<zeroOrMore>
<element name="B">
<attribute name="id"/>
</element>
</zeroOrMore>
<oneOrMore>
<element name="C">
<attribute name="id"/>
</element>
</oneOrMore>
</interleave>
</group>
<element name="Z" >
<attribute name="id"/>
</element>
</start>
Une transformation xslt me permet de générer une xsl qui, appliquée à un document xml quelquonque (respectant ce schéma) va afficher un formulaire web d'édition du document en question : on affiche chaque élément dans des <div> imbriqués (ainsi que les group).
en gros : schemaRelaxNG + genereEditionXSL.xsl ==> Edition.xsl (+ xml ==> formulaire html)
Et ce que j'ai du mal à faire c'est d'ajouter au début de chaque div la liste des bouton permettant d'ajouter des sous-éléments.
En fait, l'éditeur présente également une arborescence du document xml, quand on clique sur un noeud on affiche dans un frame, le formulaire d'édition du noeud choisi.
Autrement dit la xsl d'édition recoit en paramètre le xpath du noeud et n'applique que le template le concernant :
- j'utilise une fonction dyn:evaluate() définis dans une xsl importée.
- je génère un template pour chaque type de noeud (pour chaque élément du schéma).
Voici à quoi ressemble genereEditionXSL.xsl (je n'ai pas mis les "entêtes" xsl : celles du fichiers xsl généré sont ajoutées par script, avec le paramètre <xsl:param name="xpathNode"/>)
<xsl:template match="/">
<xsl:element name="xsl:template"><xsl:attribute name="match">/</xsl:attribute>
<html>
<head>...</head>
<body>
<xsl:element name="xsl:apply-templates">
<xsl:attribute name="select">dyn:evaluate(.,$xpathNode)</xsl:attribute>
</xsl:element>
</body>
</html>
</xsl:element>
<xsl:apply-templates select="//*" mode="createTemplate"/>
</xsl:template>
<!-- ****************************** CREATE TEMPLATE ****************************** -->
<xsl:template match="*" mode="createTemplate"/>
<xsl:template match="start" mode="createTemplate">
<xsl:element name="xsl:template">
<xsl:attribute name="match">/<xsl:value-of select="$STARTname"/></xsl:attribute>
<div>
<xsl:apply-templates select="*" mode="AddSubNodeButtons"/>
<xsl:apply-templates select="*" mode="SubNodeContent"/>
</div>
</xsl:element>
</xsl:template>
<xsl:template match="group" mode="createTemplate">
<div>
<xsl:apply-templates select="*" mode="AddSubNodeButtons"/>
<xsl:apply-templates select="*" mode="SubNodeContent"/>
</div>
</xsl:template>
<xsl:template match="element" mode="createTemplate">
<xsl:element name="xsl:template">
<xsl:attribute name="match">/<xsl:value-of select="$STARTname"/><xsl:for-each select="ancestor-or-self::element">/<xsl:value-of select="@name"/></xsl:for-each></xsl:attribute>
<div>
<xsl:apply-templates select="*" mode="AddSubNodeButtons"/>
<xsl:apply-templates select="*" mode="SubNodeContent"/>
</div>
</xsl:element>
</xsl:template>
<!-- ****************************** SUBNODE CONTENT ****************************** -->
<xsl:template match="element" mode="SubNodeContent">
<xsl:apply-templates select="*" mode="SubNodeContent"/>
</xsl:template>
<xsl:template match="element" mode="SubNodeContent">
<xsl:element name="xsl:apply-templates">
<xsl:attribute name="select"><xsl:value-of select="@name"/></xsl:attribute>
</xsl:element>
</xsl:template>
<!-- ****************************** ADD SUBNODE BUTTONS ****************************** -->
<xsl:template match="*" mode="AddSubNodeButtons">
<xsl:apply-templates select="*" mode="AddSubNodeButtons"/>
</xsl:template>
<xsl:template match="element" mode="AddSubNodeButtons">
<button>++ <xsl:value-of select="@name"/></button>
</xsl:template>
<xsl:template match="interleave" mode="AddSubNodeButtons">
<xsl:apply-templates select="*" mode="AddSubNodeButtons"/>
</xsl:template>
C'est ces template mode="AddSubNodeButtons" qui me posent problème. J'ai l'impression que je ne peux pas travailler de manière délarative à 100% au risque de multiplier les traitements spécifiques... le template qui match element n'est pas le même selon qu'il y a un zeroOrMore juste avant l'élément par exemple.
Je devrait peut être faire un seul template qui traite tous les cas de figure avec des xsl:choose.
Mais les cas de figures sont innombrables : toutes les combinaisons possibles (du moins autorisé en RelaxNG) des éléments element, attribute, text, group, interleave, oneOrMore, et ZeroOrMore...
Comment prévoir tous les cas même les plus absurdes tel un ZeroOrMore dans un ZeroOrMore, traité comme un seul ZeroOrMore en fait.
J'aimerai rester générique dans la mesure du possible, c'est-à dire que n'importe quel schéma utilisant les éléments indiqués puisse être correctement interprétés.
On en revient peut être au problème du sujet précèdent "RelaxNG, outil xsl ?", la réponse serait elle de simplifier le schéma ("[...] encouragent les implémentations RELAX NG à simplifier les grammaires RELAX NG avant de les utiliser") ?
A défaut de simplifier un schéma complexe existant je pourrais éventuellement donner des régles pour écrire le schéma dans sa version simplifiée directement, mais quelle règles au juste ?
Faut-il que je prévoie tous les cas de figure d'imbrication (ayant du sens) des éléments indiqués, jusqu'à quel profondeur ?
Si vous avez une idées, une démarche à suivre... merci d'avance,
Matthieu.
PS : je n'ai pas mentionné la partie dépendante du doc xml édité, je pense générer les tests nécéssaires avec <xsl:element name="xsl:if" ou "xsl:choose" etc> en ayant préalablement définis une variable $occursNumber (toujours en <xsl:element name="xsl:variable"/>...
--
Devenez redacteur <XML>fr et contribuez au developpement du
xml francophone (http://xmlfr.org/infos/redacteurs/) !
Liste de diffusion "xml-tech@xmlfr.org" (http://xmlfr.org).
Cette liste est a votre disposition pour discuter en francais de
tout sujet technique lie a XML.
Pour resilier votre abonnement, envoyez un message contenant
la commande "unsubscribe" a xml-tech-request@xmlfr.org
(mailto:xml-tech-request@xmlfr.org?Subject=unsubscribe)
Received on Thu Oct 13 17:02:34 2005