Xml 如何基于节点属性动态更改xslt页面序列?
我遇到的问题的淡化版本是这样的。对于XML文件,如:Xml 如何基于节点属性动态更改xslt页面序列?,xml,xslt,xsl-fo,apache-fop,Xml,Xslt,Xsl Fo,Apache Fop,我遇到的问题的淡化版本是这样的。对于XML文件,如: <?xml version="1.0" encoding="UTF-8"?> <items> <item cols="1">Item 1</item> <item cols="1">Item 2</item> <item cols="1">Item 3</item> <item cols="1">Item
<?xml version="1.0" encoding="UTF-8"?>
<items>
<item cols="1">Item 1</item>
<item cols="1">Item 2</item>
<item cols="1">Item 3</item>
<item cols="1">Item 4</item>
<item cols="1">Item 5</item>
<item cols="1">Item 6</item>
<item cols="1">Item 7</item>
<item cols="1">Item 8</item>
<item cols="1">Item 9</item>
<item cols="2">Item 10</item>
<item cols="1">Item 11</item>
<item cols="1">Item 12</item>
<item cols="1">Item 13</item>
<item cols="1">Item 14</item>
<item cols="1">Item 15</item>
<item cols="1">Item 16</item>
<item cols="1">Item 17</item>
<item cols="1">Item 18</item>
</items>
项目1
项目2
项目3
项目4
项目5
项目6
项目7
项目8
项目9
项目10
项目11
项目12
项目13
项目14
项目15
项目16
项目17
项目18
我需要能够在单列页面布局中打印“cols=1”的“item”,在双列页面布局中打印“cols=2”的“item”。必须保留物品的顺序。具有相同@cols值的所有连续“项”都需要显示为连续流。每当@cols值发生变化时,我都需要切换到新页面,并根据需要更改布局
我在做这样的事情:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="one-column-page-master">
<fo:region-body margin-top="3cm" region-name="body" column-count="1"/>
</fo:simple-page-master>
<fo:simple-page-master master-name="two-column-page-master">
<fo:region-body margin-top="3cm" region-name="body" column-count="2"/>
<fo:region-before region-name="header" extent="2cm"/>
</fo:simple-page-master>
<fo:page-sequence-master master-name="one-column-page">
<fo:repeatable-page-master-reference master-reference="one-column-page-master"/>
</fo:page-sequence-master>
<fo:page-sequence-master master-name="two-column-page">
<fo:repeatable-page-master-reference master-reference="two-column-page-master"/>
</fo:page-sequence-master>
</fo:layout-master-set>
<xsl:for-each select="//item">
<xsl:choose>
<xsl:when test="@cols = preceding-sibling::item[1]/@cols">
<!--cols value hasn't changed, don't create a new page-sequence-->
<!--But we cannot directly add fo:flow as the child of fo:root! -->
<xsl:call-template name="itemtemplate"/>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="@cols = 1">
<fo:page-sequence master-reference="one-column-page">
<xsl:call-template name="itemtemplate"/>
</fo:page-sequence>
</xsl:when>
<xsl:otherwise>
<fo:page-sequence master-reference="two-column-page">
<xsl:call-template name="itemtemplate"/>
</fo:page-sequence>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</fo:root>
</xsl:template>
<xsl:template name="itemtemplate">
<fo:flow flow-name="body">
<fo:block margin-bottom="5cm">
<xsl:apply-templates/>
</fo:block>
</fo:flow>
</xsl:template>
</xsl:stylesheet>
但当然,问题是我要么必须在样式表中包含一个,要么不包含,我不能根据注释属性“动态”地决定是否添加一个。(除非我有一个元程序,首先动态创建样式表,但我希望只使用简单的静态样式表就可以实现这一点)
我需要能够在单列页面布局中打印具有“cols=1”的“项目”,以及在双列页面布局中打印具有“cols=2”的“项目”。必须保留项目的顺序。
最后,您希望按照适当的fo页面顺序,根据@cols
的值对相邻的项
元素进行分组
XSLT1.0指令,如xsl:choose
和xsl:for each
并不真正适合此任务。我想你得改变一下主意。下面是一个如何通过递归实现结果分组的示例
现在还不清楚每个流元素中要包含什么,然后我决定向您展示如何对元素进行分组;然后,您可以根据自己的需求调整代码
[XSLT1.0]
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="text()"/>
<xsl:template match="/*">
<fo:root>
<!-- layout master stuff -->
<xsl:apply-templates select="item"/>
</fo:root>
</xsl:template>
<!-- match @cols 1, first group occurrences -->
<xsl:template match="/*/item[@cols=1]
[not(preceding-sibling::item[1][@cols=1])]">
<fo:page-sequence master-reference="one-column-page">
<xsl:copy-of select="."/>
<xsl:apply-templates select="
following-sibling::*[1][self::item[@cols=1]]" mode="flow">
<xsl:with-param name="cols" select="1"/>
</xsl:apply-templates>
</fo:page-sequence>
</xsl:template>
<!-- match @cols 2, first group occurrences -->
<xsl:template match="/*/item[@cols=2]
[not(preceding-sibling::item[1][@cols=2])]">
<fo:page-sequence master-reference="two-column-page">
<xsl:copy-of select="."/>
<xsl:apply-templates select="
following-sibling::*[1][self::item[@cols=2]]" mode="flow">
<xsl:with-param name="cols" select="2"/>
</xsl:apply-templates>
</fo:page-sequence>
</xsl:template>
<!-- recursive match adjacent @cols -->
<xsl:template match="item" mode="flow">
<xsl:param name="cols"/>
<xsl:copy-of select="."/>
<xsl:apply-templates select="
following-sibling::*[1][self::item[@cols=$cols]]" mode="flow">
<xsl:with-param name="cols" select="$cols"/>
</xsl:apply-templates>
</xsl:template>
</xsl:stylesheet>
当应用于问题中提供的样本输入时,产生:
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:page-sequence master-reference="one-column-page">
<item cols="1">Item 1</item>
<item cols="1">Item 2</item>
<item cols="1">Item 3</item>
<item cols="1">Item 4</item>
<item cols="1">Item 5</item>
<item cols="1">Item 6</item>
<item cols="1">Item 7</item>
<item cols="1">Item 8</item>
<item cols="1">Item 9</item>
</fo:page-sequence>
<fo:page-sequence master-reference="two-column-page">
<item cols="2">Item 10</item>
</fo:page-sequence>
<fo:page-sequence master-reference="one-column-page">
<item cols="1">Item 11</item>
<item cols="1">Item 12</item>
<item cols="1">Item 13</item>
<item cols="1">Item 14</item>
<item cols="1">Item 15</item>
<item cols="1">Item 16</item>
<item cols="1">Item 17</item>
<item cols="1">Item 18</item>
</fo:page-sequence>
</fo:root>
项目1
项目2
项目3
项目4
项目5
项目6
项目7
项目8
项目9
项目10
项目11
项目12
项目13
项目14
项目15
项目16
项目17
项目18
这里是一个XSLT 2.0解决方案,它与组相邻使用:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<xsl:template match="/">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="one-column-page-master">
<fo:region-body margin-top="3cm" region-name="body"
column-count="1"/>
</fo:simple-page-master>
<fo:simple-page-master master-name="two-column-page-master">
<fo:region-body margin-top="3cm" region-name="body"
column-count="2"/>
<fo:region-before region-name="header" extent="2cm"/>
</fo:simple-page-master>
<fo:page-sequence-master master-name="one-column-page">
<fo:repeatable-page-master-reference
master-reference="one-column-page-master"/>
</fo:page-sequence-master>
<fo:page-sequence-master master-name="two-column-page">
<fo:repeatable-page-master-reference
master-reference="two-column-page-master"/>
</fo:page-sequence-master>
</fo:layout-master-set>
<xsl:apply-templates/>
</fo:root>
</xsl:template>
<xsl:template match="items">
<xsl:for-each-group select="item"
group-adjacent="@cols">
<xsl:choose>
<xsl:when test="@cols = 1">
<fo:page-sequence master-reference="one-column-page">
<fo:flow flow-name="body">
<xsl:for-each select="current-group()">
<xsl:apply-templates select="."/>
</xsl:for-each>
</fo:flow>
</fo:page-sequence>
</xsl:when>
<xsl:otherwise>
<fo:page-sequence master-reference="two-column-page">
<fo:flow flow-name="body">
<xsl:for-each select="current-group()">
<xsl:apply-templates select="."/>
</xsl:for-each>
</fo:flow>
</fo:page-sequence>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:template>
<xsl:template match="item">
<fo:block margin-bottom="5cm">
<xsl:apply-templates/>
</fo:block>
</xsl:template>
</xsl:stylesheet>
输出:
<?xml version="1.0" encoding="UTF-8"?>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="one-column-page-master">
<fo:region-body margin-top="3cm" region-name="body" column-count="1"/>
</fo:simple-page-master>
<fo:simple-page-master master-name="two-column-page-master">
<fo:region-body margin-top="3cm" region-name="body" column-count="2"/>
<fo:region-before region-name="header" extent="2cm"/>
</fo:simple-page-master>
<fo:page-sequence-master master-name="one-column-page">
<fo:repeatable-page-master-reference master-reference="one-column-page-master"/>
</fo:page-sequence-master>
<fo:page-sequence-master master-name="two-column-page">
<fo:repeatable-page-master-reference master-reference="two-column-page-master"/>
</fo:page-sequence-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="one-column-page">
<fo:flow flow-name="body">
<fo:block margin-bottom="5cm">Item 1</fo:block>
<fo:block margin-bottom="5cm">Item 2</fo:block>
<fo:block margin-bottom="5cm">Item 3</fo:block>
<fo:block margin-bottom="5cm">Item 4</fo:block>
<fo:block margin-bottom="5cm">Item 5</fo:block>
<fo:block margin-bottom="5cm">Item 6</fo:block>
<fo:block margin-bottom="5cm">Item 7</fo:block>
<fo:block margin-bottom="5cm">Item 8</fo:block>
<fo:block margin-bottom="5cm">Item 9</fo:block>
</fo:flow>
</fo:page-sequence>
<fo:page-sequence master-reference="two-column-page">
<fo:flow flow-name="body">
<fo:block margin-bottom="5cm">Item 10</fo:block>
</fo:flow>
</fo:page-sequence>
<fo:page-sequence master-reference="one-column-page">
<fo:flow flow-name="body">
<fo:block margin-bottom="5cm">Item 11</fo:block>
<fo:block margin-bottom="5cm">Item 12</fo:block>
<fo:block margin-bottom="5cm">Item 13</fo:block>
<fo:block margin-bottom="5cm">Item 14</fo:block>
<fo:block margin-bottom="5cm">Item 15</fo:block>
<fo:block margin-bottom="5cm">Item 16</fo:block>
<fo:block margin-bottom="5cm">Item 17</fo:block>
<fo:block margin-bottom="5cm">Item 18</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
项目1
项目2
项目3
项目4
项目5
项目6
项目7
项目8
项目9
项目10
项目11
项目12
项目13
项目14
项目15
项目16
项目17
项目18
@empo:太棒了!因此,基本方法是在主循环中处理关键的“项”(其中@cols发生了变化),并在递归模板调用中处理这些项的相邻节点。我使用了您的方法,并做了一些更改,使代码更简单,但这非常有效
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="text()"/>
<xsl:template match="/*">
<fo:root>
<xsl:for-each select="item">
<xsl:choose>
<xsl:when test="preceding-sibling::item[1]/@cols != @cols or position()=1">
<xsl:choose>
<xsl:when test="@cols = 1">
<fo:page-sequence master-reference="one-column-page">
<xsl:apply-templates select="." mode="recurse">
<xsl:with-param name="cols" select="@cols"/>
</xsl:apply-templates>
</fo:page-sequence>
</xsl:when>
<xsl:when test="@cols = 2">
<fo:page-sequence master-reference="two-column-page">
<xsl:apply-templates select="." mode="recurse">
<xsl:with-param name="cols" select="@cols"/>
</xsl:apply-templates>
</fo:page-sequence>
</xsl:when>
</xsl:choose>
</xsl:when>
</xsl:choose>
</xsl:for-each>
</fo:root>
</xsl:template>
<!-- recursive match adjacent @cols -->
<xsl:template match="item" mode="recurse">
<xsl:param name="cols"/>
<xsl:copy-of select="."/>
<xsl:apply-templates select="
following-sibling::*[1][self::item[@cols=$cols]]"
mode="recurse">
<xsl:with-param name="cols" select="$cols"/>
</xsl:apply-templates>
</xsl:template>
</xsl:stylesheet>
问得好。我想知道XSLT2.0的分组功能是否能为您解决这个问题。请为示例输入显示所需的输出XML(FO),以便