2010-12-15 61 views
3

Je veux ajouter des acronymes à un texte HTML en utilisant xslt: analyze-string. Le problème: dans mon texte HTML sont des balises telles queUtiliser xslt: analyze-string pour ajouter des acronymes au HTML

<strong>some text</strong> 

qui sont traités comme des noeuds XML. Quand j'applique xslt: analyze-string, ces nœuds sont convertis en chaînes - les balises sont supprimées. De même, dans ma feuille de style XSLT récursive, les acronymes déjà insérés sont également supprimés.

Ma question: y a-t-il un truc pour empêcher xslt: analyse-chaîne de transformer les nœuds HTML en chaînes et préserver les balises HTML?

Voici mon exemple:

Stylesheet:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns="http://www.w3.org/1999/xhtml" exclude-result-prefixes="xhtml" > 

    <xsl:template match="/"> 
     <div> 
      <xsl:call-template name="insert-acronyms"> 
       <xsl:with-param name="text" select="/doc/div"/> 
       <xsl:with-param name="acronyms" select="/doc/dictionary/acronym"/> 
      </xsl:call-template> 
     </div> 
    </xsl:template> 


    <xsl:template name="insert-acronyms"> 
     <xsl:param name="text" as="node()*"/> 
     <xsl:param name="acronyms"/> 

     <xsl:choose> 
      <xsl:when test="$acronyms"> 
       <xsl:call-template name="insert-acronyms"> 
        <xsl:with-param name="acronyms" select="$acronyms[position() &gt; 1]"/> 
        <xsl:with-param name="text"> 
         <xsl:call-template name="replace-words"> 
          <xsl:with-param name="text" select="$text"/> 
          <xsl:with-param name="name" select="$acronyms[1]/name"/> 
          <xsl:with-param name="description" select="$acronyms[1]/description"/> 
         </xsl:call-template> 
        </xsl:with-param> 
       </xsl:call-template> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:copy-of select="$text"/> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 


    <xsl:template name="replace-words"> 
     <xsl:param name="text" /> 
     <xsl:param name="name" /> 
     <xsl:param name="description" /> 

     <xsl:analyze-string select="$text" regex="{concat('(^|\W)(', string-join($name, '|'), ')(\W|$)')}"> 
      <xsl:matching-substring> 
       <xsl:value-of select="regex-group(1)"/> 
       <xsl:element name="acronym"> 
       <xsl:attribute name="title"><xsl:value-of select="$description"/></xsl:attribute> 
        <xsl:value-of select="regex-group(2)"/> 
       </xsl:element> 
       <xsl:value-of select="regex-group(3)"/> 
      </xsl:matching-substring> 
      <xsl:non-matching-substring> 
       <xsl:value-of select="."/> 
      </xsl:non-matching-substring> 
     </xsl:analyze-string> 
    </xsl:template> 

</xsl:stylesheet> 

Source:

<?xml version="1.0" encoding="UTF-8"?> 
<doc> 
    <dictionary> 

     <acronym> 
      <name>WWW</name> 
      <description>The World Wide Web</description> 
     </acronym> 

     <acronym> 
      <name>HTML</name> 
      <description>The HyperText Markup Language</description> 
     </acronym> 

    </dictionary> 

    <div> 
     <p>In the <strong>WWW</strong> you can find a lot of <em>HTML</em> documents.</p> 
    </div> 

</doc> 

Résultat de la transformation (strong et em-tags sont dépouillés loin, un seul acronyme est inséré parce que l'autre est également dépouillé):

<?xml version="1.0" encoding="UTF-8"?> 
<div> In the WWW you can find a lot of <acronym title="The HyperText Markup Language">HTML</acronym> documents. </div> 
+0

Bonne question, +1. Voyez ma réponse indiquant les problèmes dans le code fourni et pour une solution beaucoup plus simple et non récursive. :) –

Répondre

2

Le code fourni est inutilement compliqué. Le principal problème est d'essayer de créer un acronyme un à la fois et aussi d'essayer inutilement un traitement récursif.

Voici un simple et logique, solution non récurrente:

<xsl:stylesheet version="2.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"/> 
<xsl:strip-space elements="*"/> 

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

<xsl:template match="/*"> 
    <xsl:apply-templates/> 
</xsl:template> 

<xsl:template match="text()" priority="0.1"> 
    <xsl:sequence select= 
    "my:insert-acronyms(., /*/dictionary/acronym)"/> 
</xsl:template> 

    <xsl:function name="my:insert-acronyms" as="node()*"> 
    <xsl:param name="text" as="text()"/> 
    <xsl:param name="acronyms" as="node()*"/> 

    <xsl:sequence select= 
    "if($acronyms) 
     then my:replace-words($text, $acronyms/name) 
     else $text 
    "/> 
