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(.) &lt; 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[. &lt; '7']">
          <xsl:copy-of select="."></xsl:copy-of>
        </xsl:for-each>
      </AsString>
    </element>
 </xsl:template>
</xsl:stylesheet>

Если вы собираетесь на первое число обходной путь может быть только подстроке первой позиции.

<xsl:if test="substring(./text(), 1, 1) &lt; '7'">

возвращает

<AsString>
  <x>1</x>
  <x>2</x>
  <x>3</x>
  <x>4</x>
  <x>5</x>
  <x>6</x>
  <x>10</x>
</AsString>

обратите внимание, что в XSLT 1.0 и 'a' > 'b' и 'b' > 'a' оценить как false.