XSL for-each(-group)嵌套在for-each循环中

时间:2014-05-08 12:46:03

标签: xslt xslt-2.0

我们的目标是打印发票行,这些发票行首先按照被调用的服务类型分组,然后按作业描述和成员名称打印:

咨询

做实际工作
Gummo - 2014-03-03
Zeppo - 2014-02-24
Harpo - 2014-03-07

Snide备注
格劳乔 - 2014-02-24

竖琴演奏
Harpo - 2014-02-28

费用增加

雪茄

我们从结构有些复杂的xml文件中提取这些数据,即丹麦国家OIOUBL标准:

<Invoice>

(...)

<cac:InvoiceLine>
    <cbc:ID>1</cbc:ID>
    <cbc:Note>Bla bla</cbc:Note>
    <cbc:InvoicedQuantity unitCode="EA">1.2500</cbc:InvoicedQuantity>
    <cbc:LineExtensionAmount currencyID="DKK">1395.0000</cbc:LineExtensionAmount>
    <cac:Delivery>
      <cbc:ActualDeliveryDate>2014-02-24</cbc:ActualDeliveryDate>
    </cac:Delivery>
    <cac:TaxTotal>
      <cbc:TaxAmount currencyID="DKK">348.75</cbc:TaxAmount>
      <cac:TaxSubtotal>
        <cbc:TaxableAmount currencyID="DKK">1395.00</cbc:TaxableAmount>
        <cbc:TaxAmount currencyID="DKK">348.75</cbc:TaxAmount>
        <cac:TaxCategory>
          <cbc:ID schemeAgencyID="320" schemeID="urn:oioubl:id:taxcategoryid-1.1">StandardRated</cbc:ID>
          <cbc:Percent>25.00</cbc:Percent>
          <cac:TaxScheme>
            <cbc:ID schemeAgencyID="320" schemeID="urn:oioubl:id:taxschemeid-1.1">63</cbc:ID>
            <cbc:Name>Moms</cbc:Name>
          </cac:TaxScheme>
        </cac:TaxCategory>
      </cac:TaxSubtotal>
    </cac:TaxTotal>
    <cac:Item>
      <cbc:Description>Snide Remarks</cbc:Description>
      <cbc:Name>CONSULTANCY</cbc:Name>
      <cac:SellersItemIdentification>
        <cbc:ID schemeAgencyID="9" schemeID="foo">Groucho</cbc:ID>
        <cbc:ExtendedID>Timer</cbc:ExtendedID>
      </cac:SellersItemIdentification>
      <cac:StandardItemIdentification>
        <cbc:ID schemeAgencyID="9" schemeID="foo">2014-02-24</cbc:ID>
      </cac:StandardItemIdentification>
      <cac:AdditionalItemIdentification>
        <cbc:ID schemeAgencyID="9" schemeID="foo">10000</cbc:ID>
      </cac:AdditionalItemIdentification>
    </cac:Item>
    <cac:Price>
      <cbc:PriceAmount currencyID="DKK">1116.0000</cbc:PriceAmount>
      <cbc:BaseQuantity unitCode="EA">1</cbc:BaseQuantity>
    </cac:Price>
  </cac:InvoiceLine>

(...)

  <cac:InvoiceLine>
    <cbc:ID>6</cbc:ID>
    <cbc:InvoicedQuantity unitCode="EA">1.0000</cbc:InvoicedQuantity>
    <cbc:LineExtensionAmount currencyID="DKK">1116.0000</cbc:LineExtensionAmount>
    <cac:Delivery>
      <cbc:ActualDeliveryDate>2014-03-06</cbc:ActualDeliveryDate>
    </cac:Delivery>
    <cac:TaxTotal>
      <cbc:TaxAmount currencyID="DKK">279.00</cbc:TaxAmount>
      <cac:TaxSubtotal>
        <cbc:TaxableAmount currencyID="DKK">1116.00</cbc:TaxableAmount>
        <cbc:TaxAmount currencyID="DKK">279.00</cbc:TaxAmount>
        <cac:TaxCategory>
          <cbc:ID schemeAgencyID="320" schemeID="urn:oioubl:id:taxcategoryid-1.1">StandardRated</cbc:ID>
          <cbc:Percent>25.00</cbc:Percent>
          <cac:TaxScheme>
            <cbc:ID schemeAgencyID="320" schemeID="urn:oioubl:id:taxschemeid-1.1">63</cbc:ID>
            <cbc:Name>Moms</cbc:Name>
          </cac:TaxScheme>
        </cac:TaxCategory>
      </cac:TaxSubtotal>
    </cac:TaxTotal>
    <cac:Item>
      <cbc:Description>Cigars</cbc:Description>
      <cbc:Name>EXPENSES INCURRED</cbc:Name>
      <cac:SellersItemIdentification>
        <cbc:ID schemeAgencyID="9" schemeID="foo"></cbc:ID>
        <cbc:ExtendedID>Timer</cbc:ExtendedID>
      </cac:SellersItemIdentification>
      <cac:StandardItemIdentification>
        <cbc:ID schemeAgencyID="9" schemeID="foo">2014-03-06</cbc:ID>
      </cac:StandardItemIdentification>
      <cac:AdditionalItemIdentification>
        <cbc:ID schemeAgencyID="9" schemeID="foo">20000</cbc:ID>
      </cac:AdditionalItemIdentification>
    </cac:Item>
    <cac:Price>
      <cbc:PriceAmount currencyID="DKK">1116.0000</cbc:PriceAmount>
      <cbc:BaseQuantity unitCode="EA">1</cbc:BaseQuantity>
    </cac:Price>
  </cac:InvoiceLine>

  </Invoice>

