J'essaie d'utiliser XSLT pour transformer un document en marquant un groupe de nœuds XML avec des ID entiers, en commençant à 0 et en augmentant d'un pour chaque nœud du groupe. Le XML transmis dans la feuille de style doit être renvoyé, mais augmenté pour inclure cette information supplémentaire.Comment utiliser XSLT pour marquer des nœuds spécifiques avec des ID entiers uniques, séquentiels et croissants?
Juste pour être clair sur ce que je parle, voici comment cette transformation serait exprimée à l'aide DOM:
states = document.getElementsByTagName("state");
for(i = 0; i < states.length; i++){
states.stateNum = i;
}
Ceci est très simple avec DOM, mais je vais avoir beaucoup plus de mal faire cela avec XSLT. La stratégie actuelle que j'ai conçue a été de commencer par la transformation d'identité, puis de créer une variable globale qui sélectionne et stocke tous les nœuds que je souhaite numéroter. Je crée ensuite un modèle qui correspond à ce type de noeud. L'idée, alors, est que dans le modèle, je chercherais la position du nœud correspondant dans la variable globale nodelist, ce qui me donnerait un nombre unique que je pourrais ensuite définir comme un attribut.
Le problème avec cette approche est que la fonction de position ne peut être utilisé avec le noeud contextuel, donc quelque chose comme ce qui suit est illégale:
<template match="state">
<variable name="stateId" select="@id"/>
<variable name="uniqueStateNum" select="$globalVariable[@id = $stateId]/position()"/>
</template>
en est de même pour les éléments suivants:
<template match="state">
<variable name="stateId" select="@id"
<variable name="stateNum" select="position($globalVariable[@id = $stateId])/"/>
</template>
Pour utiliser position() pour rechercher la position d'un élément dans $ globalVariable, le noeud contextuel doit être modifié.
J'ai trouvé une solution, mais elle est très sous-optimale. Fondamentalement, dans le modèle, j'utilise chacun pour parcourir la variable globale. Car chacun change le nœud de contexte, ce qui me permet d'utiliser position() comme je l'ai décrit. Le problème est que cela transforme ce qui serait normalement une opération O (n) en une opération O (n^2), où n est la longueur de la nodelist, car cela nécessite de parcourir toute la liste à chaque fois que le modèle est trouvé. Je pense qu'il doit y avoir une solution plus élégante.
Au total, voici mon courant (un peu simplifiée) feuille de style XSLT:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:s="http://www.w3.org/2005/07/scxml"
xmlns="http://www.w3.org/2005/07/scxml"
xmlns:c="http://msdl.cs.mcgill.ca/"
version="1.0">
<xsl:output method="xml"/>
<!-- we copy them, so that we can use their positions as identifiers -->
<xsl:variable name="states" select="//s:state" />
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="s:state">
<xsl:variable name="stateId">
<xsl:value-of select="@id"/>
</xsl:variable>
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:for-each select="$states">
<xsl:if test="@id = $stateId">
<xsl:attribute name="stateNum" namespace="http://msdl.cs.mcgill.ca/">
<xsl:value-of select="position()"/>
</xsl:attribute>
</xsl:if>
</xsl:for-each>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
J'apprécierais tout conseil qu'on peut offrir. Merci.
Bonne question (+1). Voir ma réponse pour une solution très simple mais correcte.:) –