2009-04-30 5 views
4

Je tente de faire une transformation sur un document XML. Ma transformation XML peut se traduire par deux différents types d'éléments de base en fonction de la valeur d'un certain élément:Blank xmlns = "" Attributs de l'importation

<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éés avec leurs propres espaces de noms et schemaLocations:

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

StructureA & B partage certains éléments communs, ceux-ci sont donc définis dans un fichier séparé appelé "xmlcommon.xslt" dont les deux structures incluent des modèles. 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 quand je lance mon transform, tous les modèles tirés dans du résultat de fichier commun dans xmlns blanc attributs:

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

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

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> 

Répondre

9

L'essentiel à comprendre est que votre feuille de style dicte le nom de chaque élément que vous ajoutez à l'arbre résultat. 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 noms, ce qui signifie qu'il prendra par défaut la chaîne vide. (En fait, il prend l'espace de nom par défaut de ce module de feuille de style, puisqu'il n'y en a aucun, alors 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 de décompter 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 dicté par votre feuille de style. La manière la moins intrusive de résoudre ce problème serait d'ajouter un autre paramètre (par exemple, $namespaceURI), comme vous l'avez fait avec $xmlElem. Ensuite, vous écririez:

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

Maintenant, l'élément résultant prendra tout l'espace de noms que vous lui dites de prendre (ce qui aura pour effet de supprimer les espaces de noms par défaut ONU- déclarations).

Cela devrait répondre à votre question. Je propose ce qui suit en tant que matériel bonus gratuit. ;-)

Vous devez supprimer le test de noeud text() dans votre comparaison de valeurs. Vous aurez très rarement 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 (qui est définie comme la concaténation des valeurs de chaîne de tous ses nœuds de texte descendant). 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 se cassera pas s'il y a un commentaire cacher là-dedans:

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

Dans ce cas, il y a deux nœuds de texte ("2" et "00"). Votre test d'origine échouerait, car il vérifie si l'un d'entre eux est égal à "200".Il est peu probable que cela se produise 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:choose>, <xsl:call-template>, et <xsl:with-param> autant que possible. D'une part, les règles de modèle peuvent vous aider à éviter beaucoup de parties laides 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, comme le nœud actuel reste inchangé dans le modèle appelé. Vous pouvez accéder à //databean (ou /databean, que je soupçonne est ce que vous voulez dire) tout aussi facilement à l'intérieur ou l'autre de vos StructureA ou StructureB modèles, car le nœud actuel sera toujours «/» (le nœud de document).

Si vous êtes intéressés à en apprendre davantage sur le modèle de traitement de base de XSLT et ses fonctionnalités les plus puissantes (règles de modèle), alors je vous encourage à consulter "How XSLT Works", le chapitre de l'échantillon gratuit de mon XSLT 1.0 Pocket Reference.

J'espère que cela a été utile pour vous, même si elle est plus que vous espériez!

+0

Bonne explication, Evan. Rien de plus à ajouter. +1 de moi. Bienvenue à SO. –

+0

Merci Evan. C'est une grande aide :) Et merci pour les infos supplémentaires aussi. Je ne touche pas souvent XSLT, donc c'est agréable d'entendre les meilleures façons de faire les choses. –

Questions connexes