0

次のxmlファイルがあります。

<Contract>
    <TotalCosts>31003</TotalCosts>
    <PaymentSchedules>
        <PaymentSchedule>
            <Amount>516.7</Amount>
            <NumberOfPayments>3</NumberOfPayments>
        </PaymentSchedule>
        <PaymentSchedule>
            <Amount>529.7</Amount>
            <NumberOfPayments>1</NumberOfPayments>
        </PaymentSchedule>
        <PaymentSchedule>
            <Amount>516.7</Amount>
            <NumberOfPayments>55</NumberOfPayments>
        </PaymentSchedule>
        <PaymentSchedule>
            <Amount>504.70</Amount>
            <NumberOfPayments>1</NumberOfPayments>
        </PaymentSchedule>
    </PaymentSchedules>
</Contract>

私のスキーマトロン ファイルで、TotalCosts を paymentSchedule の金額と同じにしたいと考えています。

そのためには、PaymentSchedule ごとに次のことを行う必要があります。

金額 * 支払回数

その後、すべての PaymentSchedules の合計を取得する必要があり、その数はまったく同じである必要があります。与えられた例でこれを試すと、金額がまったく同じであることがわかります。

これを schematron で検証するために、次の schematron ファイルを作成しました。

<iso:schema xmlns:iso="http://purl.oclc.org/dsdl/schematron"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" queryBinding="xslt2">
    <iso:ns uri="http://www.someurl.com" prefix="func"/>

    <xsl:function name="func:getPaymentScheduleTotal">
        <xsl:param name="contract" as="element()"/>
        <xsl:value-of
            select="sum($contract/PaymentSchedules/PaymentSchedule/(NumberOfPayments * Amount))"/>
    </xsl:function>

    <iso:pattern id="Contract">
        <iso:rule context="Contract">
            <iso:assert test="func:getPaymentScheduleTotal(.) = number(TotalCosts)">amount in paymentschedule(<iso:value-of select="func:getPaymentScheduleTotal(.)"/>)    doesn't match total amount(<iso:value-of select="TotalCosts"/>)</iso:assert>
        </iso:rule>
    </iso:pattern>

</iso:schema>

しかし、ここで私は問題に直面しています。次の検証結果が得られます。

paymentschedule(31003.000000000004) の金額が合計金額 (31003) と一致しません (func:getPaymentScheduleTotal(.) = number(TotalCosts)) [assert]

.000000000004 がどこから来ているのかわかりません。もちろん、floor のようなものを使用して数値を四捨五入することもできますが、.000000000004 はそもそもそこにあるべきではないと思います。

何か案は?

4

2 に答える 2

3

発生している問題は、double 変数がどのように機能するかの予想される動作です。XSLT プロセッサは、Amount と NumberOfPayments を xs:double データ型として解釈しています。

ご存じのとおり、xs:double は 64 ビットで表現され、IEEE754 標準に準拠しています (仕様はhttp://grouper.ieee.org/groups/754/にあります)。主な問題は、一部の数値は xs:double として表現できないため、それらの数値は表現可能な最も近い数値として表現されることです (表現できない算術演算の中間結果である場合もあります)。

ただし、問題の解決策があります。xs:double (指数を使用して数値を格納する) を使用する代わりに、 xs:decimal を使用できます。これは、データ型の仕様に従って指数を含めることができないため、数値をそのまま格納する必要があります。したがって、値の式を次のように置き換えます

    <xsl:value-of select="sum($contract/PaymentSchedules/PaymentSchedule/(xs:decimal(Amount) * xs:decimal(NumberOfPayments)))" />

期待どおりに動作するはずです。

更新: 完全な解決策は次のとおりです。

<iso:schema xmlns:iso="http://purl.oclc.org/dsdl/schematron"
            xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
            xmlns:xsl="http://www.w3.org/2001/XMLSchema" queryBinding="xslt2">

    <iso:ns uri="http://www.someurl.com" prefix="func"/>

    <xsl:function name="func:getPaymentScheduleTotal" as="xs:decimal">
        <xsl:param name="contract" as="element()"/>
        <xsl:sequence
            select="sum($contract/PaymentSchedules/PaymentSchedule/(xs:decimal(NumberOfPayments) * xs:decimal(Amount)))"/>
    </xsl:function>

    <iso:pattern id="Contract">
        <iso:rule context="Contract">
            <iso:assert test="func:getPaymentScheduleTotal(.) = xs:decimal(TotalCosts)">amount in paymentschedule(<iso:value-of select="func:getPaymentScheduleTotal(.)"/>)    doesn't match total amount(<iso:value-of select="TotalCosts"/>)</iso:assert>
        </iso:rule>
    </iso:pattern>

</iso:schema>
于 2013-02-19T15:33:42.180 に答える
0

10 進数表現 (516.7、529.7 など) は有限のように聞こえますが、同じ値の 2 進数表現はそうではない可能性があります。したがって、結果の違いが得られます。結果を四捨五入する以外に選択肢はないと思います。

お役に立てれば。

于 2013-02-19T15:25:45.083 に答える