是 xslt 新手,我正在使用 xslt 1.0 从 xml 代码创建 PDF。
我的源数据如下。
<STATEMENT>
<STATEMENT_AGING>
<AGING>
<AGING_LABEL>Current</AGING_LABEL>
<AGING_AMOUNT>$28,927.43</AGING_AMOUNT>
</AGING>
<AGING>
<AGING_LABEL>1 - 30</AGING_LABEL>
<AGING_AMOUNT>$0.00</AGING_AMOUNT>
</AGING>
<AGING>
<AGING_LABEL>31 - 60</AGING_LABEL>
<AGING_AMOUNT>$0.00</AGING_AMOUNT>
</AGING>
<AGING>
<AGING_LABEL>61 - 90</AGING_LABEL>
<AGING_AMOUNT>$0.00</AGING_AMOUNT>
</AGING>
<AGING>
<AGING_LABEL>91 - 120</AGING_LABEL>
<AGING_AMOUNT>$0.00</AGING_AMOUNT>
</AGING>
<AGING>
<AGING_LABEL>Over 120</AGING_LABEL>
<AGING_AMOUNT>$0.00</AGING_AMOUNT>
</AGING>
</STATEMENT_AGING>
<GROUP
ID='1'
label=''>
<GROUP_LABEL />
<GROUP_NAME>SoleraStatementSection</GROUP_NAME>
<GROUP_TYPE>LABEL</GROUP_TYPE>
<GROUP_HIDE_FLAG>0</GROUP_HIDE_FLAG>
<GROUP_HEADER_ROW>
<COL
headerAlign='start'
headerFormat='text'
width='2cm'>Doc. #</COL>
<COL
headerAlign='start'
headerFormat='text'
width='1cm'>Doc. Type</COL>
<COL
headerAlign='start'
headerFormat='text'
width='1cm'>Doc. Date</COL>
<COL
headerAlign='start'
headerFormat='text'
width='1cm'>Due Date</COL>
<COL
headerAlign='center'
headerFormat='text'
width='1cm'>Currency</COL>
<COL
headerAlign='end'
headerFormat='currency'
width='1cm'>Original Amount</COL>
<COL
headerAlign='end'
headerFormat='currency'
width='1cm'>Balance</COL>
<COL
headerAlign='start'
headerFormat='number'
width='1cm'>ChildAccount</COL>
</GROUP_HEADER_ROW>
<GROUP_DATA_ROW>
<COL>2120-000023134</COL>
<COL>Invoice</COL>
<COL>2024-05-13T00:23:14.205918-05:00</COL>
<COL>2024-06-12T05:00:00.000000+00:00</COL>
<COL>USD</COL>
<COL>$13,247.46</COL>
<COL>$13,247.46</COL>
<COL>Price Acura</COL>
</GROUP_DATA_ROW>
<GROUP_DATA_ROW>
<COL>2120-000023135</COL>
<COL>Invoice</COL>
<COL>2024-05-13T00:36:37.008144-05:00</COL>
<COL>2024-06-12T05:00:00.000000+00:00</COL>
<COL>USD</COL>
<COL>$13,247.37</COL>
<COL>$13,247.37</COL>
<COL>Price Acura</COL>
</GROUP_DATA_ROW>
<GROUP_DATA_ROW>
<COL>2120-000023136</COL>
<COL>Invoice</COL>
<COL>2024-05-13T00:51:32.838201-05:00</COL>
<COL>2024-06-12T05:00:00.000000+00:00</COL>
<COL>USD</COL>
<COL>$2,432.60</COL>
<COL>$2,432.60</COL>
<COL>Price Honda</COL>
</GROUP_DATA_ROW>
</GROUP>
<GROUP ID='2'
label=''>
<GROUP_LABEL />
<GROUP_NAME>CreditData</GROUP_NAME>
<GROUP_TYPE>LABEL</GROUP_TYPE>
<GROUP_HIDE_FLAG>0</GROUP_HIDE_FLAG>
<GROUP_HEADER_ROW>
<COL
headerAlign='start'
headerFormat='text'
width='0cm'>Credit #</COL>
<COL
headerAlign='start'
headerFormat='text'
width='0cm'>Credit Type</COL>
<COL
headerAlign='start'
headerFormat='text'
width='0cm'>Credit Date</COL>
<COL
headerAlign='center'
headerFormat='text'
width='0cm'>Currency</COL>
<COL
headerAlign='end'
headerFormat='currency'
width='0cm'>Credit Amount</COL>
<COL
headerAlign='end'
headerFormat='currency'
width='0cm'>Unallocated Amnt</COL>
<COL
headerAlign='start'
headerFormat='text'
width='0cm'>ChildAccount</COL>
</GROUP_HEADER_ROW>
</GROUP>
<GROUP ID='3'
label=''>
<GROUP_LABEL />
<GROUP_NAME>PaymentSection</GROUP_NAME>
<GROUP_TYPE>LABEL</GROUP_TYPE>
<GROUP_HIDE_FLAG>0</GROUP_HIDE_FLAG>
<GROUP_HEADER_ROW>
<COL
headerAlign='start'
headerFormat='text'
width='0cm'>Payment #</COL>
<COL
headerAlign='start'
headerFormat='text'
width='0cm'>Payment Type</COL>
<COL
headerAlign='start'
headerFormat='text'
width='0cm'>Payment Date</COL>
<COL
headerAlign='center'
headerFormat='text'
width='0cm'>Currency</COL>
<COL
headerAlign='end'
headerFormat='currency'
width='0cm'>Payment Amount</COL>
<COL
headerAlign='end'
headerFormat='currency'
width='0cm'>Unallocated Amnt</COL>
<COL
headerAlign='start'
headerFormat='text'
width='0cm'>ChildAccount</COL>
</GROUP_HEADER_ROW>
</GROUP>
</STATEMENT>
问题是,在 GROUPID 1 中,我尝试按 custName 或 col[8] 对数据进行分组,但我想在每次 custName 更改时打印标题。我尝试将值存储到变量中,但一旦循环再次出现,该值就会丢失,因此我尝试使用 IF 进行评估时不起作用。
有谁知道我该如何管理这个问题,因为我看到了很多使用 diff 方法的答案,但我不太理解所有这些答案,因为我的源 xml 有“通用”标签而不是真实的标签名称。
PS。我尝试了选择和 if 条件,但它们都不起作用。
<xsl:template name= "DetailSectionG1">
<fo:block space-before="8mm" font-weight="bold" color="{$blue-color}" keep-together.within-page="always" keep-with-next="always">
<fo:table width="100%" border-collapse="collapse" table-layout="fixed">
<fo:table-column column-width="{$left-margin}"/>
<fo:table-column column-width="proportional-column-width(1)"/>
<fo:table-column column-width="{$right-margin}"/>
<fo:table-body>
<fo:table-row>
<fo:table-cell>
<fo:block/>
</fo:table-cell>
<fo:table-cell>
<fo:block font-size="{$large-font-size}" padding-top="3 * {$padding}" padding-bottom="{$padding}">
Statement Details
</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
</fo:block>
<xsl:choose>
<xsl:when test="GROUP[@ID=1]/GROUP_DATA_ROW/COL[1] !=''">
<fo:block>
<fo:table width="100%" border-collapse="collapse" table-layout="fixed">
<fo:table-column column-width="{$data-left-margin}"/>
<fo:table-column column-width="30mm"/>
<fo:table-column column-width="25mm"/>
<fo:table-column column-width="25mm"/>
<fo:table-column column-width="25mm"/>
<fo:table-column column-width="22mm"/>
<fo:table-column column-width="27mm"/>
<fo:table-column column-width="25mm"/>
<fo:table-column column-width="{$data-right-margin}"/>
<xsl:for-each select="/STATEMENT/GROUP[@ID=1]/GROUP_DATA_ROW[generate-id(.)=generate-id(key('groupDataRow', concat(COL[position() = 8],'+',COL[position() = 1])))]">
<xsl:variable name="vGroup" select="key('kAllFields', concat(COL[position() = 8],'+',COL[position() = 1]))"/>
<fo:table-body>
<xsl:choose>
<xsl:when test="custName != COL[position() = 8] or position() = 1">
<fo:table-row>
<fo:table-cell>
<fo:block/>
</fo:table-cell>
<fo:table-cell>
<fo:block font-weight="bold" color="{$blue-color}" keep-together.within-page="always" keep-with-next="always" padding-bottom="{$padding}"/>
<!--xsl:value-of select="COL[position() = 8]"/-->
<!--/fo:block-->
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell>
<fo:block/>
</fo:table-cell>
<xsl:call-template name="HeaderCell">
<xsl:with-param name="position">1</xsl:with-param>
<xsl:with-param name="color" select="$blue-color"/>
</xsl:call-template>
<xsl:call-template name="HeaderCell">
<xsl:with-param name="position">2</xsl:with-param>
<xsl:with-param name="color" select="$blue-color"/>
</xsl:call-template>
<xsl:call-template name="HeaderCell">
<xsl:with-param name="position">3</xsl:with-param>
<xsl:with-param name="color" select="$blue-color"/>
</xsl:call-template>
<xsl:call-template name="HeaderCell">
<xsl:with-param name="position">4</xsl:with-param>
<xsl:with-param name="color" select="$blue-color"/>
</xsl:call-template>
<xsl:call-template name="HeaderCell">
<xsl:with-param name="position">5</xsl:with-param>
<xsl:with-param name="color" select="$blue-color"/>
</xsl:call-template>
<xsl:call-template name="HeaderCell">
<xsl:with-param name="position">6</xsl:with-param>
<xsl:with-param name="color" select="$blue-color"/>
</xsl:call-template>
<xsl:call-template name="HeaderCell">
<xsl:with-param name="position">7</xsl:with-param>
<xsl:with-param name="color" select="$blue-color"/>
</xsl:call-template>
</fo:table-row>
</xsl:when>
<xsl:otherwise/>
</xsl:choose>
<!--xsl:if test="{$acctName} != COL[position() = 8] or position() = 1"> </xsl:if-->
<fo:table-row>
<fo:table-cell>
<fo:block/>
</fo:table-cell>
<xsl:call-template name="Cell">
<xsl:with-param name="position">1</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="Cell">
<xsl:with-param name="position">2</xsl:with-param>
</xsl:call-template>
<fo:table-cell>
<fo:block color="{$base-color}" padding-bottom="{$small-padding}">
<xsl:attribute name="end-indent">1mm</xsl:attribute>
<xsl:attribute name="text-align">
<xsl:value-of select="../GROUP_HEADER_ROW[1]/COL[position() = 3]/@headerAlign"/>
</xsl:attribute>
<xsl:call-template name="getDate">
<xsl:with-param name="value" select="COL[position()=3]"/>
</xsl:call-template>
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block color="{$base-color}" padding-bottom="{$small-padding}">
<xsl:attribute name="end-indent">1mm</xsl:attribute>
<xsl:attribute name="text-align">
<xsl:value-of select="../GROUP_HEADER_ROW[1]/COL[position() = 4]/@headerAlign"/>
</xsl:attribute>
<xsl:call-template name="getDate">
<xsl:with-param name="value" select="COL[position()=4]"/>
</xsl:call-template>
</fo:block>
</fo:table-cell>
<xsl:call-template name="Cell">
<xsl:with-param name="position">5</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="Cell">
<xsl:with-param name="position">6</xsl:with-param>
</xsl:call-template>
<xsl:call-template name="Cell">
<xsl:with-param name="position">7</xsl:with-param>
</xsl:call-template>
</fo:table-row>
<xsl:variable name="custName">
<xsl:value-of select="COL[position() = 8]"/>
</xsl:variable>
</fo:table-body>
</xsl:for-each>
</fo:table>
</fo:block>
</xsl:when>
<xsl:otherwise>
<fo:block keep-together.within-page="always" keep-with-next="always">
<fo:table width="100%" border-collapse="collapse" table-layout="fixed">
<fo:table-column column-width="{$left-margin}"/>
<fo:table-column column-width="proportional-column-width(1)"/>
<fo:table-column column-width="{$right-margin}"/>
<fo:table-body>
<fo:table-row>
<fo:table-cell>
<fo:block/>
</fo:table-cell>
<fo:table-cell>
<fo:block color="{$base-color}" padding-bottom="{$small-padding}" end-indent="1mm">
No invoices to display
</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
</fo:block>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
我期望的 PDF 就是这个。
[期望输出] (https://i.sstatic.net/GPAPwxHQ.png)
目前我尝试的验证不起作用,并且 acctName 和标头表仅显示一次。
您似乎在分组方面遇到了困难,请注意,在 XSLT 2 或更高版本中,分组要容易得多,您可以这样做
<xsl:template match="GROUP[@ID = 1]">
<xsl:for-each-group select="GROUP_DATA_ROW" group-by="COL[8]">
<group key="{current-grouping-key()}">
<xsl:sequence select="current-group()"/>
</group>
</xsl:for-each-group>
</xsl:template>
并获得例如
<group key="Price Acura">
<GROUP_DATA_ROW>
<COL>2120-000023134</COL>
<COL>Invoice</COL>
<COL>2024-05-13T00:23:14.205918-05:00</COL>
<COL>2024-06-12T05:00:00.000000+00:00</COL>
<COL>USD</COL>
<COL>$13,247.46</COL>
<COL>$13,247.46</COL>
<COL>Price Acura</COL>
</GROUP_DATA_ROW>
<GROUP_DATA_ROW>
<COL>2120-000023135</COL>
<COL>Invoice</COL>
<COL>2024-05-13T00:36:37.008144-05:00</COL>
<COL>2024-06-12T05:00:00.000000+00:00</COL>
<COL>USD</COL>
<COL>$13,247.37</COL>
<COL>$13,247.37</COL>
<COL>Price Acura</COL>
</GROUP_DATA_ROW>
</group>
<group key="Price Honda">
<GROUP_DATA_ROW>
<COL>2120-000023136</COL>
<COL>Invoice</COL>
<COL>2024-05-13T00:51:32.838201-05:00</COL>
<COL>2024-06-12T05:00:00.000000+00:00</COL>
<COL>USD</COL>
<COL>$2,432.60</COL>
<COL>$2,432.60</COL>
<COL>Price Honda</COL>
</GROUP_DATA_ROW>
</group>
因此您可以轻松地拥有两个组和每个组的正确数据,我没有尝试输出想要的 XSL-FO,但是一旦您解决了分组问题就应该很容易。
请注意,XSLT 3(XSLT 的当前版本)在多种平台、浏览器 (https://www.saxonica.com/download/javascript.xml) 和 Node.js () 中受支持https://www.npmjs.com/package/saxon-js)您可以使用 SaxonJS 2(2.6 是当前版本),对于 Java,您可以在 Maven 上找到 Saxon HE https://mvnrepository.com/artifact/ net.sf.saxon/Saxon-HE 或在 Github 上,对于 Python,有 SaxonCHE (https://pypi.org/project/saxonche/),对于 .NET,有 Saxon .NET HE (https:/ /www.nuget.org/packages/Saxon-HE,https://www.nuget.org/packages/SaxonHE12s9apiExtensions)。
尽管如此,如果您在受限环境中工作而被迫使用 XSLT 1,请使用密钥
<xsl:key name="group" match="GROUP[@ID = 1]/GROUP_DATA_ROW" use="COL[8]"/>
<xsl:template match="GROUP[@ID = 1]">
<xsl:for-each select="GROUP_DATA_ROW[generate-id() = generate-id(key('group', COL[8])[1])]">
<group key="{COL[8]}">
<xsl:copy-of select="key('group', COL[8])"/>
</group>
</xsl:for-each>
</xsl:template>