【问题标题】:XPath - Java XPath result unexpectedXPath - Java XPath 结果意外
【发布时间】:2017-02-23 17:00:32
【问题描述】:

我注意到了一些奇怪的事情。这是我的 XML

<Items>
    <Item>
        <Name>A</Name>
        <Amount>0.0012</Amount>
        <Quantity>17</Quantity>
        <TotalAmount>0.0204</TotalAmount>
    </Item>
    <Item>
        <Name>B</Name>
        <Amount>1</Amount>
        <Quantity>2</Quantity>
        <TotalAmount>2</TotalAmount>
    </Item>
    <Item>
        <Name>C</Name>
        <Amount>3</Amount>
        <Quantity>2</Quantity>
        <TotalAmount>6</TotalAmount>
    </Item>
</Items>

这是我使用的 XPath

/Items/Item[((Amount * Quantity) != TotalAmount)]/名称

此 XPath 必须打印 TotalAmount!= Product(Amount, Quantity) 的项目名称。

我得到值 A。但我不明白为什么会这样因为 0.0012 * 17 = 0.0204

如果我删除项目“A”,那么我不会得到结果。

新版本的 XPath 也是如此

对于 $x in /Items/Item[((Amount * Quantity) != TotalAmount)] 返回 $x/姓名

我在 Java 中使用 Saxon 9。

谁能解释为什么会这样。

【问题讨论】:

    标签: java xpath javax.xml


    【解决方案1】:

    尝试使用xs:decimal/xs:integer 以获得更好的精度:/Items/Item[((xs:decimal(Amount) * xs:integer(Quantity)) != TotalAmount)]/Name

    如果你看看http://xsltransform.net/94AbWBV 是什么

    <xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema"
        exclude-result-prefixes="xs">
    
        <xsl:strip-space elements="*"/>
        <xsl:output indent="yes"/>
    
        <xsl:template match="/">
          <results>
              <names-precise>
                <xsl:value-of select="/Items/Item[((xs:decimal(Amount) * xs:integer(Quantity)) != TotalAmount)]/Name"/>
              </names-precise>
              <names-imprecise>
                  <xsl:value-of select="/Items/Item[((Amount * Quantity) != TotalAmount)]/Name"/>
              </names-imprecise>
              <xsl:apply-templates/>
          </results>
    
        </xsl:template>
    
        <xsl:template match="@*|node()">
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
        </xsl:template>
    
        <xsl:template match="Item">
            <xsl:copy>
                <xsl:apply-templates/>
                <double-computation>
                    <xsl:value-of select="Amount * Quantity"/>
                </double-computation>
                <decimal-computation>
                    <xsl:value-of select="xs:decimal(Amount) * xs:integer(Quantity)"/>
                </decimal-computation>
            </xsl:copy>
        </xsl:template>
    </xsl:transform>
    

    您可以看到使用的默认浮点算法不足以计算出精确的结果:

    <results>
       <names-precise/>
       <names-imprecise>A</names-imprecise>
       <Items>
          <Item>
             <Name>A</Name>
             <Amount>0.0012</Amount>
             <Quantity>17</Quantity>
             <TotalAmount>0.0204</TotalAmount>
             <double-computation>0.020399999999999998</double-computation>
             <decimal-computation>0.0204</decimal-computation>
          </Item>
          <Item>
             <Name>B</Name>
             <Amount>1</Amount>
             <Quantity>2</Quantity>
             <TotalAmount>2</TotalAmount>
             <double-computation>2</double-computation>
             <decimal-computation>2</decimal-computation>
          </Item>
          <Item>
             <Name>C</Name>
             <Amount>3</Amount>
             <Quantity>2</Quantity>
             <TotalAmount>6</TotalAmount>
             <double-computation>6</double-computation>
             <decimal-computation>6</decimal-computation>
          </Item>
       </Items>
    </results>
    

    使用 IEEE 双数格式的其他语言(如 Javascript)也存在同样的不精确性:

    document.getElementById('result').textContent = 0.0012 * 17;
    &lt;p&gt;Result of &lt;code&gt;0.0012 * 17&lt;/code&gt; with Javascript is &lt;code id="result"&gt;&lt;/code&gt;.&lt;/p&gt;

    【讨论】:

    • 嗨,马丁。谢谢。像魅力一样工作。 :)
    猜你喜欢
    • 2021-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多