2011-03-07 81 views
0

我對xslt感到沮喪,並且有一個問題,我似乎無法找到答案。我將轉換應用於xml文件,然後使用fo將其輸出到.pdf。輸入文件(xml)來自計費系統,我們希望將其輸出爲可作爲賬單郵寄給客戶的pdf。我正在使用xslt 1.0,而fop正在生成pdf。我無法將來自2個不同父母(CHARGES和OTHER_CHARGES)的類似命名的節點(TAX)分組。這裏有一個例子:
(輸入文件)對來自不同父母的XML節點進行分組

<BILL> 
    <CHARGES PARENT_ID="123456" CUSTOMER="MR. JONES"> 
     <CHARGE NAME="CHARGE1" AMOUNT="10000"> 
      <TAXES> 
       <TAX NAME="FEDERAL" AMOUNT="200"/> 
       <TAX NAME="STATE" AMOUNT="50"> 
      </TAXES> 
     </CHARGE> 
    </CHARGES> 
    <OTHER_CHARGES PARENT_ID="123456" CUSTOMER="MR_JONES"> 
     <OTHER_CHARGE NAME="OTHER_CHARGE1"> 
      <TAXES> 
       <TAX NAME="FEDERAL" AMOUNT="150"/> 
      </TAXES> 
     </OTHER_CHARGE> 
    </OTHER_CHARGES> 
</BILL> 

我要爲項目總稅收結算,使PDF輸出看起來像這樣

聯邦 - $ 350
州 - $ 50

雖然來自不同的節點,但總稅款按名稱和總計分組。我對鍵和分組的理解有限,但我似乎無法找到一個能夠輕鬆轉換我腦中的開關的神奇例子。

+0

您可以發佈您目前使用的xslt嗎? TAX元素的NAME屬性是否受限於一組較小的值? – Chris 2011-03-07 16:01:38

+0

那麼爲什麼分組?你只需要'sum(*/*/TAXES/TAX [@NAME ='FEDERAL']/@ AMOUNT)'和sum(*/*/TAXES/TAX [@NAME ='STATE']/@ AMOUNT)' 。什麼應該分組? – Flack 2011-03-07 16:04:45

+0

@Fack - 這個例子被簡化了,所以可能不止FEDERAL或STATE。可能會有一些我們從未聽說過的稅收。這就是爲什麼我試圖將所有名爲tax的節點組合在一起。如果我知道所有可能適用的不同稅種,那麼我會樂意嘗試不分組。 – theUncannyValley 2011-03-07 16:10:35

回答

1
<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="text"/> 
    <xsl:strip-space elements="*"/> 
    <xsl:key name="kTaxes" match="TAX" use="@NAME"/> 
    <xsl:template match="/*"> 
     <xsl:apply-templates select=" 
      */*/TAXES/TAX[generate-id() = generate-id(key('kTaxes', @NAME)[1])] 
      "/> 
    </xsl:template> 
    <xsl:template match="TAX"> 
     <xsl:value-of select="@NAME"/> 
     <xsl:text>: </xsl:text> 
     <xsl:value-of select="sum(key('kTaxes', @NAME)/@AMOUNT)"/> 
     <xsl:text>&#xa;</xsl:text> 
    </xsl:template> 
</xsl:stylesheet> 

應用到一個稍微複雜的文件:

<BILL> 
    <CHARGES PARENT_ID="123456" CUSTOMER="MR. JONES"> 
     <CHARGE NAME="CHARGE1" AMOUNT="10000"> 
      <TAXES> 
       <TAX NAME="FEDERAL" AMOUNT="200"/> 
       <TAX NAME="STATE" AMOUNT="50"/> 
       <TAX NAME="HEALTH" AMOUNT="300"/> 
      </TAXES> 
     </CHARGE> 
    </CHARGES> 
    <OTHER_CHARGES PARENT_ID="123456" CUSTOMER="MR_JONES"> 
     <OTHER_CHARGE NAME="OTHER_CHARGE1"> 
      <TAXES> 
       <TAX NAME="FEDERAL" AMOUNT="150"/> 
       <TAX NAME="MATERNITY" AMOUNT="150"/> 
       <TAX NAME="HEALTH" AMOUNT="600"/> 
      </TAXES> 
     </OTHER_CHARGE> 
    </OTHER_CHARGES> 
</BILL> 

正確的結果將是:

FEDERAL: 350 
STATE: 50 
HEALTH: 900 
MATERNITY: 150 
+0

+1正確答案。 – 2011-03-07 20:56:08

+0

對於正確的答案+1。 – 2011-03-07 21:34:47

+0

這樣做!謝謝! – theUncannyValley 2011-03-08 16:17:00

1

所以,你可以做什麼(如果你有XSLT 1.0堅持)是:

  • 在varibale選擇所有稅費

<xs:variable name="taxes" select="//TAX"/>

  • 然後選擇不同稅務名稱如下:

<xs:variable name="distict_taxes" select="//$taxes[not(@NAME=preceding::TAX/@NAME)"/>

  • 然後通過這個獨特的稅費由-每年投入名稱爲變量$ taxname迭代,並做到:

<xs:value-of select="sum(//*/TAXES/TAX[@NAME=$taxname]/@AMOUNT)"/>

希望有所幫助。

+0

我認爲這至少讓我在正確的道路上。我對此很新,所以我受到一個'不知道自己到底在做什麼'的嚴重情況的困擾。我會讓你知道結果如何。 – theUncannyValley 2011-03-07 16:57:10

+0

XPath 1.0「第一種」表達式的性能比XSLT分組性能更差。 – 2011-03-07 20:52:05

+0

@Ajjandro ...是...和?在需要XSLT 1.0解決方案的問題中,XSLT 1.0解決方案有什麼問題? – Chris 2011-03-07 21:27:43

0

如果你可以使用XSLT 2.0,那麼試試這個:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="2.0"> 

    <xsl:output method="xml" indent="yes" omit-xml-declaration="no" /> 

    <xsl:template match="BILL"> 
     <report> 
      <xsl:for-each-group select=".//TAX" group-by="@NAME"> 
       <tax> 
        <xsl:attribute name="name"> 
         <xsl:value-of 
          select="current-grouping-key()" /> 
        </xsl:attribute> 
        <xsl:attribute name="total"> 
         <xsl:value-of 
          select="sum(current-group()/@AMOUNT)" /> 
        </xsl:attribute> 
       </tax> 
      </xsl:for-each-group> 
     </report> 
    </xsl:template> 

</xsl:stylesheet> 

輸出

<report> 
    <tax name="FEDERAL" total="350"/> 
    <tax name="STATE" total="50"/> 
</report> 
+0

+1這是一個正確的XSLT 2.0解決方案。但是如果你要匹配'BILL'元素,你最好使用'TAX'元素的相對路徑。 – 2011-03-07 20:55:13

+0

@Alejandro:你能解釋一下你的評論嗎? – MarcoS 2011-03-07 21:03:11

+1

是的。如果你打算用'BILL'進行分組,不要使用每個'TAX',只使用它的後綴,如'。TAX'或'*/*/*/TAX',否則worng結果可能會出現幾個文件中的「BILL」元素。 – 2011-03-07 21:11:28

相關問題