XSLT 大整数 (int64) 处理 msxml
当尝试在 xslt 模板中对大整数 (int64) 进行数学运算时,我得到了错误的结果,因为 xslt 中没有本机 64 位整数支持(xslt 数字是 64 位双精度)。我在 Windows XP SP3 上使用 msxml 6.0。 Windows 上有解决这个问题的方法吗?
<tables>
<table>
<table_schem>REPADMIN</table_schem>
<table_name>TEST_DESCEND_IDENTITY_BIGINT</table_name>
<column>
<col_name>COL1</col_name>
<identity>
<col_min_val>9223372036854775805</col_min_val>
<col_max_val>9223372036854775805</col_max_val>
<autoincrementvalue>9223372036854775807</autoincrementvalue>
<autoincrementstart>9223372036854775807</autoincrementstart>
<autoincrementinc>-1</autoincrementinc>
</identity>
</column>
</table>
</tables>
由于 64 位双精度数中大整数的不精确表示(我假设),此测试返回 true,但如果我可以以某种方式告诉 xslt 处理器使用 int64 而不是默认的 64 位双精度数数据,则实际上返回 false因为大整数是 xml 输入中数字的实际数据类型。
<xsl:when test="autoincrementvalue =
(col_min_val + autoincrementinc)">
<xsl:value-of select="''"/>
</xsl:when>
这是完整的模板
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<!--Reseed Derby identity column-->
<xsl:output omit-xml-declaration='yes' method='text' />
<xsl:param name="stmtsep">;</xsl:param>
<xsl:param name="schemprefix"></xsl:param>
<xsl:template match="tables">
<xsl:variable name="identitycount" select="count(table/column/identity)"></xsl:variable>
<xsl:for-each select="table/column/identity">
<xsl:variable name="table_schem" select="../../table_schem"></xsl:variable>
<xsl:variable name="table_name" select="../../table_name"></xsl:variable>
<xsl:variable name="tablespec">
<xsl:if test="$schemprefix">
<xsl:value-of select="$table_schem"/>.</xsl:if><xsl:value-of
select="$table_name"/></xsl:variable>
<xsl:variable name="col_name" select="../col_name"></xsl:variable>
<xsl:variable name="newstart">
<xsl:choose>
<xsl:when test="autoincrementinc > 0">
<xsl:choose>
<xsl:when test="col_max_val = '' and
autoincrementvalue = autoincrementstart">
<xsl:value-of select="''"/>
</xsl:when>
<xsl:when test="col_max_val = ''">
<xsl:value-of select="autoincrementstart"/>
</xsl:when>
<xsl:when test="autoincrementvalue =
(col_max_val + autoincrementinc)">
<xsl:value-of select="''"/>
</xsl:when>
<xsl:when test="(col_max_val + autoincrementinc) <
autoincrementstart">
<xsl:value-of select="autoincrementstart"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="col_max_val + autoincrementinc"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="autoincrementinc < 0">
<xsl:choose>
<xsl:when test="col_min_val = '' and
autoincrementvalue = autoincrementstart">
<xsl:value-of select="''"/>
</xsl:when>
<xsl:when test="col_min_val = ''">
<xsl:value-of select="autoincrementstart"/>
</xsl:when>
<xsl:when test="autoincrementvalue =
(col_min_val + autoincrementinc)">
<xsl:value-of select="''"/>
</xsl:when>
<xsl:when test="(col_min_val + autoincrementinc) >
autoincrementstart">
<xsl:value-of select="autoincrementstart"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="col_min_val + autoincrementinc"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
</xsl:choose>
</xsl:variable>
<xsl:if test="not(position()=1)"><xsl:text>
</xsl:text></xsl:if>
<xsl:choose>
<!--restart with ddl changes both the next identity value AUTOINCREMENTVALUE and
the identity start number AUTOINCREMENTSTART eventhough in this casewe only want
to change only the next identity number-->
<xsl:when test="$newstart != '' and
$newstart != autoincrementvalue">alter table <xsl:value-of
select="$tablespec"/> alter column <xsl:value-of
select="$col_name"/> restart with <xsl:value-of
select="$newstart"/><xsl:if test="$identitycount>1">;</xsl:if></xsl:when>
<xsl:otherwise>-- reseed <xsl:value-of select="$tablespec"/> is not necessary</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
When trying to do math on an big integer (int64) large number in xslt template I get the wrong result since there is no native 64-bit integer support in xslt (xslt number is 64-bit double). I am using msxml 6.0 on Windows XP SP3. Are there any work around for this on Windows?
<tables>
<table>
<table_schem>REPADMIN</table_schem>
<table_name>TEST_DESCEND_IDENTITY_BIGINT</table_name>
<column>
<col_name>COL1</col_name>
<identity>
<col_min_val>9223372036854775805</col_min_val>
<col_max_val>9223372036854775805</col_max_val>
<autoincrementvalue>9223372036854775807</autoincrementvalue>
<autoincrementstart>9223372036854775807</autoincrementstart>
<autoincrementinc>-1</autoincrementinc>
</identity>
</column>
</table>
</tables>
This test returns true due to the inexact representation of the large integer in 64-bit double (I am assuming) but actually is false if I could tell the xslt processor somehow to use int64 rather than the default 64-bit double for the number data since big integer is the actual data type for numbers in the xml input.
<xsl:when test="autoincrementvalue =
(col_min_val + autoincrementinc)">
<xsl:value-of select="''"/>
</xsl:when>
here is the complete template
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<!--Reseed Derby identity column-->
<xsl:output omit-xml-declaration='yes' method='text' />
<xsl:param name="stmtsep">;</xsl:param>
<xsl:param name="schemprefix"></xsl:param>
<xsl:template match="tables">
<xsl:variable name="identitycount" select="count(table/column/identity)"></xsl:variable>
<xsl:for-each select="table/column/identity">
<xsl:variable name="table_schem" select="../../table_schem"></xsl:variable>
<xsl:variable name="table_name" select="../../table_name"></xsl:variable>
<xsl:variable name="tablespec">
<xsl:if test="$schemprefix">
<xsl:value-of select="$table_schem"/>.</xsl:if><xsl:value-of
select="$table_name"/></xsl:variable>
<xsl:variable name="col_name" select="../col_name"></xsl:variable>
<xsl:variable name="newstart">
<xsl:choose>
<xsl:when test="autoincrementinc > 0">
<xsl:choose>
<xsl:when test="col_max_val = '' and
autoincrementvalue = autoincrementstart">
<xsl:value-of select="''"/>
</xsl:when>
<xsl:when test="col_max_val = ''">
<xsl:value-of select="autoincrementstart"/>
</xsl:when>
<xsl:when test="autoincrementvalue =
(col_max_val + autoincrementinc)">
<xsl:value-of select="''"/>
</xsl:when>
<xsl:when test="(col_max_val + autoincrementinc) <
autoincrementstart">
<xsl:value-of select="autoincrementstart"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="col_max_val + autoincrementinc"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="autoincrementinc < 0">
<xsl:choose>
<xsl:when test="col_min_val = '' and
autoincrementvalue = autoincrementstart">
<xsl:value-of select="''"/>
</xsl:when>
<xsl:when test="col_min_val = ''">
<xsl:value-of select="autoincrementstart"/>
</xsl:when>
<xsl:when test="autoincrementvalue =
(col_min_val + autoincrementinc)">
<xsl:value-of select="''"/>
</xsl:when>
<xsl:when test="(col_min_val + autoincrementinc) >
autoincrementstart">
<xsl:value-of select="autoincrementstart"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="col_min_val + autoincrementinc"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
</xsl:choose>
</xsl:variable>
<xsl:if test="not(position()=1)"><xsl:text>
</xsl:text></xsl:if>
<xsl:choose>
<!--restart with ddl changes both the next identity value AUTOINCREMENTVALUE and
the identity start number AUTOINCREMENTSTART eventhough in this casewe only want
to change only the next identity number-->
<xsl:when test="$newstart != '' and
$newstart != autoincrementvalue">alter table <xsl:value-of
select="$tablespec"/> alter column <xsl:value-of
select="$col_name"/> restart with <xsl:value-of
select="$newstart"/><xsl:if test="$identitycount>1">;</xsl:if></xsl:when>
<xsl:otherwise>-- reseed <xsl:value-of select="$tablespec"/> is not necessary</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
否,除非您使用 XSLT 2.0 处理器,例如 Saxon 或 AltovaXML。
在 XSLT 2.0 中,使用 XPath 2.0,它支持 xs:decimal,这为您提供了所需的精度。对于 Saxon,也可以只使用 xs:integer,因为 Saxon 和 Altova 都实现 Big Integer 算术。
这是一个 XSLT 2.0 样式表(默认情况下使用 xs:integer):
Saxon 9.x 和 AltovaXML2010 都会生成以下正确结果:
这是一个 XSLT显式使用 xs:decimal 的 2.0 样式表:
Saxon 9.x 和 AltovaXML2010 再次生成正确的结果
No, unless you use an XSLT 2.0 processor, such as Saxon or AltovaXML.
In XSLT 2.0 XPath 2.0 is used, which has support for xs:decimal and this gives you the required precision. With Saxon one can also use just xs:integer, because both Saxon and Altova implement Big Integer arithmetic.
Here is an XSLT 2.0 stylesheet (that uses xs:integer by default):
Both Saxon 9.x and AltovaXML2010 produce the following correct result:
Here is an XSLT 2.0 stylesheet that uses xs:decimal explicitly:
Both Saxon 9.x and AltovaXML2010 again produce the correct result