Search code examples
replacesplitxslt-1.0

Replacing 3 characters by 1 in a string with XSLT 1.0


I'm working on a xsl template and one specific string is giving me a hard time. <prixmenu>29.00-90.00</prixmenu> Desired output : <prixmenu>29€-90€</prixmenu>

The whole code I have is : XML (input) :

<?xml version="1.0" encoding="UTF-8"?>
<data>
    <etablissement not="15.0" etoile="2" >
        <nom>L&#039;Auberge Asterix</nom>
        <index>AUBERGE ASTERIX (L&#039;)</index>
        <id>0123456789</id>
        <regionindex>Paris</regionindex>
        <equipe>
            <chef>Ratatouille</chef>
        </equipe>
        <pictoPratique cave_remarquable="0"  coeur="0" ></pictoPratique>
        <coordonnees>
            <adresse>Random adress</adresse>
            <tel>01 23 45 67 89/tel>
            <fermetures>mam,maa,</fermetures>
            <pratique terrasse="0"
                voiturier="0"
                parcPrive="1"
                handicap="0"
                airConditione="0"
                piscine="0"
                tennis="0"
                chien="1"
                relaischat="0"
                delivery="0"
                clickAndCollect="0"
                itineraireGourmand="0"
                menu_kids="1"
                hebergement="0"
                ></pratique>
        </coordonnees>
        <texte>Lorem ipsum</texte>
        <prixrestau>
            <prixcarte>0</prixcarte>
            <prixmenu>29.00-90.00</prixmenu>
        </prixrestau>
    </etablissement>
</data>

XSL stylesheet :

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes" />
  <xsl:strip-space elements="*" />
  
  <xsl:template match="data | node()[not(self::coordonnees)]">
    <xsl:copy>
      <xsl:apply-templates select="nom" />
      
      <xsl:choose>
        <xsl:when test="@etoile = 1">
          <etoile>1 étoile</etoile>
        </xsl:when>
        <xsl:when test="@etoile > 1">
          <etoile><xsl:value-of select="@etoile" /> étoiles</etoile>
        </xsl:when>
      </xsl:choose>
      
      <xsl:apply-templates select="index" />
      <xsl:apply-templates select="id" />
      <xsl:apply-templates
        select="@*[not(.='0')][name(  ) != 'etoile'] | node()[not(self::index)][not(self::id)][not(self::prixrestau)][not(self::nom)][not(self::etoile)]" />
    </xsl:copy>
  </xsl:template>
  
  <xsl:template match="@*[name(  ) != 'etoile']">
    <xsl:element name="{name()}">
      <xsl:value-of select="number(.)" />
    </xsl:element>
  </xsl:template>
  
  <xsl:template match="prixrestau/prixmenu" name="split">
    <xsl:param name="pText" select="."/>
    <xsl:if test="$pText">
      <xsl:value-of select="number(substring-before(concat($pText, '-'), '-'))"/>
      <xsl:call-template name="split">
        <xsl:with-param name="pText" select="substring-after($pText, '-')"/>
      </xsl:call-template>
    </xsl:if>
  </xsl:template>
  
  <xsl:template match="coordonnees">
    <xsl:copy>
      <xsl:apply-templates select="adresse" />
      <xsl:apply-templates select="tel" />
      <xsl:element name="prixrestau">
<xsl:value-of select="translate(../prixrestau/prixmenu,'.00.','€')"/>

        <xsl:apply-templates select="../prixrestau/prixcarte[not(.='0')]" />

        <xsl:element name="prixmenu">
          <xsl:apply-templates select="../prixrestau/prixmenu" />
        </xsl:element>
        
      </xsl:element>
      <xsl:apply-templates select="fermetures" />
      <xsl:apply-templates
        select="@*[not(.='0')] | node()[not(self::adresse)][not(self::tel)][not(self::fermetures)]" />
    </xsl:copy>
  </xsl:template>
  
</xsl:stylesheet>

Desired output :

<?xml version="1.0"?>
<data>
  <etablissement>
    <nom>L'Auberge Asterix</nom>
    <etoile>2 étoiles</etoile>
    <index>AUBERGE ASTERIX (L')</index>
    <id>0123456789</id>
    <not>13</not>
    <regionindex>Paris</regionindex>
    <equipe>
      <chef>Ratatouille</chef>
    </equipe>
    <pictoPratique/>
    <coordonnees>
      <adresse>Random adress</adresse>
      <tel>01 23 45 67 89</tel>
      <prixrestau><prixmenu>29€-90€</prixmenu></prixrestau>
      <fermetures>mam,maa,</fermetures>
      <pratique>
        <parcPrive>1</parcPrive>
        <chien>1</chien>
        <menu_kids>1</menu_kids>
      </pratique>
    </coordonnees>
    <texte>Lorem ipsum</texte>
  </etablissement>
</data>

Any suggestions on how to proceed ? Should I import FXSL or switch to XSLT 2.0 as it probably be less of a pain to get to the desired result ?

I've tried splitting it with the following code (I belive it's called a 'recursive template" :

  <xsl:template match="prixrestau/prixmenu" name="split">
    <xsl:param name="pText" select="."/>
    <xsl:if test="$pText">
      <xsl:value-of select="number(substring-before(concat($pText, '-'), '-'))"/>
      <xsl:call-template name="split">
        <xsl:with-param name="pText" select="substring-after($pText, '-')"/>
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

This outputs <prixmenu>2990</prixmenu>

And i've also tried <xsl:value-of select="translate(../prixrestau/prixmenu,'.00.','€')"/> and the output is : 29€-9€ Because '.00.' and '€'don't have the same length (MDN reference)...


Solution

  • How about:

    <xsl:template match="prixmenu">
        <xsl:copy>
            <xsl:value-of select="format-number(substring-before(., '-'), '0€')"/>
            <xsl:text>-</xsl:text>
            <xsl:value-of select="format-number(substring-after(., '-'), '0€')"/>
        </xsl:copy>
    </xsl:template>
    

    If you like, you could change the first xsl:value-of instruction to:

        <xsl:value-of select="format-number(substring-before(., '-'), '0€-')"/>
    

    and get rid of the xsl:text part - but I think it's better to keep it to make the code more readable.