我们通过执行简单的for-each循环来启动我们的XSL样式表,该循环按cac对发票行进行分组:InvoiceLine / cac:Item / cac:AdditionalItemIdentification(顾问行标记为10000,费用行标记为20000);然后,我们需要确保每个咨询行首先按职务描述分组(cac:InvoiceLine / cac:Item / cbc:Description)。我们已经尝试了几次迭代,每个循环,每个组和使用密钥的解决方案。但是,它们似乎都依赖于XPath问题

<xsl:choose>
<xsl:when test="$layouttype = '1'">

    <xsl:for-each select="cac:InvoiceLine/cac:Item/cac:AdditionalItemIdentification[cbc:ID='10000']">
        <!-- Invoice headline - Printed once-->
        <xsl:if test="number(position()) = 1">
            <fo:table-row margin-left="0mm" margin-right="0mm" white-space="normal">
                <!-- see if period is empty so colspan should be = 2 -->
                <xsl:choose>
                    <xsl:when test="../cac:StandardItemIdentification/cbc:ID != 'n/a'">
                        <fo:table-cell display-align="after">
                            <fo:block margin-bottom="1mm" font-weight="bold">
                                <xsl:value-of select="../cbc:Name"/>
                            </fo:block>
                        </fo:table-cell>
                    </xsl:when>
                    <xsl:otherwise>
                        <fo:table-cell number-columns-spanned="2" display-align="after">
                            <fo:block margin-bottom="1mm" font-weight="bold">
                                <xsl:value-of select="../cbc:Name"/>
                            </fo:block>
                        </fo:table-cell>
                    </xsl:otherwise>
                </xsl:choose>
            </fo:table-row>
        </xsl:if>

        <!-- the actual invoice line -->
        <!-- and this is where it gets tricky... -->

        <xsl:for-each-group select="../cbc:Description" group-by="../cbc:Description">
            <fo:table-row>
                <fo:table-cell>
                    <fo:block><xsl:value-of select="../cbc:Description"/></fo:block>
                </fo:table-cell>
            </fo:table-row>


            <xsl:for-each select="current-group()">

                <fo:table-row>
                    <fo:table-cell>

                        <fo:block>
                            <xsl:value-of select="../cac:SellersItemIdentification/cbc:ID"/>
                        </fo:block>

                    </fo:table-cell>
                </fo:table-row>

            </xsl:for-each>

        </xsl:for-each-group>

    </xsl:for-each>

    <xsl:for-each select="cac:InvoiceLine/cac:Item/cac:AdditionalItemIdentification[cbc:ID='20000']">

<!-- then the same pattern is repeated -->

1 个答案:

答案 0 :(得分:0)

最好尽可能避免重复代码。目前尚不清楚你是否只会有“咨询”和“费用发生”,但可以安全地假设没有。我还假设每个 InvoiceLine 可以有多个 Item 元素(尽管如果不是这样,解决方案仍然有用)。

无论如何,您可以从 AdditionalItemIdentification Item 元素进行分组开始。这将为“咨询”和“费用发生”

创建您的组
<xsl:for-each-group select="cac:InvoiceLine/cac:Item" 
                    group-by="cac:AdditionalItemIdentification/cbc:ID">

然后,只需输出名称

即可完成每组的标题
<xsl:value-of select="cbc:Name" />

现在,在当前组( Item )元素中,您需要按说明

进行分组
<xsl:for-each-group select="current-group()" 
                    group-by="cbc:Description">

最后,在此群组中(仍然是项目),您希望按 SellersItemIdentification 分组,但您可能需要额外检查,因为并非所有项目元素具有它们(在“Expenses Incurred”的情况下

<xsl:for-each-group select="current-group()[cac:SellersItemIdentification/cbc:ID != '']" 
                    group-by="cac:SellersItemIdentification/cbc:ID">

输出当前的“卖方”将是使用分组键和其他字段的情况:

<xsl:value-of select="current-grouping-key()" />
<xsl:value-of select="cac:StandardItemIdentification/cbc:ID" />

由于我不太了解XSL-FO,作为示例提供的XSLT将只输出模糊的“表”和“行”元素,但它应该给你一般的想法。

试试这个XSLT:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" 
                xmlns:cac="cac" xmlns:cbc="cbc" exclude-result-prefixes="cac cbc">
    <xsl:output indent="yes"/>
    <xsl:template match="Invoice">
        <xsl:for-each-group select="cac:InvoiceLine/cac:Item" group-by="cac:AdditionalItemIdentification/cbc:ID">
            <table>
                <row><xsl:value-of select="cbc:Name" /></row>
                <xsl:for-each-group select="current-group()" group-by="cbc:Description">
                    <row><xsl:value-of select="cbc:Description" /></row>

                    <xsl:for-each-group select="current-group()[cac:SellersItemIdentification/cbc:ID != '']" group-by="cac:SellersItemIdentification/cbc:ID">
                        <row>
                            <xsl:value-of select="current-grouping-key()" /> - <xsl:value-of select="cac:StandardItemIdentification/cbc:ID" />
                        </row>
                    </xsl:for-each-group>                    
                </xsl:for-each-group>
            </table>
        </xsl:for-each-group>
    </xsl:template>
</xsl:stylesheet>

这应输出以下内容(根据您提供的样本,仅包括Groucho,而不是可怜的旧Zeppo或Harpo)

<table>
   <row>CONSULTANCY</row>
   <row>Snide Remarks</row>
   <row>Groucho - 2014-02-24</row>
</table>
<table>
   <row>EXPENSES INCURRED</row>
   <row>Cigars</row>
</table>