Question

J'essaie de transformer un document XML. Ma transformation XML peut générer deux types d'éléments de base différents, en fonction de la valeur d'un élément donné:

<xsl:template match="/">
  <xsl:choose>
    <xsl:when test="/databean/data[@id='pkhfeed']/value/text()='200'">
      <xsl:call-template name="StructureA">
        <xsl:with-param name="structure" select="//databean" />
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:call-template name="StructureB">
        <xsl:with-param name="structure" select="//databean" />
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

StructureA ou StructureB sont ensuite créées avec leurs propres espaces de noms et schemaLocations:

<StructureA xmlns="http://...">

StructureA & amp; B partageant certains éléments communs, ils sont définis dans un fichier séparé appelé "xmlcommon.xslt". que les deux structures incluent des modèles de. Ce fichier xmlcommon n'a pas d'espace de noms par défaut défini car je souhaite qu'il soit utilisable à partir de l'espace de noms défini dans StructureA ou StructureB. Mais lorsque j'exécute ma transformation, tous les modèles extraits du fichier commun génèrent des attributs xmlns vides:

<StructureA xmlns="http://...">
  <SharedElement xmlns="">Something</SharedElement>
</StructureA>

Lors de la validation, l'espace de nom vide est ensuite utilisé à la place de celui parent correct. Quelqu'un sait-il comment je peux empêcher mes modèles dans mon fichier commun d'ajouter ces attributs vides xmlns?

Voici un extrait du fichier commun:

<xsl:stylesheet version="1.0" xmlns:fn="http://www.w3.org/2005/02/xpath-functions" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:template name="ControlledListStructure">
    <xsl:param name="xmlElem" />
    <xsl:param name="structure" />

    <xsl:element name="{$xmlElem}">
      <!-- Blah blah blah -->
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>
Était-ce utile?

La solution

L’important, c’est que votre feuille de style dicte le nom de chaque élément que vous ajoutez à l’arbre des résultats. Le nom d'un élément comporte deux parties: le nom local et l'URI de l'espace de noms. Dans votre code ci-dessus, vous fournissez le nom local (la valeur de $ xmlElem ), mais vous ne spécifiez pas d'URI d'espace de nom, ce qui signifie que la chaîne vide sera utilisée par défaut. (En fait, il prend l'espace de noms par défaut de ce module de feuille de style; puisqu'il n'y en a aucun, c'est la chaîne vide.) En d'autres termes, l'élément sera pas dans un espace de noms . Lors de la sérialisation du document, le processeur XSLT doit inclure les non-déclarations xmlns = "" afin d'indéclarer l'espace de nom par défaut qui apparaît en haut. Sinon, l'élément prendrait cet espace de noms, ce qui n'est pas ce que votre feuille de style dictait. Le moyen le moins intrusif de résoudre ce problème serait d’ajouter un autre paramètre (par exemple, $ namespaceURI ), comme vous le faites avec $ xmlElem . Ensuite, vous écririez:

<xsl:element name="{$xmlElem}" namespace="{$namespaceURI}">

L'élément résultant prendra tout l'espace de noms que vous lui indiquez (ce qui aura pour effet de supprimer les non-déclarations d'espace de noms par défaut).

Cela devrait répondre à votre question. Je propose ce qui suit comme bonus gratuit. ; -)

Vous devez supprimer le test de noeud text () dans votre comparaison de valeurs. Très rarement, vous aurez besoin de comparer directement les valeurs des nœuds de texte. Au lieu de cela, vous pouvez simplement comparer la valeur de chaîne de l'élément lui-même (définie comme la concaténation des valeurs de chaîne de tous ses nœuds de texte descendants). Cela ressemblerait à ceci:

<xsl:when test="/databean/data[@id='pkhfeed']/value = '200'">

L'avantage de le faire de cette façon est que votre code ne sera pas cassé s'il y a un commentaire caché dedans:

<value>2<!--test-->00</value>

Dans ce cas, il y a deux nœuds de texte ("2" et "00"). Votre test initial échouera puisqu'il vérifiera si l'un d'entre eux est égal à "200". Ce n'est pas très probable dans ce cas, mais dans tous les cas, tester la valeur de chaîne de l'élément (par opposition à ses enfants de nœud de texte) est une bonne pratique lorsque c'est votre intention.

Enfin, je vous encourage à en apprendre davantage sur les règles de modèle et le contexte XPath. J'ai tendance à éviter < xsl: choisissez > , < xsl: modèle d'appel > et < xsl: with-param > . dès que possible. D'une part, les règles de modèle peuvent vous aider à éviter beaucoup de parties vilaines et prolixes de XSLT.

<xsl:template match="/databean[data[@id='pkhfeed']/value = '200']" priority="1">
  <StructureA xmlns="http://...">
    ...
  </StructureA>
</xsl:template>

<xsl:template match="/databean">
  <StructureB xmlns="http://...">
    ...
  </StructureB>
</xsl:template>

Même si vous continuez à utiliser < xsl: call-template > , vous ne devriez pas avoir à passer ce paramètre $ structure , car le nœud actuel restera inchangé. dans le modèle appelé. Vous pouvez accéder à // databean (ou / databean , ce que je soupçonne être ce que vous voulez dire) tout aussi facilement depuis l'un de vos StructureA ou StructureB , car le nœud actuel sera toujours " / " (le noeud du document).

Si vous souhaitez en savoir plus sur le modèle de traitement principal de XSLT et sur ses fonctionnalités les plus puissantes (règles de modèle), je vous encourage à consulter " Comment fonctionne XSLT ", exemple gratuit du chapitre de ma Référence de poche XSLT 1.0 .

J'espère que cela vous a été utile, même si c'est plus que ce que vous aviez prévu!

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top