使用 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,而您可以为每个 olul 创建一个.


因为您事先不知道为标签预留的宽度,但这取决于项目文本本身……好吧,也许您根本不需要使用 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-containerwriting-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>