2010-08-27 7 views
0

Fondamentalement, ce que je fais en ce moment est d'exécuter un XSLT, puis en ouvrant le résultat dans Visual Studio et de faire une recherche et un remplacement pour un mot - pour cet exemple, je veux changer toutes les instances de "bar" à "myBar". Toutes les instances de « bar » peuvent être considérés comme des éléments de texte comme ceci:Substitution générale sur tout XML (XSLT)

<someElement>bar.whatever</someElement> 

Ce serait transformé à:

<someElement>myBar.whatever</someElement> 

Mais la mise en garde à cela est que je suis également en cours d'exécution d'autres des transformations, telles que le changement de nom ou le déplacement de l'élément. Est-il possible que je puisse combiner ces deux opérations (la transformation et la trouver et remplacer) dans un XSLT? Est-ce possible pour plusieurs trouver-et-remplacer?

Toute aide est appréciée et merci d'avance!

Modifier: D'après les commentaires

Je aurait dû préciser que je suis en effet en utilisant XSLT 2.0. Je lis cet article et essayer de comprendre comment j'utiliser remplacer()

+0

adam_0: Une bonne pratique consiste à poser une autre question. En outre, fournissez l'échantillon d'entrée et la sortie désirée dans votre nouvelle question. –

+0

J'ai créé une nouvelle question: http://stackoverflow.com/questions/3620298/substituting-values-over-many-xml-elements-xslt-2-0 et enlevé la deuxième question –

Répondre

5

XSLT 1.0 n'a pas de recherche de texte robuste et de remplacement. Vous pouvez ajouter quelque chose qui utilise contains, substring-before, et substring-after, mais vous devez utiliser un modèle récursif pour gérer le cas où la chaîne que vous essayez de corriger a plusieurs occurrences de la sous-chaîne.

Cela fonctionne, en supposant que votre transformation qui se déplace et renomme éléments est une variante de l'identité de transformation:

<xsl:template match="text()"> 
    <xsl:call-template name="replace"> 
    <xsl:with-param name="text" select="."/> 
    </xsl:call-template> 
</xsl:template> 

<xsl:template name="replace"> 
    <xsl:param name="text"/> 
    <xsl:choose> 
    <xsl:when test="contains($text, 'bar')"> 
     <xsl:call-template name="replace"> 
     <xsl:with-param name="text" select="concat(
         substring-before($text, 'bar'), 
         'myBar', 
         substring-after($text, 'bar'))"/> 
     </xsl:call-template> 
    </xsl:when> 
    <xsl:otherwise> 
     <xsl:value-of select="$text"/> 
    </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 

Notez que partout où vous copiez la valeur d'un élément à l'aide value-of, vous devez être en utilisant apply-templates; changer ceci:

<xsl:template match="someElement"> 
    <renamedElement> 
     <xsl:value-of select="."/> 
    <renamedElement> 
</xsl:template> 

dans ce:

<xsl:template match="someElement"> 
    <renamedElement> 
     <xsl:apply-templates select="text()"/> 
    <renamedElement> 
</xsl:template> 

Faire plusieurs remplacements est un peu plus compliqué.Vous devez étendre le modèle replace de prendre searchFor et replaceWith arguments, ce qui est assez facile, puis le faire dans le modèle text():

<xsl:variable name="pass1"> 
    <xsl:call-template name="replace"> 
     <xsl:with-param name="text" select="."/> 
     <xsl:with-param name="searchFor">bar</xsl:with-param> 
     <xsl:with-param name="replaceWith">myBar</xsl:with-param> 
    </xsl:call-template> 
</xsl:variable> 

<xsl:variable name="pass2"> 
    <xsl:call-template name="replace"> 
     <xsl:with-param name="text" select="."/> 
     <xsl:with-param name="searchFor">bar</xsl:with-param> 
     <xsl:with-param name="replaceWith">myBar</xsl:with-param> 
    </xsl:call-template> 
</xsl:variable> 

<xsl:value-of select="$pass2"/> 

Dans XSLT 2.0, qui prend en charge en utilisant des expressions régulières sur les nœuds de texte, cette est beaucoup plus facile. Vous créez toujours un modèle qui correspond à text(), mais il a juste un appel à replace. Voir this article pour beaucoup d'informations, si vous êtes assez chanceux pour pouvoir utiliser XSLT 2.0.

+0

@Robert Rossney: Je pense que vous êtes ajouter une certaine complexité là où il n'y en a pas. Si le PO va élaborer plus sur la correspondance nécessaire, alors vous pouvez dire combien complexe la solution XSLT 1.0 serait. De plus, pourquoi ne recommandez-vous pas simplement de faire correspondre le nœud de texte? –

+0

L'OP a dit qu'il veut remplacer "toutes les instances de 'barre'", pas "toute instance de 'barre' qui apparaît au début d'un noeud de texte." Si vous pouvez écrire un template XSLT 1.0 plus simple qui peut changer 'barbarian' en' myBarmyBarian', j'aimerais beaucoup le voir. Je ne comprends pas votre deuxième question. –

+0

@Robert Rossney: L'OP a également fourni un échantillon d'entrée à une sortie désirée. ;) Je pourrais facilement réécrire ma réponse pour adresser votre transformation «barbare» à «myBarmyBarian» en ajoutant juste quelques instructions à ma réponse. La complexité émergerait seulement si les nœuds de texte devenaient énormes, parce que le besoin d'utiliser DVC pour éviter le stackoverflow. Pour l'explication de la deuxième question, vous pouvez voir ma réponse ... –

1

EDIT: Maintenant, qui a été précisé que l'OP veut que chaque occurrence de « bar » remplacé par « Mybar » cette feuille de style XSLT 1.0:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:template match="@*|node()"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*|node()"/> 
     </xsl:copy> 
    </xsl:template> 
    <xsl:template match="text()" name="text"> 
     <xsl:param name="pString" select="."/> 
     <xsl:choose> 
      <xsl:when test="contains($pString,'bar')"> 
       <xsl:value-of 
       select="concat(substring-before($pString,'bar'),'myBar')"/> 
       <xsl:call-template name="text"> 
        <xsl:with-param name="pString" 
        select="substring-after($pString,'bar')"/> 
       </xsl:call-template> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:value-of select="$pString"/> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 
</xsl:stylesheet> 

Avec entrée:

<someElement>barbarian</someElement> 

sortie:

<someElement>myBarmyBarian</someElement> 

Maintenant, XSLT 2.0 stylesheet:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:template match="@*|node()"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*|node()"/> 
     </xsl:copy> 
    </xsl:template> 
    <xsl:template match="text()"> 
     <xsl:value-of select="replace(.,'bar','myBar')"/> 
    </xsl:template> 
</xsl:stylesheet> 

Remarque: texte noeuds pattern matching.

0

Vous pouvez utiliser l'identité Transformer modèle comme suggéré par alejandro et au remplacement des EXSLT str:replace

Si votre processeur ne supporte pas, vous pouvez trouver une implémentation en tant que modèle XSLT sur la même page.

Pour activer EXSLT, il suffit d'utiliser l'espace de noms approprié dans votre feuille de style comme décrit here

Quelques indications supplémentaires: Vous pouvez en savoir plus sur le modèle here: et here. L'utilisation du premier modèle copiera uniquement la source vers la destination sans changement.

Ensuite, vous pouvez simplement ajouter des modèles supplémentaires pour chaque élément que vous voulez faire un formatage plus spécifique, dans votre cas, celui qui correspond à "text()", je suppose que cela fait le remplacement.