Xslt 嵌套在for each循环中的每个(-group)的XSL
我们的目标是打印发票行,首先按发票服务类型分组,然后按工作描述和员工姓名分组,方式如下: 咨询 实际工作 Gummo-2014-03-03 泽波-2014-02-24 哈波-2014-03-07 讽刺的话 格鲁乔-2014-02-24 竖琴演奏 哈波-2014-02-28 发生的费用 雪茄 我们从一个结构比较复杂的xml文件中提取这些数据,即丹麦国家OIOUBL标准:Xslt 嵌套在for each循环中的每个(-group)的XSL,xslt,xslt-2.0,Xslt,Xslt 2.0,我们的目标是打印发票行,首先按发票服务类型分组,然后按工作描述和员工姓名分组,方式如下: 咨询 实际工作 Gummo-2014-03-03 泽波-2014-02-24 哈波-2014-03-07 讽刺的话 格鲁乔-2014-02-24 竖琴演奏 哈波-2014-02-28 发生的费用 雪茄 我们从一个结构比较复杂的xml文件中提取这些数据,即丹麦国家OIOUBL标准: <Invoice> (...) <cac:InvoiceLine> <cbc:ID&g
<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>
我们从XSL样式表开始,先做一个简单的for each循环,按cac:InvoiceLine/cac:Item/cac:AdditionalItemIdentification将发票行分组咨询行标记为10000,费用行标记为20000;然后,我们需要确保每个咨询行首先按照工作描述cac:InvoiceLine/cac:Item/cbc:description进行分组。我们已经尝试了多次进一步的for-each循环、for-each-group和使用键的解决方案的迭代。然而,它们似乎都依赖于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 -->
最好尽可能避免重复代码。目前还不清楚你是否只会有咨询和费用,但可以放心地假设不会。我还将假设每个InvoiceLine可以有多个Item元素,尽管如果不是这样,给出的解决方案仍然有效 无论如何,您应该首先按照项目元素的AdditionalItemIdentification对项目元素进行分组。这将为您的咨询和费用创建组
<xsl:for-each-group select="cac:InvoiceLine/cac:Item"
group-by="cac:AdditionalItemIdentification/cbc:ID">
<xsl:for-each-group select="current-group()[cac:SellersItemIdentification/cbc:ID != '']"
group-by="cac:SellersItemIdentification/cbc:ID">
然后,只需输出名称,即可获得每个组的标题
<xsl:value-of select="cbc:Name" />
现在,在当前的Item元素组中,您需要根据描述进行分组
最后,在该组中,您仍然希望按SellerItemIdentification对项目进行分组,尽管您可能需要额外检查,因为在发生费用的情况下,并非所有项目元素都有这些检查
<xsl:for-each-group select="cac:InvoiceLine/cac:Item"
group-by="cac:AdditionalItemIdentification/cbc:ID">
<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>
那么你面临的问题是什么?您的代码对每个组都执行select=../cbc:DescriptionTested,但在您发布的输入代码段中,我甚至找不到名为cbc:DescriptionTested的元素。您可能希望避免for循环。XSLT首先是一种模式匹配练习。我将把它分为两个步骤:第一步:将源XML转换成具有正确结构的XML格式,第二步:用FO布局装饰它。@stwissel:不幸的是,XML格式无法更改,因为它是政府标准。或者你的意思是将相关数据放入某种临时xml文件或数组中,然后从中提取数据?@MartinHonnen:你说得对-cbc:DescriptionEnded一定是某种复制/粘贴错误-应该是cvc:Description,我已经相应地更正了上面的帖子。嗨,Lars,第二个选择就是我的意思。将固定的政府格式转换为以正确的顺序包含所需内容的格式,并使用第二个样式表将其输入XSL:FO,该样式表进行FO装饰。在一切正常后,您不需要写出temp格式,在开发过程中,中间格式是一个很好的调试入口点