XSLT 将数字作为字符串进行比较
XSLT Compare Numbers as Strings
背景
我最近惊讶地发现 XSL 能够智能地处理数字;即知道在执行比较时将文本中的数字视为数字(即它理解 7 < 10
而不是思考 '10' < '7'
)。就我而言,这就是我想要的;只是出乎我的意料。
出于好奇,我试图强制 XSLT 将数字作为字符串进行比较(即通过使用 string()
函数,但没有成功。
问题
是否可以让 XSLT 将数字作为字符串进行比较;例如所以 '10' < '7'
?
例子
来源XML:
<?xml version="1.0" encoding="utf-8"?>
<element>
<x>1</x>
<x>2</x>
<x>3</x>
<x>4</x>
<x>5</x>
<x>6</x>
<x>7</x>
<x>8</x>
<x>9</x>
<x>10</x>
</element>
XSLT:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes"/>
<xsl:template match="element">
<element>
<AsItComes>
<xsl:for-each select="./x">
<xsl:if test="./text() < 7">
<xsl:copy-of select="."></xsl:copy-of>
</xsl:if>
</xsl:for-each>
</AsItComes>
<AsNumber>
<xsl:for-each select="./x">
<xsl:if test="number(./text()) < 7">
<xsl:copy-of select="."></xsl:copy-of>
</xsl:if>
</xsl:for-each>
</AsNumber>
<AsString>
<xsl:for-each select="./x">
<xsl:if test="string(./text()) < '7'">
<xsl:copy-of select="."></xsl:copy-of>
</xsl:if>
</xsl:for-each>
</AsString>
</element>
</xsl:template>
</xsl:stylesheet>
预期输出:
<?xml version="1.0" encoding="utf-8"?>
<element>
<AsItComes>
<x>1</x>
<x>2</x>
<x>3</x>
<x>4</x>
<x>5</x>
<x>6</x>
<x>10</x>
</AsItComes>
<AsNumber>
<x>1</x>
<x>2</x>
<x>3</x>
<x>4</x>
<x>5</x>
<x>6</x>
</AsNumber>
<AsString>
<x>1</x>
<x>2</x>
<x>3</x>
<x>4</x>
<x>5</x>
<x>6</x>
<x>10</x>
</AsString>
</element>
实际输出:
<?xml version="1.0" encoding="utf-8"?>
<element>
<AsItComes>
<x>1</x>
<x>2</x>
<x>3</x>
<x>4</x>
<x>5</x>
<x>6</x>
</AsItComes>
<AsNumber>
<x>1</x>
<x>2</x>
<x>3</x>
<x>4</x>
<x>5</x>
<x>6</x>
</AsNumber>
<AsString>
<x>1</x>
<x>2</x>
<x>3</x>
<x>4</x>
<x>5</x>
<x>6</x>
</AsString>
</element>
如果您要获取第一个数字,work-around 可能只是对第一个位置进行子字符串化。
<xsl:if test="substring(./text(), 1, 1) < '7'">
returns
<AsString>
<x>1</x>
<x>2</x>
<x>3</x>
<x>4</x>
<x>5</x>
<x>6</x>
<x>10</x>
</AsString>
似乎在XSLT/XPATH 1.0中,string()
值在执行比较时仍被评估为数字。
https://www.w3.org/TR/xpath/#booleans
When neither object to be compared is a node-set and the operator is
<=, <, >= or >, then the objects are compared by converting both
objects to numbers and comparing the numbers according to IEEE 754.
The < comparison will be true if and only if the first number is less
than the second number.
与XSLT/XPATH2.0(以及3.0,和3.1),可以显式设置数据类型为xs:string
,以确保进行比较针对字符串而不是强制转换为数字值。
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
version="2.0">
<xsl:template match="element">
<element>
<AsString>
<xsl:for-each select="./x">
<xsl:if test="xs:string(.) < xs:string('7')">
<xsl:copy-of select="."></xsl:copy-of>
</xsl:if>
</xsl:for-each>
</AsString>
</element>
</xsl:template>
</xsl:stylesheet>
但是将值与字符串 '7'
进行比较就足够了(另外,您可以删除 <xsl:if>
并将过滤器放在谓词中):
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:template match="element">
<element>
<AsString>
<xsl:for-each select="./x[. < '7']">
<xsl:copy-of select="."></xsl:copy-of>
</xsl:for-each>
</AsString>
</element>
</xsl:template>
</xsl:stylesheet>
请注意,在 XSLT 1.0 中,'a' > 'b'
和 'b' > 'a'
都计算为 false
。
背景
我最近惊讶地发现 XSL 能够智能地处理数字;即知道在执行比较时将文本中的数字视为数字(即它理解 7 < 10
而不是思考 '10' < '7'
)。就我而言,这就是我想要的;只是出乎我的意料。
出于好奇,我试图强制 XSLT 将数字作为字符串进行比较(即通过使用 string()
函数,但没有成功。
问题
是否可以让 XSLT 将数字作为字符串进行比较;例如所以 '10' < '7'
?
例子
来源XML:
<?xml version="1.0" encoding="utf-8"?>
<element>
<x>1</x>
<x>2</x>
<x>3</x>
<x>4</x>
<x>5</x>
<x>6</x>
<x>7</x>
<x>8</x>
<x>9</x>
<x>10</x>
</element>
XSLT:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes"/>
<xsl:template match="element">
<element>
<AsItComes>
<xsl:for-each select="./x">
<xsl:if test="./text() < 7">
<xsl:copy-of select="."></xsl:copy-of>
</xsl:if>
</xsl:for-each>
</AsItComes>
<AsNumber>
<xsl:for-each select="./x">
<xsl:if test="number(./text()) < 7">
<xsl:copy-of select="."></xsl:copy-of>
</xsl:if>
</xsl:for-each>
</AsNumber>
<AsString>
<xsl:for-each select="./x">
<xsl:if test="string(./text()) < '7'">
<xsl:copy-of select="."></xsl:copy-of>
</xsl:if>
</xsl:for-each>
</AsString>
</element>
</xsl:template>
</xsl:stylesheet>
预期输出:
<?xml version="1.0" encoding="utf-8"?>
<element>
<AsItComes>
<x>1</x>
<x>2</x>
<x>3</x>
<x>4</x>
<x>5</x>
<x>6</x>
<x>10</x>
</AsItComes>
<AsNumber>
<x>1</x>
<x>2</x>
<x>3</x>
<x>4</x>
<x>5</x>
<x>6</x>
</AsNumber>
<AsString>
<x>1</x>
<x>2</x>
<x>3</x>
<x>4</x>
<x>5</x>
<x>6</x>
<x>10</x>
</AsString>
</element>
实际输出:
<?xml version="1.0" encoding="utf-8"?>
<element>
<AsItComes>
<x>1</x>
<x>2</x>
<x>3</x>
<x>4</x>
<x>5</x>
<x>6</x>
</AsItComes>
<AsNumber>
<x>1</x>
<x>2</x>
<x>3</x>
<x>4</x>
<x>5</x>
<x>6</x>
</AsNumber>
<AsString>
<x>1</x>
<x>2</x>
<x>3</x>
<x>4</x>
<x>5</x>
<x>6</x>
</AsString>
</element>
如果您要获取第一个数字,work-around 可能只是对第一个位置进行子字符串化。
<xsl:if test="substring(./text(), 1, 1) < '7'">
returns
<AsString>
<x>1</x>
<x>2</x>
<x>3</x>
<x>4</x>
<x>5</x>
<x>6</x>
<x>10</x>
</AsString>
似乎在XSLT/XPATH 1.0中,string()
值在执行比较时仍被评估为数字。
https://www.w3.org/TR/xpath/#booleans
When neither object to be compared is a node-set and the operator is <=, <, >= or >, then the objects are compared by converting both objects to numbers and comparing the numbers according to IEEE 754. The < comparison will be true if and only if the first number is less than the second number.
与XSLT/XPATH2.0(以及3.0,和3.1),可以显式设置数据类型为xs:string
,以确保进行比较针对字符串而不是强制转换为数字值。
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
version="2.0">
<xsl:template match="element">
<element>
<AsString>
<xsl:for-each select="./x">
<xsl:if test="xs:string(.) < xs:string('7')">
<xsl:copy-of select="."></xsl:copy-of>
</xsl:if>
</xsl:for-each>
</AsString>
</element>
</xsl:template>
</xsl:stylesheet>
但是将值与字符串 '7'
进行比较就足够了(另外,您可以删除 <xsl:if>
并将过滤器放在谓词中):
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:template match="element">
<element>
<AsString>
<xsl:for-each select="./x[. < '7']">
<xsl:copy-of select="."></xsl:copy-of>
</xsl:for-each>
</AsString>
</element>
</xsl:template>
</xsl:stylesheet>
请注意,在 XSLT 1.0 中,'a' > 'b'
和 'b' > 'a'
都计算为 false
。