2010-10-19 5 views
6

Celui-ci est un peu compliqué, et j'ai été bloqué dessus pendant un certain temps. Ce que je veux faire est de balises mises en place des supports de la [ '(par exemple pour des boutons, des liens, etc.), et à la place de ']'XSL: Remplacer certains caractères par des balises xml

<section> 
    <title>Buttons</title> 
    <orderedlist> 
     <listitem> 
      <para>Clicking on [Save] will attempt to save changes, then it navigates to <xref linkend="saved" xrefstyle="select: title"/>.</para> 
     </listitem> 
     <listitem> 
      <para>Clicking on [Cancel] navigates to <xref linkend="noSave" xrefstyle="select: title"/>.</para> 
     </listitem> 
    </orderedlist> 
</section> 

Pour:

<section> 
    <title>Buttons</title> 
    <orderedlist> 
     <listitem> 
      <para>Clicking on <uicontrol>Save</uicontrol> will attempt to save changes, then it navigates to <xref linkend="saved" xrefstyle="select: title"/>.</para> 
     </listitem> 
     <listitem> 
      <para>Clicking on <uicontrol>Cancel</uicontrol> navigates to <xref linkend="noSave" xrefstyle="select: title"/>.</para> 
     </listitem> 
    </orderedlist> 
</section> 

Et la '[' ']' n'est pas forcément toujours dans section.listitem.para

Modifier: Je n'ai besoin que de [] remplacement lorsque certains mots sont entre parenthèses.

+0

Bonne question, +1. Voir ma réponse pour une solution plus sûre et plus efficace. –

+0

En regardant dans la réponse de @ Dimitre, je suis venu à penser que c'est une meilleure approche: le texte fixe entre parenthèses pour la recherche. Cela rend le problème moins général, donc vous n'avez pas à vous soucier des parenthèses imbriquées ou isolées. Notez que pour les parenthèses imbriquées, vous aurez besoin d'analyse! –

Répondre

2

Cette transformation:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:my="my:my" exclude-result-prefixes="my"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<my:uicontrols> 
    <control>[Save]</control> 
    <control>[Cancel]</control> 
</my:uicontrols> 

<xsl:key name="kHasControls" match="text()" 
    use="boolean(document('')/*/my:uicontrols/*[contains(current(), .)])"/> 

<xsl:variable name="vControls" select="document('')/*/my:uicontrols/*"/> 

<xsl:template match="node()|@*" name="identity"> 
    <xsl:copy> 
    <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="text()[key('kHasControls', 'true')]"> 
    <xsl:choose> 
    <xsl:when test="not($vControls[contains(current(),.)])"> 
    <xsl:copy-of select="."/> 
    </xsl:when> 
    <xsl:otherwise> 
    <xsl:call-template name="createControl"/> 
    </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 

