2009-03-21 13 views
0

私のXSLTファイルでは、入力XMLに小数点以下が含まれるかどうかに応じて、条件付きで小数点とともに価格を表示する必要があります。 XMLは2つのタイプの値を持つXMLファイルを受け取ることができます - XMLには小数点以下2桁までの価格が含まれます(これをDecimal-XMLと呼びます)、または価格は最も近い整数に切り上げられます1つの「Integer-XML」)。XSLT入力XMLに基づく小数点フォーマット

私の問題は、XSLTファイルで可能な限りリファクタリングする必要がありますが、XML入力と同じ形式でXHTMLに変換を適用する必要があるということです。これを実現するためには、私が実装され、私のチームには3つのガイドライン提案:値が計算に計算したり、変数に格納されているときに、すべてのformat-number()関数呼び出し

  1. 削除を。代わりにnumber(<value>)を使用してください。ただし、このルールには特定の条件が適用されます(下記参照)。
  2. 値を表示する場合は、format-number(<value>, '#.##')形式を使用します。これにより、XMLに元々存在する整数値または小数点値が確実に表示されます。
  3. オプションのタグ(「割引」など)の場合は、値が計算されている場合でもformat-number(<value>, '0.00')関数を使用します。これは、タグが存在しない場合、値を取得しようとするとNaNの結果が得られるため必要です。それがすべてではないが、ほとんどの場合で動作し、HTMLコメントの注意点としては

    <x:stylesheet version="1.0" xmlns:x="http://www.w3.org/1999/XSL/Transform"> 
        <x:template match="/"> 
        <html> 
         <body> 
         <table border="1" width="60%"> 
          <tr> 
          <th>Simple</th> 
          <th>number()</th> 
          <th>format-number(&lt;expression&gt;, '0.00')</th> 
          <th>format-number(&lt;expression&gt;, '#.##')</th> 
          </tr> 
          <x:apply-templates /> 
         </table> 
         </body> 
        </html> 
        </x:template> 
    
        <x:template match="Item"> 
        <x:variable name="qty" select="number(@numItems)" /> 
        <x:variable name="cost" select="number(ItemCost) * $qty" /> 
        <x:variable name="extraCharges" select="(number(Tax) + number(TxnFee)) * $qty"/> 
        <x:variable name="discount" select="format-number(Discount, '0.00') * $qty"/> 
        <tr> 
         <td> 
         <!-- Works for Integer-XML, but values in Decimal-XML are 
         *sometimes* rendered upto 14 decimal places. Even though Quickwatch 
         shows it correctly in the debugger in VS. I cannot figure out what's 
         special about the error cases. --> 
         <x:value-of select="$cost + $extraCharges - $discount"/> 
         </td> 
         <td> 
         <!-- Works same as the above case. --> 
         <x:value-of select="number($cost + $extraCharges - $discount)"/> 
         </td> 
         <td> 
         <!-- Works for Decimal-XML, but values in Integer-XML are always 
         rendered with decimal digits. --> 
         <x:value-of select="format-number(($cost + $extraCharges - $discount), '0.00')"/> 
         </td> 
         <td> 
         <!-- Works for Integer-XML, but some values in Decimal-XML are 
         rendered incorrectly. For example, 95.20 is rendered as 95.2; 
         95.00 is rendered as 95 --> 
         <x:value-of select="format-number(($cost + $extraCharges - $discount), '#.##')"/> 
         </td> 
        </tr> 
        </x:template> 
    </x:stylesheet> 
    

    :ここ

は、XSLTの例示的な一例です。

私は、表示形式を決定するためにXSLTに渡されるブール型パラメータをさらに必要とする「when-otherwise」構成をどこにでも適用するのではなく、入力と同じ価格をすべてフォーマットする単一式を使用したいと考えています。 XSLTの現在の状態は、format-number(<expression>, '0')を使用して、入力に関係なくすべての数値が四捨五入されていることです。

どうすればよいですか?


編集: Dimitreさんのコメントの後、私は、サンプルのXML(および上記のXSLT)を作成することを決めたので、専門家は簡単にそれを試してみることができます。

サンプルXMLは(この1つは、小数点以下が含まれています):

<ShoppingList> 
    <Item numItems="2"> 
    <ItemCost>10.99</ItemCost> 
    <Tax>3.99</Tax> 
    <TxnFee>2.99</TxnFee> 
    <Discount>2.99</Discount> 
    </Item> 
    <Item numItems="4"> 
    <ItemCost>15.50</ItemCost> 
    <Tax>5.50</Tax> 
    <TxnFee>3.50</TxnFee> 
    <Discount>3.50</Discount> 
    </Item> 
</ShoppingList> 
+0

可能な限り単純なXMLドキュメントでも提供することを忘れました。これは役に立たない。 –

+0

@ Dimitre:私はそれを提供することを忘れていませんでしたが、これは実際に変換の問題ではないので、ソースXMLが必要であることを認識していないことを認めなければなりません。小数点の書式設定に関する一般的な質問です。それでも助けがあれば、私はそれを作成しようとします。 – Cerebrus

答えて

6

私が正しくあなたを理解していれば、あなたが望む:

  • "整数-XML" は常に丸めた数として表示するために、無小数点以下は
  • 「小数-XML」は常に小数点以下
  • 書式設定を行い、テンプレートを使用しないが、XPathのワンライナーで表示する
  • XPathの1で条件式を使用して簡単なありませんので

    <xsl:value-of select=" 
        format-number($cost + $extraCharges - $discount, '0.00') 
    " /> 
    

あなたが望むものを得ている最も近いはこの表現です。$cost$extraCharges$discountラウンド数まで追加するとき

<xsl:value-of select=" 
    substring-before(
    concat(format-number($cost + $extraCharges - $discount, '0.00'), '.00') 
    , '.00' 
) 
" /> 

しかし、これは(小数点以下をカット) "失敗":0(XPath 2.0 has if/then/else)、妥協このあろう。

魅力のない選択肢は、(HU BerlinOliver Beckerにちなんで名付けられた)ベッカーのメソッドを使用することです:

concat(
    substring($s1, 1, number($condition)  * string-length($s1)), 
    substring($s2, 1, number(not($condition)) * string-length($s2)) 
) 

は技術的には、それはワンライナーです。 2つのsub-string()部分は$conditionに基づいて互いに排他的です。したがって、concat()は1つの値のみを返します。

実際に(特にあなたの場合)、管理不能な混乱になるだろう、遅いと完全に意図を隠す:

concat( 
    substring(
    format-number($cost + $extraCharges - $discount, '0.00') 
    , 1 
    , number(
     contains($cost, '.') 
    ) * string-length(format-number($cost + $extraCharges - $discount, '0.00')) 
), 
    substring(
    format-number($cost + $extraCharges - $discount, '#.##') 
    , 1 
    , number(
     not(contains($cost, '.')) 
    ) * string-length(format-number($cost + $extraCharges - $discount, '#.##')) 
) 
) 

あなたはすべての入力値のいずれかが小数点を含まない、またはそれらのどれと述べているので、上記の式は、$costに小数点が含まれているかどうかをチェックするだけです。 $extraCharges$discountもチェックするのが正しいでしょう。

関連する問題