【问题标题】:XSLT Compare Numbers as StringsXSLT 将数字作为字符串进行比较
【发布时间】:2016-04-17 06:12:42
【问题描述】:

背景

我最近惊讶地发现 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() &lt; 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()) &lt; 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()) &lt; '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>

【问题讨论】:

    标签: xslt comparison string-comparison numeric-conversion


    【解决方案1】:

    似乎在 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' 进行比较就足够了(另外,您可以消除&lt;xsl:if&gt; 并将您的过滤器放在谓词中):

    <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>
    

    【讨论】:

    • 我同意这个分析,但是对于 XSLT 2.0,使用 &lt;xsl:if test=". &amp;lt; '7'"&gt;version="2.0" 样式表就足够了,这表明 &lt;xsl:if test="xs:string(.) &amp;lt; xs:string('7')"&gt; 我担心人们认为他们必须在 xs:string 构造函数中包装任何东西来电。
    【解决方案2】:

    如果您要获取第一个数字,解决方法可能是仅对第一个位置进行子串化。

    <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>
    

    【讨论】:

    • 感谢@MartinVitek;好的解决方法。我真的很感兴趣是否可以进行全文比较;虽然只是出于好奇而不是任何必要/要求。
    【解决方案3】:

    请注意,在 XSLT 1.0 中,'a' &gt; 'b''b' &gt; 'a' 均计算为 false

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-04-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-12
      • 2016-10-17
      • 1970-01-01
      相关资源
      最近更新 更多