基于输入XML的XSLT十进制格式
我的XSLT文件应该有条件地显示价格和小数,这取决于输入XML是否包含小数。因此,我可以接收具有两种类型值的XML文件—XML将包含所有格式为小数最多两位的价格(我称之为“十进制XML”),或者价格将四舍五入到最接近的整数(我称之为“整数XML”) 我的问题是,我需要在XSLT文件中尽可能少地重构,同时允许它们以与XML输入相同的格式将转换应用于XHTML。为了实现这一目标,我向我的团队实施并建议了三条准则:基于输入XML的XSLT十进制格式,xml,xslt,formatting,decimal,xslt-1.0,Xml,Xslt,Formatting,Decimal,Xslt 1.0,我的XSLT文件应该有条件地显示价格和小数,这取决于输入XML是否包含小数。因此,我可以接收具有两种类型值的XML文件—XML将包含所有格式为小数最多两位的价格(我称之为“十进制XML”),或者价格将四舍五入到最接近的整数(我称之为“整数XML”) 我的问题是,我需要在XSLT文件中尽可能少地重构,同时允许它们以与XML输入相同的格式将转换应用于XHTML。为了实现这一目标,我向我的团队实施并建议了三条准则: 在计算值或将其存储在变量中时,删除所有format-number()函数调用。改用nu
format-number()
函数调用。改用number()
。但是,某些条件适用于此规则(见下文)格式编号(,'#.###')
格式。这将确保整数或十进制值将显示为XML中最初显示的值李>
格式编号(,'0.00')
函数,即使仅计算值。这是必要的,因为如果没有标记,尝试获取值将给出NaN
结果 <x:stylesheet version="1.0" xmlns:x="http://www.w3.org/1999/XSL/Transform">
<x:template match="/">
<html>
<body>
<table border="1" width="60%">
<tr>
<th>Simple</th>
<th>number()</th>
<th>format-number(<expression>, '0.00')</th>
<th>format-number(<expression>, '#.##')</th>
</tr>
<x:apply-templates />
</table>
</body>
</html>
</x:template>
<x:template match="Item">
<x:variable name="qty" select="number(@numItems)" />
<x:variable name="cost" select="number(ItemCost) * $qty" />
<x:variable name="extraCharges" select="(number(Tax) + number(TxnFee)) * $qty"/>
<x:variable name="discount" select="format-number(Discount, '0.00') * $qty"/>
<tr>
<td>
<!-- Works for Integer-XML, but values in Decimal-XML are
*sometimes* rendered upto 14 decimal places. Even though Quickwatch
shows it correctly in the debugger in VS. I cannot figure out what's
special about the error cases. -->
<x:value-of select="$cost + $extraCharges - $discount"/>
</td>
<td>
<!-- Works same as the above case. -->
<x:value-of select="number($cost + $extraCharges - $discount)"/>
</td>
<td>
<!-- Works for Decimal-XML, but values in Integer-XML are always
rendered with decimal digits. -->
<x:value-of select="format-number(($cost + $extraCharges - $discount), '0.00')"/>
</td>
<td>
<!-- Works for Integer-XML, but some values in Decimal-XML are
rendered incorrectly. For example, 95.20 is rendered as 95.2;
95.00 is rendered as 95 -->
<x:value-of select="format-number(($cost + $extraCharges - $discount), '#.##')"/>
</td>
</tr>
</x:template>
</x:stylesheet>
简单的
编号()
格式编号(表达式“0.00”)
格式编号(表达式“#.##”)
正如HTML注释所指出的,它在大多数情况下有效,但并非所有情况下都有效
我希望使用一个表达式来格式化与输入相同的所有价格,而不是到处应用“whenother”构造,这还需要一个传递给XSLT的布尔参数来确定显示格式。XSLT的当前状态是,使用格式编号(,'0')
对所有数字进行四舍五入,而不考虑输入
我如何做到这一点
编辑:在Dimitre的评论之后,我决定创建一个示例XML(以及上面的XSLT),以便专家们可以轻松地进行尝试 示例XML(这个包含小数):
10.99
3.99
2.99
2.99
15.50
5.50
3.50
3.50
如果我理解正确,您需要:
- “整数XML”始终显示为四舍五入的数字,没有小数位数
- “Decimal XML”总是以两位小数显示
- 不是使用进行格式化的模板,而是XPath单行程序
<xsl:value-of select="
format-number($cost + $extraCharges - $discount, '0.00')
" />
但是,当$cost
、$extraCharges
和$discount
加起来是一个整数时,此“失败”(删除小数)
没有吸引力的替代方法是使用贝克尔的方法(以of命名):
从技术上讲,这是一个单一的班轮。这两个sub-string()
部分基于$condition
相互排斥,因此concat()
将只返回一个值或另一个值
实际上(特别是对你的情况),这将是一个难以管理的混乱局面,缓慢且完全隐藏了意图:
concat(
substring(
format-number($cost + $extraCharges - $discount, '0.00')
, 1
, number(
contains($cost, '.')
) * string-length(format-number($cost + $extraCharges - $discount, '0.00'))
),
substring(
format-number($cost + $extraCharges - $discount, '#.##')
, 1
, number(
not(contains($cost, '.'))
) * string-length(format-number($cost + $extraCharges - $discount, '#.##'))
)
)
由于您声明所有输入值都包含小数,或者没有小数,因此上述表达式仅检查
$cost
是否包含小数点。我想,检查$extraCharges
和$discount
也是正确的。如果我理解正确,您需要:
- “整数XML”始终显示为四舍五入的数字,没有小数位数
- “Decimal XML”总是以两位小数显示
- 不是使用进行格式化的模板,而是XPath单行程序
<xsl:value-of select="
format-number($cost + $extraCharges - $discount, '0.00')
" />
但是,当$cost
、$extraCharges
和$discount
加起来是一个整数时,此“失败”(删除小数)
没有吸引力的替代方法是使用贝克尔的方法(以of命名):
从技术上讲,这是一个单一的班轮。这两个sub-string()
部分基于$condition
相互排斥,因此concat()
将只返回一个值或另一个值
实际上(特别是对你的情况),这将是一个难以管理的混乱局面,缓慢且完全隐藏了意图:
concat(
substring(
format-number($cost + $extraCharges - $discount, '0.00')
, 1
, number(
contains($cost, '.')
) * string-length(format-number($cost + $extraCharges - $discount, '0.00'))
),
substring(
format-number($cost + $extraCharges - $discount, '#.##')
, 1
, number(
not(contains($cost, '.'))
) * string-length(format-number($cost + $extraCharges - $discount, '#.##'))
)
)
由于您声明所有输入值都包含小数,或者没有小数,因此上述表达式仅检查
$cost
是否包含小数点。我想,检查$extraCharges
和$discount
也是正确的。您甚至忘了提供最简单的XML文档。这是没有帮助的。@Dimitre:我没有忘记提供它,但我必须承认,我没有意识到需要一个源XML,因为这实际上不是一个转换问题。这是一个关于十进制格式的一般性问题。不过,如果有帮助的话,我会尝试创建一个。您甚至忘了提供最简单的XML文档。这是没有帮助的。@Dimitre:我没有忘记提供它,但我必须承认,我没有意识到需要一个源XML,因为这实际上不是一个转换问题。这是一个关于十进制格式的一般性问题。不过,如果有帮助的话,我会尝试创建一个。
concat(
substring(
format-number($cost + $extraCharges - $discount, '0.00')
, 1
, number(
contains($cost, '.')
) * string-length(format-number($cost + $extraCharges - $discount, '0.00'))
),
substring(
format-number($cost + $extraCharges - $discount, '#.##')
, 1
, number(
not(contains($cost, '.'))
) * string-length(format-number($cost + $extraCharges - $discount, '#.##'))
)
)