2011-03-07 77 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

相关问题