背景
我最近惊讶地注意到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>
答案 0 :(得分:5)
似乎在 XSLT / XPATH 1.0 中,string()
值在执行比较时仍会被评估为数字。
https://www.w3.org/TR/xpath/#booleans
当要比较的对象都不是节点集而运算符是 &lt; =,&lt;,&gt; =或&gt;,然后通过转换两者来比较对象 对象到数字并根据IEEE 754比较数字。 &lt;当且仅当第一个数字较小时,比较才会成立 而不是第二个数字。
使用 XSLT / XPATH 2.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>
答案 1 :(得分:1)
如果您要使用第一个数字,那么解决方法可能就是将第一个位置子串起来。
<xsl:if test="substring(./text(), 1, 1) < '7'">
返回
<AsString>
<x>1</x>
<x>2</x>
<x>3</x>
<x>4</x>
<x>5</x>
<x>6</x>
<x>10</x>
</AsString>
答案 2 :(得分:1)
请注意,在XSLT 1.0中,'a' > 'b'
和'b' > 'a'
的评估均为false
。