XSLT сравнивает числа как строки
фон
недавно я был удивлен, заметив, что XSL смог разумно обрабатывать числа; т. е. зная, что числа в тексте являются числовыми при выполнении сравнений (т. е. он понял, что 7 < 10
вместо '10' < '7'
). В моем случае это то, чего я хотел; просто не то, чего я ожидал.
из любопытства я попытался заставить XSLT сравнивать числа как строки (т. е. с помощью
3 ответов
похоже, что в XSLT / XPATH 1.0 на string()
значение по-прежнему оценивается как число при выполнении сравнения.
https://www.w3.org/TR/xpath/#booleans
когда ни один из сравниваемых объектов не является набором узлов, а оператор = или >, затем объекты сравниваются путем преобразования обоих объекты для чисел и сравнения чисел в соответствии с IEEE 754.
С 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>
Если вы собираетесь на первое число обходной путь может быть только подстроке первой позиции.
<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>