<xsl:template name="createControl"> 
    <xsl:param name="pText" select="."/> 

    <xsl:choose> 
    <xsl:when test="not(contains($pText, '['))"> 
    <xsl:copy-of select="$pText"/> 
    </xsl:when> 
    <xsl:otherwise> 
    <xsl:copy-of select="substring-before($pText, '[')"/> 

    <xsl:variable name="vStartText" select= 
    "concat('[', substring-after($pText, '['))"/> 
    <xsl:variable name="vCtrl" select="$vControls[starts-with($vStartText,.)]"/> 
    <xsl:choose> 
     <xsl:when test="not($vCtrl)"> 
     <xsl:text>[</xsl:text> 
     <xsl:call-template name="createControl"> 
     <xsl:with-param name="pText" select="substring($vStartText,1)"/> 
     </xsl:call-template> 
     </xsl:when> 
     <xsl:otherwise> 
     <uicontrol> 
     <xsl:value-of select="translate($vCtrl,'[]','')"/> 
     </uicontrol> 

     <xsl:call-template name="createControl"> 
     <xsl:with-param name="pText" select="substring-after($vStartText, $vCtrl)"/> 
     </xsl:call-template> 
     </xsl:otherwise> 
    </xsl:choose> 
    </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 
</xsl:stylesheet> 

lorsqu'il est appliqué sur le document XML fourni:

<section> 
    <title>Buttons</title> 
    <orderedlist> 
     <listitem> 
      <para>Clicking on [Save] will attempt to save changes, then it navigates to <xref linkend="saved" xrefstyle="select: title"/>.</para> 
     </listitem> 
     <listitem> 
      <para>Clicking on [Cancel] navigates to <xref linkend="noSave" xrefstyle="select: title"/>.</para> 
     </listitem> 
    </orderedlist> 
</section> 

produit le résultat souhaité, correct:

<section> 
    <title>Buttons</title> 
    <orderedlist> 
     <listitem> 
      <para>Clicking on <uicontrol>Save</uicontrol><xref linkend="saved" xrefstyle="select: title"/>.</para> 
     </listitem> 
     <listitem> 
      <para>Clicking on <uicontrol>Cancel</uicontrol><xref linkend="noSave" xrefstyle="select: title"/>.</para> 
     </listitem> 
    </orderedlist> 
</section> 

Prenez note de ce qui suit:

  1. Cette solution remplace uniquement une liste contrôlée des noms de contrôle. De cette façon, nous sommes protégés contre les erreurs accidentelles et nous pouvons également utiliser librement les chaînes de type "[Anything]" sans aucun problème (par ex.nous voulons afficher une célèbre expression XPath - cette expression par définition prédicats :))

  2. L'utilisation des clés assure une meilleure efficacité que scanner chaque nœud de texte pour "[".

+0

@Dimitre: +1 Parce que j'aime l'approche '[control]' fixe afin de préserver l'autre texte entre parenthèses (prédicats XPath, comme vous l'avez écrit!). J'aime aussi l'utilisation de 'fn: current()' dans les clés (je ne sais pas pourquoi j'ai toujours pensé que c'était interdit). –

+0

@Dimitre: En tant que contribution, je n'utiliserais pas ce test "in whole document" ... Si vous définissez la clé comme valeur booléenne plus l'identifiant de noeud, vous pouvez tester efficacement "ce noeud de texte satisfait" –

+0

@ Alejandro: Bien sûr, s'il y a une exigence bien spécifiée que seuls les nœuds doivent traiter pour les contrôles, la clé ne peut correspondre qu'à ces nœuds de texte. –

2

Vous pouvez utiliser les fonctions contains, substring-before et substring-after pour trouver les parenthèses, puis insérer les éléments selon vos besoins au lieu des parenthèses.

Edit - qui devrait fonctionner:

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"> 
    <xsl:output method="xml" indent="yes"/> 

    <xsl:template name="insertElements"> 
     <xsl:param name="text" select="." /> 
     <xsl:choose> 
      <xsl:when test="contains($text, '[')"> 
       <xsl:value-of select="substring-before($text, '[')"/> 
       <xsl:variable name="after" select="substring-after($text, '[')" /> 
       <uicontrol> 
        <xsl:value-of select="substring-before($after, ']')"/> 
       </uicontrol> 
       <xsl:call-template name="insertElements"> 
        <xsl:with-param name="text" select="substring-after($after, ']')" /> 
       </xsl:call-template> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:value-of select="$text"/> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 

    <xsl:template match="@* | node()"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*"/> 
      <xsl:for-each select="node()"> 
       <xsl:choose> 
        <xsl:when test="self::text()"> 
         <xsl:call-template name="insertElements" /> 
        </xsl:when> 
        <xsl:otherwise> 
         <xsl:apply-templates select="." /> 
        </xsl:otherwise> 
       </xsl:choose> 
      </xsl:for-each> 
     </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 
+0

