使用 fo:list-block 生成 PDF 时右对齐 xml 数据
Right align xml data while generating PDF using fo:list-block
我的 XML 输入中有数字列表并且我能够将列表主体(文本内容)对齐以右对齐,但数字仍保持左对齐。如何将包括 numbers/bullets 在内的整个列表向右对齐,默认情况下是向左对齐。
非常感谢任何帮助或指点,谢谢。
当前输出:
Number list below
1. L List 1
2. R list 2
我的预期输出:
Number list below
1. L List 1
2. R list 2
我已将 xml 数据简化如下:
<p>Number list below</p>
<ol>
<li style="text-align: right;">L list 1</li>
<li style="text-align: right;">R list 2</li>
</ol>
我的 xslt 代码如下所示:
<xsl:template match="LI|li">
<fo:list-block>
<xsl:attribute name="text-align">
<!--xsl:value-of select="end"/-->
<xsl:text disable-output-escaping="yes">right</xsl:text>
</xsl:attribute>
<fo:list-item>
<fo:list-item-label end-indent="label-end()">
<fo:block>
<xsl:variable name="value-fetcher">
<xsl:choose>
<xsl:when test="../@start">
<xsl:number value="count(preceding-sibling::li) + count(preceding-sibling::LI)+ ../@start"/>
</xsl:when>
<xsl:otherwise>
<xsl:number value="count(preceding-sibling::li) + count(preceding-sibling::LI) + 1"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:number value="$value-fetcher" format="1."/>
</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>
</fo:list-block>
</xsl:template>
您的模板存在一些问题:
- 你没有设置
provisional-distance-between-starts
which, together with provisional-label-separation
决定项目标签的宽度,所以你得到的宽度是 24pt - 6pt = 18pt
- 您的商品标签不符合要求
end-indent="label-end()"
,商品主体缺失 start-indent="body-start()"
,因此它们的尺寸/位置不正确。
修改后的模板应该可以工作:
<xsl:template match="LI|li">
<fo:list-block text-align="end" provisional-distance-between-starts="3cm"><!-- set the value you want! -->
<fo:list-item>
<fo:list-item-label end-indent="label-end()">
<fo:block>
<xsl:variable name="value-fetcher">
<xsl:choose>
<xsl:when test="../@start">
<xsl:number value="count(preceding-sibling::li) + count(preceding-sibling::LI)+ ../@start"/>
</xsl:when>
<xsl:otherwise>
<xsl:number value="count(preceding-sibling::li) + count(preceding-sibling::LI) + 1"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:number value="$value-fetcher" format="1."/>
</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>
</fo:list-block>
</xsl:template>
只是一个小问题:您正在为输入中的每个 li
元素创建一个 fo:list-block
,而您可以为每个 ol
或 ul
创建一个.
因为您事先不知道为标签预留的宽度,但这取决于项目文本本身……好吧,也许您根本不需要使用 fo:list-block
!
右对齐的 fo:block
就足够了,前提是项目文本始终只创建一行:
<xsl:template match="LI|li">
<fo:block text-align="end">
<fo:inline>
<xsl:variable name="value-fetcher">
<xsl:choose>
<xsl:when test="../@start">
<xsl:number value="count(preceding-sibling::li) + count(preceding-sibling::LI)+ ../@start"/>
</xsl:when>
<xsl:otherwise>
<xsl:number value="count(preceding-sibling::li) + count(preceding-sibling::LI) + 1"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:number value="$value-fetcher" format="1."/>
</fo:inline>
<fo:inline>
<xsl:apply-templates select="text()"/>
</fo:inline>
</fo:block>
</xsl:template>
在我看来,右对齐、可变宽度的列表并不是 fo:list-block
的设计目的。
假设您的 FO 格式化程序实现了 fo:table-and-caption
,您可以制作一个看起来像您想要的 table:
<table-and-caption text-align="right">
<table text-align="left">
<table-body>
<table-row>
<table-cell padding="1pt">
<block>1.</block>
</table-cell>
<table-cell padding="1pt">
<block>L List 1</block>
</table-cell>
</table-row>
</table-body>
<table-body>
<table-row>
<table-cell padding="1pt">
<block>2.</block>
</table-cell>
<table-cell padding="1pt">
<block>R list 2</block>
</table-cell>
</table-row>
</table-body>
</table>
</table-and-caption>
在没有 fo:table-and-caption
的情况下,你可以滥用 fo:block-container
和 writing-mode
属性:
<block-container writing-mode="rl">
<table text-align="left" writing-mode="lr">
或者你可以用右边的fo:leader
(https://www.w3.org/TR/xsl11/#fo_leader) to 'push' an fo:inline-container
(https://www.w3.org/TR/xsl11/#fo_inline-container):
<block>
<leader leader-length.optimum="100%"/><inline-container>
<table>
感谢您的回复,总是有用的。
通过以下 xslt 实现对齐:
<xsl:template match="LI|li">
<fo:block margin-left="36pt" text-align="right">
<fo:leader leader-pattern="space" leader-length="-18pt"/>
<fo:inline><xsl:variable name="value-fetcher">
<xsl:choose>
<xsl:when test="../@start">
<xsl:number value="count(preceding-sibling::li) + count(preceding-sibling::LI)+ ../@start"/>
</xsl:when>
<xsl:otherwise>
<xsl:number value="count(preceding-sibling::li) + count(preceding-sibling::LI) + 1"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:number value="$value-fetcher" format="1."/>
</fo:inline>
<fo:inline>
<fo:leader leader-pattern="space" leader-length="18pt"/>
<xsl:apply-templates select="text()"/>
</fo:inline>
</fo:block>
</xsl:template>
我的 XML 输入中有数字列表并且我能够将列表主体(文本内容)对齐以右对齐,但数字仍保持左对齐。如何将包括 numbers/bullets 在内的整个列表向右对齐,默认情况下是向左对齐。 非常感谢任何帮助或指点,谢谢。
当前输出:
Number list below
1. L List 1
2. R list 2
我的预期输出:
Number list below
1. L List 1
2. R list 2
我已将 xml 数据简化如下:
<p>Number list below</p>
<ol>
<li style="text-align: right;">L list 1</li>
<li style="text-align: right;">R list 2</li>
</ol>
我的 xslt 代码如下所示:
<xsl:template match="LI|li">
<fo:list-block>
<xsl:attribute name="text-align">
<!--xsl:value-of select="end"/-->
<xsl:text disable-output-escaping="yes">right</xsl:text>
</xsl:attribute>
<fo:list-item>
<fo:list-item-label end-indent="label-end()">
<fo:block>
<xsl:variable name="value-fetcher">
<xsl:choose>
<xsl:when test="../@start">
<xsl:number value="count(preceding-sibling::li) + count(preceding-sibling::LI)+ ../@start"/>
</xsl:when>
<xsl:otherwise>
<xsl:number value="count(preceding-sibling::li) + count(preceding-sibling::LI) + 1"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:number value="$value-fetcher" format="1."/>
</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>
</fo:list-block>
</xsl:template>
您的模板存在一些问题:
- 你没有设置
provisional-distance-between-starts
which, together withprovisional-label-separation
决定项目标签的宽度,所以你得到的宽度是 24pt - 6pt = 18pt - 您的商品标签不符合要求
end-indent="label-end()"
,商品主体缺失start-indent="body-start()"
,因此它们的尺寸/位置不正确。
修改后的模板应该可以工作:
<xsl:template match="LI|li">
<fo:list-block text-align="end" provisional-distance-between-starts="3cm"><!-- set the value you want! -->
<fo:list-item>
<fo:list-item-label end-indent="label-end()">
<fo:block>
<xsl:variable name="value-fetcher">
<xsl:choose>
<xsl:when test="../@start">
<xsl:number value="count(preceding-sibling::li) + count(preceding-sibling::LI)+ ../@start"/>
</xsl:when>
<xsl:otherwise>
<xsl:number value="count(preceding-sibling::li) + count(preceding-sibling::LI) + 1"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:number value="$value-fetcher" format="1."/>
</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>
</fo:list-block>
</xsl:template>
只是一个小问题:您正在为输入中的每个 li
元素创建一个 fo:list-block
,而您可以为每个 ol
或 ul
创建一个.
因为您事先不知道为标签预留的宽度,但这取决于项目文本本身……好吧,也许您根本不需要使用 fo:list-block
!
右对齐的 fo:block
就足够了,前提是项目文本始终只创建一行:
<xsl:template match="LI|li">
<fo:block text-align="end">
<fo:inline>
<xsl:variable name="value-fetcher">
<xsl:choose>
<xsl:when test="../@start">
<xsl:number value="count(preceding-sibling::li) + count(preceding-sibling::LI)+ ../@start"/>
</xsl:when>
<xsl:otherwise>
<xsl:number value="count(preceding-sibling::li) + count(preceding-sibling::LI) + 1"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:number value="$value-fetcher" format="1."/>
</fo:inline>
<fo:inline>
<xsl:apply-templates select="text()"/>
</fo:inline>
</fo:block>
</xsl:template>
在我看来,右对齐、可变宽度的列表并不是 fo:list-block
的设计目的。
假设您的 FO 格式化程序实现了 fo:table-and-caption
,您可以制作一个看起来像您想要的 table:
<table-and-caption text-align="right">
<table text-align="left">
<table-body>
<table-row>
<table-cell padding="1pt">
<block>1.</block>
</table-cell>
<table-cell padding="1pt">
<block>L List 1</block>
</table-cell>
</table-row>
</table-body>
<table-body>
<table-row>
<table-cell padding="1pt">
<block>2.</block>
</table-cell>
<table-cell padding="1pt">
<block>R list 2</block>
</table-cell>
</table-row>
</table-body>
</table>
</table-and-caption>
在没有 fo:table-and-caption
的情况下,你可以滥用 fo:block-container
和 writing-mode
属性:
<block-container writing-mode="rl">
<table text-align="left" writing-mode="lr">
或者你可以用右边的fo:leader
(https://www.w3.org/TR/xsl11/#fo_leader) to 'push' an fo:inline-container
(https://www.w3.org/TR/xsl11/#fo_inline-container):
<block>
<leader leader-length.optimum="100%"/><inline-container>
<table>
感谢您的回复,总是有用的。
通过以下 xslt 实现对齐:
<xsl:template match="LI|li">
<fo:block margin-left="36pt" text-align="right">
<fo:leader leader-pattern="space" leader-length="-18pt"/>
<fo:inline><xsl:variable name="value-fetcher">
<xsl:choose>
<xsl:when test="../@start">
<xsl:number value="count(preceding-sibling::li) + count(preceding-sibling::LI)+ ../@start"/>
</xsl:when>
<xsl:otherwise>
<xsl:number value="count(preceding-sibling::li) + count(preceding-sibling::LI) + 1"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:number value="$value-fetcher" format="1."/>
</fo:inline>
<fo:inline>
<fo:leader leader-pattern="space" leader-length="18pt"/>
<xsl:apply-templates select="text()"/>
</fo:inline>
</fo:block>
</xsl:template>