(Xslt 1.0) Comment remplacer l'espace avec une chaîne de toutes les valeurs de texte en XML?

StackOverflow https://stackoverflow.com/questions/2318118

  •  22-09-2019
  •  | 
  •  

Question

  

EDIT: [il a commencé avec le remplacement de caractères   et je me suis retrouvé avec une corde découverte   remplacements avec l'aide de Dimitre   Novatchev et Roland Bouman

Je pense que les codes d'échantillons suffisent pour expliquer les exigences ..

Ceci est l'exemple XML:

<root>
  <node1>text node</node1>
  <node2>space between the text</node2>
  <node3> has to be replaced with $</node3>
</root>

Ceci est la sortie J'attends:

<root>
  <node1>text$node</node1>
  <node2>space$between$the$text</node2>
  <node3>$has$to$be$replaced$with$$</node3>
</root>

Je l'ai essayé d'écrire un code XSLT qui ne montre pas la puissance requise ..
Voici le code:

    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>
  <xsl:template match="text()[.!='']">
    <xsl:call-template name="rep_space">
      <xsl:with-param name="text" select="."/>
    </xsl:call-template>
  </xsl:template>
  <xsl:template name="rep_space">
    <xsl:param name="text"/>
    <xsl:variable name="temp" select="'&#x36;'"/> 
    <xsl:choose>
      <xsl:when test="contains(text,'&#x32;')">
        <xsl:call-template name="rep_space">
          <xsl:with-param name="text" select="concat((concat(substring-before(text,' '),temp)),substring-after(text,' '))"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="text"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  

translate (., « », « $ ») Fonction fonctionne .. mais pas dans la mesure satisfaisante .. mes questions sont .. si c'est une chaîne   au lieu de caractère? Je veux dire, suppose   Je suis destiné à remplacer « » avec   "% 20"? Et un autre cas, si le   XML d'entrée est « XML Jolie impression »,   puis tout l'espace qui apparaît en XML   sont remplacés par '$' ..

XML d'impression Jolie est le fichier qui a tiret bon, (habituellement mon entrée XMLs n'ont jamais cela) par exemple:

  un noeud plus       c'est @ niveau inférieur     

Vous pouvez observer, il y a pas de « caractères espace » avant les noeuds de <new> <test> mais ils sont en fait bien échancré, (avec Altova XMLSPY nous pouvons donner une simple commande dans le menu d'édition .. pour faire une XML fichiers à "assez XML d'impression") ..

Où comme dans l'exemple ci-dessous ..

<new>
  <test>one more node</test>
   <test2>
    <child>this is @ lower level</child>
   </test2>
</new>

Il y a un espace avant carbonise toutes les balises de début .. balise <child> a plus d'espaces avant que ce noeud <test2> ..

Avec le second échantillon xml .. tous les caractères de l'espace sont remplacés par « %20 » .. d'où la sortie sera ..

<new>
%20%20<test>one%20more%20node</test>
%20%20<test2>
%20%20%20%20<child>this%20is%20@%20lower%20level</child>
%20%20</test2>
</new>

certainement ne devrait pas ..

  

Les solutions affichées par Dimitre   Novatchev et Roland Bouman peut également remplacer une chaîne par une autre chaîne, par   la modification des paramètres passés à la   modèle appelé.

     

C'était super apprentissage @Dimitre,   @Roland, je suis très reconnaissant et   reconnaissant les gars ..

     

Cordialement,
enfant pro.

Était-ce utile?

La solution

Conformément au souhait de Roland , voici une solution récurrente-queue :

 <xsl:template name="replace">
  <xsl:param name="ptext"/>
  <xsl:param name="ppattern"/>
  <xsl:param name="preplacement"/>

  <xsl:choose>
     <xsl:when test="not(contains($ptext, $ppattern))">
      <xsl:value-of select="$ptext"/>
     </xsl:when>
     <xsl:otherwise>
       <xsl:value-of select="substring-before($ptext, $ppattern)"/>
       <xsl:value-of select="$preplacement"/>
       <xsl:call-template name="replace">
         <xsl:with-param name="ptext"
           select="substring-after($ptext, $ppattern)"/>
         <xsl:with-param name="ppattern" select="$ppattern"/>
         <xsl:with-param name="preplacement" select="$preplacement"/>
       </xsl:call-template>
     </xsl:otherwise>
  </xsl:choose>
 </xsl:template>

Notez que l'appel récursif est la dernière instruction dans le modèle - c'est ce qui récursive. La propriété d'être récursive permet à un processeur XSLT à puce (tels que Saxon ou XslCompiledTransform .NET) pour optimiser le code, en remplaçant la récursion avec itération simple.

tel code ne sera pas finir avec une exception pile débordement, même lorsque le « imbrication » des appels est des millions, alors que le code non-récursive (et récursive) soulève généralement cette pile débordement à une profondeur d'environ 1000 imbriquée appels (cela dépend vraiment de la quantité de la mémoire disponible).

Que faire si le processeur XSLT n'est pas « assez intelligent »? Y at-il une autre technique pour éviter les appels récursifs niveau profond débordement de pile, qui fonctionne avec tous processeur XSLT?

Demandez-moi une question distincte et je pourrais vous dire:)

Autres conseils

Vérifiez la fonction XPath traduire: http://www.w3.org/TR/xpath/#function-translate

<xsl:template match="text()">
    <xsl:value-of select="translate(., ' ', '$')"/>
</xsl:template>

Si ce n'est pas un seul caractère, mais une chaîne que vous devez remplacer, il faut beaucoup plus d'efforts, et vous avez besoin d'un modèle pour remplacer récursive la chaîne:

<xsl:template match="text()[not(../*)]">
    <xsl:call-template name="replace">
        <xsl:with-param name="text" select="."/>
        <xsl:with-param name="search" select="' '"/>
        <xsl:with-param name="replace" select="'%20'"/>
    </xsl:call-template>
</xsl:template>

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

Edit: correspondance changé = "text ()" à   match = "text () [non (../*)]", de sorte que la   xml d'entrée ne doit pas être une sorte de   « XML assez d'impression » .. (pour supprimer   remplacements non désirés de l'espace avec   chaîne "% 20" dans ce fichier xml)

La solution au "xml imprimé Préty-" est pas vraiment une solution.

Imaginez avoir un document comme celui-ci:

<a>
 <b>
  <c>O M G</c>
  <d>D I Y</d>
 </b>
</a>

La sortie de la solution actuellement acceptée (après l'enveloppant dans un <xsl:stylesheet> et en ajoutant la règle d'identité est la suivante:

<a>
%20<b>
%20%20<c>O$M$G</c>
%20%20<d>D$I$Y</d>
%20</b>
</a>

Maintenant, pourquoi ne pas la solution proposée sauver la situation? Comme on le voit dans l'exemple ci-dessus, un élément peut avoir plus d'un élément enfant qui a des nœuds de texte ...

Quelle est la vraie solution ?

Les créateurs de XSLT ont pensé à ce problème. En utilisant la bonne terminologie, nous voulons que tous les nœuds de texte blanc-espace seulement insignifiant pour être ignoré par le processeur XSLT, comme si elles ne faisaient pas partie de l'arbre du document du tout. Ceci est réalisé par le <xsl:strip-space> .

Il suffit d'ajouter cette au niveau mondial (comme un enfant de <xsl:stylesheet> et, pour une meilleure lisibilité, avant tous les modèles):

 <xsl:strip-space elements="*"/>

et maintenant vous avez vraiment une solution de travail.

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