如何用XSLT 1.0将价格字符串中的.00替换为€?
问题描述
需将XML中<prixmenu>29.00-90.00</prixmenu>转换为<prixmenu>29€-90€</prixmenu>,现有XSLT 1.0代码处理时出现以下问题:
- 递归拆分模板输出
2990,丢失分隔符和欧元符号 - 使用
translate函数得到29€-9€,因字符替换规则不匹配导致错误
输入XML
<?xml version="1.0" encoding="UTF-8"?> <data> <etablissement not="15.0" etoile="2" > <nom>L'Auberge Asterix</nom> <index>AUBERGE ASTERIX (L')</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>
现有XSLT代码
<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>
期望输出
<?xml version="1.0"?> <data> <etablissement> <nom>L'Auberge Asterix</nom> <etoile>2 étoiles</etoile> <index>AUBERGE ASTERIX (L')</index> <id>0123456789</id> <not>15</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>
解决方案
方案1:XSLT 1.0 实现(无需FXSL)
替换原有prixrestau/prixmenu模板,通过递归拆分价格段并替换.00为€,保留分隔符:
<xsl:template match="prixrestau/prixmenu" name="formatPrice"> <xsl:param name="text" select="."/> <xsl:choose> <!-- 处理带分隔符的价格范围 --> <xsl:when test="contains($text, '-')"> <xsl:value-of select="concat(substring-before($text, '.00'), '€')"/> <xsl:text>-</xsl:text> <xsl:call-template name="formatPrice"> <xsl:with-param name="text" select="substring-after($text, '-')"/> </xsl:call-template> </xsl:when> <!-- 处理单个价格 --> <xsl:otherwise> <xsl:value-of select="concat(substring-before($text, '.00'), '€')"/> </xsl:otherwise> </xsl:choose> </xsl:template>
同时删除coordonnees模板中多余的translate调用行:
<xsl:value-of select="translate(../prixrestau/prixmenu,'.00.','€')"/>
方案2:切换到XSLT 2.0(更简洁)
利用XSLT 2.0的正则替换函数replace,一步完成格式转换:
<xsl:template match="prixrestau/prixmenu"> <xsl:copy> <xsl:value-of select="replace(., '(\d+)\.00', '$1€')"/> </xsl:copy> </xsl:template>
此方法无需递归,代码更简洁易维护。
内容的提问来源于stack exchange,提问作者amsived
相关产品推荐
相关产品推荐

