【问题标题】:locale-aware number comparison with XSLT与 XSLT 进行区域感知数字比较
【发布时间】:2010-09-30 09:55:47
【问题描述】:

我的 XML 中有一堆成本,我试图将它们与另一个成本值进行比较,以确定要显示的值(仅高于比较器的值)。这适用于数字使用小数点作为分隔符但不适用于使用逗号作为小数分隔符的数字。我可能会得到任何一个,这取决于语言环境。

这是我所拥有的:

<patron_max_cost><![CDATA[1,00]]></patron_max_cost>
<service_costs>
  <location_cost>
    <location_desc><![CDATA[location1]]></location_desc>
    <cost_to_user><![CDATA[0,99]]></cost_to_user>
  </location_cost>
  <location_cost>
      <location_desc><![CDATA[location2]]></location_desc>
      <cost_to_user><![CDATA[1,50]]></cost_to_user>
  </location_cost>
</service_costs>

<xsl:variable name="filtered_location_costs">
  <xsl:for-each select="service_costs/location_cost">
      <xsl:if test="number(cost_to_user) &gt; number(patron_max_cost)">
        <xsl:copy-of select="." />
      </xsl:if>
  </xsl:for-each>
</xsl:variable>

这失败了,因为 cost_to_user 和patron_max_cost 是 NaN。有没有一种方法可以进行这种比较,既适用于两种输入样式,又不涉及在比较之前将逗号转换为小数点等笨拙的东西?我正在使用 XSLT2.0 和 Saxon8。

【问题讨论】:

  • 为什么选择 CDATA 部分?使用fn:traslate 并不笨拙。如果您想要自己的数字格式,则必须定义自己的 大于 运算符。
  • 好问题 (+1)。请参阅我的答案以获得简短而完整的解决方案。 :)

标签: xslt comparison numbers locale


【解决方案1】:

我。 XSLT 1.0 解决方案

这种转变

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <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=
  "location_cost[not(translate(cost_to_user, ',', '.')
                     >
                     translate(/*/patron_max_cost, ',', '.')
                     )
                 ]
  "/>

</xsl:stylesheet>

应用于提供的 XML 文档时

<t>
    <patron_max_cost><![CDATA[1,00]]></patron_max_cost>
    <service_costs>
        <location_cost>
            <location_desc><![CDATA[location1]]></location_desc>
            <cost_to_user><![CDATA[0,99]]></cost_to_user>
        </location_cost>
        <location_cost>
            <location_desc><![CDATA[location2]]></location_desc>
            <cost_to_user><![CDATA[1,50]]></cost_to_user>
        </location_cost>
    </service_costs>
</t>

产生想要的结果

<t>
   <patron_max_cost>1,00</patron_max_cost>
   <service_costs>
      <location_cost>
         <location_desc>location2</location_desc>
         <cost_to_user>1,50</cost_to_user>
      </location_cost>
   </service_costs>
</t>

二。 XSLT 2.0 解决方案:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema"
 >
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:variable name="vpatron_max_cost" as="xs:decimal"
  select="xs:decimal(translate(/*/patron_max_cost, ',', '.'))"/>

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

 <xsl:template match=
  "location_cost[xs:decimal(translate(cost_to_user, ',', '.'))
                le
                 $vpatron_max_cost
                 ]
  "/>

</xsl:stylesheet>

【讨论】:

  • 感谢 Dimitre,这比我想象的要简单。我也很欣赏扩展的答案。
【解决方案2】:

我会使用从逗号到十进制的转换,但也会首先保留一个变量是否有逗号,以便我可以正确显示它(即,将其转换回来。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-07
    • 2017-06-28
    • 2016-04-17
    • 1970-01-01
    • 1970-01-01
    • 2012-08-21
    • 2010-10-01
    • 1970-01-01
    相关资源
    最近更新 更多