XSL:FO 为 PDF 生成应用 html 定义规则时出现问题
XSL:FO Problem in applying html definition rules for PDF generation
我正在通过 apache FOP 从模型 class 读取动态数据,从 xsl:fo 生成 pdf。以下是 xsl:fo 结构:
<xsl:template match="ProductData">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="simple"
page-height="20cm" page-width="10.5cm" margin-left="0.2cm"
margin-right="0.2cm">
<fo:region-body margin-top="0.5cm" />
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="simple">
<fo:flow flow-name="xsl-region-body">
<fo:block font-family="Arial" font-size="7pt" font-weight="normal">
<fo:table border-left-style="double" border-right-style="double"
border-top-style="double" border-width="1mm" width="18.0cm">
<fo:table-body height="2cm">
<fo:table-row border-top="solid 0.3mm #E0E0E0">
<fo:table-cell>
<fo:block margin-left="" margin-right="1.5cm"
margin-top="0.0cm">
<fo:external-graphic width="3cm" height="2cm">
<xsl:attribute name="src"><xsl:value-of
select="pdfLogo" /></xsl:attribute>
</fo:external-graphic>
</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
<fo:table>
<fo:table-column column-number="1" column-width="3cm" />
<fo:table-column column-number="2" column-width="2cm" />
<fo:table-column column-number="3" column-width="5cm" />
<fo:table-body height="10cm">
<xsl:for-each select="./productList/product">
<fo:table-row border="solid 0.1mm black">
<fo:table-cell text-align="left">
<fo:block>
<xsl:value-of select="name" />
</fo:block>
</fo:table-cell>
<fo:table-cell text-align="center">
<fo:block>
<xsl:value-of select="productDescription" />
</fo:block>
</fo:table-cell>
<fo:table-cell text-align="left">
<fo:block>
<xsl:value-of select="price" />
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:for-each>
</fo:table-body>
</fo:table>
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
这里 <xsl:value-of select="productDescription" />
是一个文本数据,它有 html 个标签,因此要保留格式。所以我创建了一组规则如下:
<xsl:template match="p">
<fo:block font-size="12pt" line-height="15pt"
space-after="12pt">
<xsl:apply-templates select="*|text()"/>
</fo:block>
</xsl:template>
<xsl:template match="br">
<fo:block>
</fo:block>
</xsl:template>
<xsl:template match="ul">
<fo:list-block provisional-distance-between-starts="1cm"
provisional-label-separation="0.5cm">
<xsl:attribute name="space-after">
<xsl:choose>
<xsl:when test="ancestor::ul or ancestor::ol">
<xsl:text>0pt</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>12pt</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:attribute name="start-indent">
<xsl:variable name="ancestors">
<xsl:choose>
<xsl:when test="count(ancestor::ol) or count(ancestor::ul)">
<xsl:value-of select="1 +
(count(ancestor::ol) +
count(ancestor::ul)) *
1.25"/>
</xsl:when>
<xsl:otherwise>
<xsl:text>1</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:value-of select="concat($ancestors, 'cm')"/>
</xsl:attribute>
<xsl:apply-templates select="*"/>
</fo:list-block>
</xsl:template>
<xsl:template match="ul/li">
<fo:list-item>
<fo:list-item-label end-indent="label-end()">
<fo:block>•</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="body-start()">
<fo:block>
<xsl:apply-templates select="*|text()"/>
</fo:block>
</fo:list-item-body>
</fo:list-item>
</xsl:template>
但是,我不知道如何将它们全部应用到 productDescription 文本,因为 html 定义的这些模板必须驻留在主模板之外?
原样 How do I display output variable text in XSL,替换为:
<xsl:value-of select="productDescription" />
与:
<xsl:apply-templates select="productDescription" />
由于 FOP 使用 Xalan,并且如 XSLT 1.0 规范中所述(参见 https://www.w3.org/TR/1999/REC-xslt-19991116#section-Applying-Template-Rules and https://www.w3.org/TR/1999/REC-xslt-19991116#built-in-rule):
- 当内置 Xalan 到达
<xsl:apply-templates select="productDescription" />
时,它将尝试为 productDescription
. 寻找模板规则
- 在
productDescription
没有模板规则的情况下,会回退到元素的内置模板规则,处理productDescription
元素的子节点。
- 当 Xalan 处理
p
等 productDescription
的子元素时,它会优先使用样式表中的模板,而不是回退到内置规则(因为规则关于模板优先级的设置就是这样。
- 文本节点的内置模板规则会将文本节点复制到结果树。
我正在通过 apache FOP 从模型 class 读取动态数据,从 xsl:fo 生成 pdf。以下是 xsl:fo 结构:
<xsl:template match="ProductData">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="simple"
page-height="20cm" page-width="10.5cm" margin-left="0.2cm"
margin-right="0.2cm">
<fo:region-body margin-top="0.5cm" />
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="simple">
<fo:flow flow-name="xsl-region-body">
<fo:block font-family="Arial" font-size="7pt" font-weight="normal">
<fo:table border-left-style="double" border-right-style="double"
border-top-style="double" border-width="1mm" width="18.0cm">
<fo:table-body height="2cm">
<fo:table-row border-top="solid 0.3mm #E0E0E0">
<fo:table-cell>
<fo:block margin-left="" margin-right="1.5cm"
margin-top="0.0cm">
<fo:external-graphic width="3cm" height="2cm">
<xsl:attribute name="src"><xsl:value-of
select="pdfLogo" /></xsl:attribute>
</fo:external-graphic>
</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
<fo:table>
<fo:table-column column-number="1" column-width="3cm" />
<fo:table-column column-number="2" column-width="2cm" />
<fo:table-column column-number="3" column-width="5cm" />
<fo:table-body height="10cm">
<xsl:for-each select="./productList/product">
<fo:table-row border="solid 0.1mm black">
<fo:table-cell text-align="left">
<fo:block>
<xsl:value-of select="name" />
</fo:block>
</fo:table-cell>
<fo:table-cell text-align="center">
<fo:block>
<xsl:value-of select="productDescription" />
</fo:block>
</fo:table-cell>
<fo:table-cell text-align="left">
<fo:block>
<xsl:value-of select="price" />
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:for-each>
</fo:table-body>
</fo:table>
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
这里 <xsl:value-of select="productDescription" />
是一个文本数据,它有 html 个标签,因此要保留格式。所以我创建了一组规则如下:
<xsl:template match="p">
<fo:block font-size="12pt" line-height="15pt"
space-after="12pt">
<xsl:apply-templates select="*|text()"/>
</fo:block>
</xsl:template>
<xsl:template match="br">
<fo:block>
</fo:block>
</xsl:template>
<xsl:template match="ul">
<fo:list-block provisional-distance-between-starts="1cm"
provisional-label-separation="0.5cm">
<xsl:attribute name="space-after">
<xsl:choose>
<xsl:when test="ancestor::ul or ancestor::ol">
<xsl:text>0pt</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>12pt</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:attribute name="start-indent">
<xsl:variable name="ancestors">
<xsl:choose>
<xsl:when test="count(ancestor::ol) or count(ancestor::ul)">
<xsl:value-of select="1 +
(count(ancestor::ol) +
count(ancestor::ul)) *
1.25"/>
</xsl:when>
<xsl:otherwise>
<xsl:text>1</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:value-of select="concat($ancestors, 'cm')"/>
</xsl:attribute>
<xsl:apply-templates select="*"/>
</fo:list-block>
</xsl:template>
<xsl:template match="ul/li">
<fo:list-item>
<fo:list-item-label end-indent="label-end()">
<fo:block>•</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="body-start()">
<fo:block>
<xsl:apply-templates select="*|text()"/>
</fo:block>
</fo:list-item-body>
</fo:list-item>
</xsl:template>
但是,我不知道如何将它们全部应用到 productDescription 文本,因为 html 定义的这些模板必须驻留在主模板之外?
原样 How do I display output variable text in XSL,替换为:
<xsl:value-of select="productDescription" />
与:
<xsl:apply-templates select="productDescription" />
由于 FOP 使用 Xalan,并且如 XSLT 1.0 规范中所述(参见 https://www.w3.org/TR/1999/REC-xslt-19991116#section-Applying-Template-Rules and https://www.w3.org/TR/1999/REC-xslt-19991116#built-in-rule):
- 当内置 Xalan 到达
<xsl:apply-templates select="productDescription" />
时,它将尝试为productDescription
. 寻找模板规则
- 在
productDescription
没有模板规则的情况下,会回退到元素的内置模板规则,处理productDescription
元素的子节点。 - 当 Xalan 处理
p
等productDescription
的子元素时,它会优先使用样式表中的模板,而不是回退到内置规则(因为规则关于模板优先级的设置就是这样。 - 文本节点的内置模板规则会将文本节点复制到结果树。