</xsl:function> 

<xsl:function name="my:replace-words" as="node()*"> 
    <xsl:param name="text" as="text()" /> 
    <xsl:param name="names" as="node()*" /> 

    <xsl:analyze-string select="$text" 
    regex="{concat('(^|\W)(', string-join($names, '|'), ')(\W|$)')}"> 
    <xsl:matching-substring> 
    <xsl:value-of select="regex-group(1)"/> 
    <acronym title="{$names[. eq regex-group(2)]/../description}"> 
     <xsl:value-of select="regex-group(2)"/> 
    </acronym> 
    <xsl:value-of select="regex-group(3)"/> 
    </xsl:matching-substring> 
    <xsl:non-matching-substring> 
    <xsl:value-of select="."/> 
    </xsl:non-matching-substring> 
    </xsl:analyze-string> 
</xsl:function> 

<xsl:template match="dictionary"/> 
</xsl:stylesheet> 

Lorsque cette transformation est appliquée sur le document XML fourni:

<doc> 
    <dictionary> 
     <acronym> 
      <name>WWW</name> 
      <description>The World Wide Web</description> 
     </acronym> 
     <acronym> 
      <name>HTML</name> 
      <description>The HyperText Markup Language</description> 
     </acronym> 
    </dictionary> 
    <div> 
     <p>In the <strong>WWW</strong> you can find a lot of <em>HTML</em> documents.</p> 
    </div> 
</doc> 

le voulait , le résultat correct est produit:

<div> 
    <p>In the <strong> 
     <acronym title="The World Wide Web">WWW</acronym> 
     </strong> you can find a lot of <em> 
     <acronym title="The HyperText Markup Language">HTML</acronym> 
     </em> documents.</p> 
</div> 
+0

Merci beaucoup. Cela fonctionne bien. – Suidu

+0

+1 Pour la solution de nœuds de texte correspondant. –

1

xsl:analyze-string fonctionne sur chaînes. Plutôt que d'essayer de s'appliquer à tous les nœuds, il suffit de l'appliquer aux nœuds text().

Essayez de changer votre feuille de style (non testé):

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:xhtml="http://www.w3.org/1999/xhtml" 
xmlns="http://www.w3.org/1999/xhtml" 
exclude-result-prefixes="xhtml" > 
<xsl:output indent="yes" /> 

    <xsl:template match="/"> 

      <xsl:apply-templates select="/doc/div" /> 

    </xsl:template> 

    <xsl:template match="text()" priority="1"> 
     <xsl:call-template name="insert-acronyms"> 
       <xsl:with-param name="text" select="."/> 
       <xsl:with-param name="acronyms" select="/doc/dictionary/acronym"/> 
     </xsl:call-template> 
    </xsl:template> 

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

    <xsl:template name="insert-acronyms"> 
     <xsl:param name="text" as="node()*"/> 
     <xsl:param name="acronyms"/> 

     <xsl:choose> 
      <xsl:when test="$acronyms"> 
       <xsl:call-template name="insert-acronyms"> 
        <xsl:with-param name="acronyms" select="$acronyms[position() &gt; 1]"/> 
        <xsl:with-param name="text"> 
         <xsl:call-template name="replace-words"> 
          <xsl:with-param name="text" select="$text"/> 
          <xsl:with-param name="name" select="$acronyms[1]/name"/> 
          <xsl:with-param name="description" select="$acronyms[1]/description"/> 
         </xsl:call-template> 
        </xsl:with-param> 
       </xsl:call-template> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:copy-of select="$text"/> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 


    <xsl:template name="replace-words"> 
     <xsl:param name="text" /> 
     <xsl:param name="name" /> 
     <xsl:param name="description" /> 

     <xsl:analyze-string select="$text" regex="{concat('(^|\W)(', string-join($name, '|'), ')(\W|$)')}"> 
      <xsl:matching-substring> 
       <xsl:value-of select="regex-group(1)"/> 
       <xsl:element name="acronym"> 
       <xsl:attribute name="title"><xsl:value-of select="$description"/></xsl:attribute> 
        <xsl:value-of select="regex-group(2)"/> 
       </xsl:element> 
       <xsl:value-of select="regex-group(3)"/> 
      </xsl:matching-substring> 
      <xsl:non-matching-substring> 
       <xsl:value-of select="."/> 
      </xsl:non-matching-substring> 
     </xsl:analyze-string> 
    </xsl:template> 

</xsl:stylesheet> 
+0

J'ai testé cette solution mais le problème était qu'elle ne remplaçait pas tous les acronymes. Je n'ai pas cherché la raison parce que la solution de Dimitre Novatchev fonctionne. – Suidu