Cela fonctionne, bien qu'il semble aussi ajouter un {xmlns = ""} à la balise uicontrol – Ace

+0

Cela échoue avec ' Ceci est juste une parenthèse: [' –

3

Pour ne uicontrol imbriqué pour les supports imbriqués (qui aurait besoin pour l'analyse syntaxique entre parenthèses équilibrées par rapport aux pas de crochets équilibrés).

Cette feuille de style:

<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="replace" priority="1"> 
    <xsl:param name="pString" select="."/> 
    <xsl:variable name="vMask" select="translate($pString, 
                translate($pString, 
                   '[]', 
                   ''), 
                '')"/> 
    <xsl:choose> 
    <xsl:when test="contains($vMask,'[]')"> 
    <xsl:call-template name="makeControl"> 
    <xsl:with-param name="pString" select="$pString"/> 
    <xsl:with-param name="pMask" 
        select="substring-before($vMask,'[]')"/> 
    </xsl:call-template> 
    </xsl:when> 
    <xsl:otherwise> 
    <xsl:value-of select="$pString"/> 
    </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 
<xsl:template name="makeControl"> 
    <xsl:param name="pString"/> 
    <xsl:param name="pMask"/> 
    <xsl:choose> 
    <xsl:when test="$pMask"> 
    <xsl:variable name="vMask" select="substring($pMask,1,1)"/> 
    <xsl:value-of select="concat(
          substring-before(
           $pString, 
           $vMask), 
          $vMask)"/> 
    <xsl:call-template name="makeControl"> 
    <xsl:with-param name="pString" 
        select="substring-after($pString,$vMask)"/> 
    <xsl:with-param name="pMask" select="substring($pMask,2)"/> 
    </xsl:call-template> 
    </xsl:when> 
    <xsl:otherwise> 
    <xsl:value-of select="substring-before($pString,'[')"/> 
    <uicontrol> 
    <xsl:value-of select="substring-before(
              substring-after(
               $pString, 
               '['), 
              ']')"/> 
    </uicontrol> 
    <xsl:call-template name="replace"> 
    <xsl:with-param name="pString" 
            select="substring-after($pString,']')"/> 
    </xsl:call-template> 
    </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 
</xsl:stylesheet> 

Sortie:

<section> 
<title>Buttons</title> 
<orderedlist> 
    <listitem> 
    <para>Clicking on <uicontrol>Save</uicontrol> will attempt to save changes, then it navigates to <xref linkend="saved" xrefstyle="select: title"></xref>.</para> 
    </listitem> 
    <listitem> 
    <para>Clicking on <uicontrol>Cancel</uicontrol> navigates to <xref linkend="noSave" xrefstyle="select: title"></xref>.</para> 
    </listitem> 
</orderedlist> 
</section> 

Et avec cette entrée:

<text> 
This is an opening bracket [ ? [Yes] [No] 
This is a closing bracket ] ? [Yes] [No] 
</text> 

Sortie:

<text> 
This is an opening bracket [ ? <uicontrol>Yes</uicontrol> <uicontrol>No</uicontrol> 
This is a closing bracket ] ? <uicontrol>Yes</uicontrol> <uicontrol>No</uicontrol> 
</text> 

Remarque: Tout texte correspondant \[[^\[\]]*\] serait enveloppé dans l'élément uicontrol.

+0

Cela fonctionne comme l'autre solution, mais génère également un certain avertissement plusieurs fois: Nom du moteur: Saxon6.5.5 Gravité: avertissement Description: Correspondance de règle ambiguë pour/section [1]/text() [1] Correspond à la fois "text()" sur la ligne 7 – Ace

+0

@Ace: C'est juste un avertissement parce que la résolution de confit de modèle. Maintenant, il est parti avec «@ priorité» explicite. Notez également que les réponses sont différentes. Le mien conserve les supports solitaires –

+0

Oh, c'est vrai. Et la priorité fixe les choses – Ace