1

I have number list in my XML input And I am able to align list body(text content) to align right, but numbers remain aligned to left. How can I align entire list including numbers/bullets to right, by default is comes to left. Any help or pointers is highly appreciated, Thanks.

Current output:

 Number list below
 1.                                                                 L List 1
 2.                                                                 R list 2

My expected output :

 Number list below
                                                                   1. L List 1
                                                                   2. R list 2

I have simplified xml data as below :

<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>

My xslt code look like below:

<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>
Ashu
  • 43
  • 8

3 Answers3

1

It seems to me that a right-aligned, variable-width list isn't quite what fo:list-block was designed to do.

Assuming that your FO formatter implements fo:table-and-caption, you could make a table that looks like what you want:

  <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>

In the absence of fo:table-and-caption, you can abuse fo:block-container and the writing-mode property:

  <block-container writing-mode="rl">
    <table text-align="left" writing-mode="lr">

or you can use 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) to the right:

  <block>
    <leader leader-length.optimum="100%"/><inline-container>
    <table>
Tony Graham
  • 7,306
  • 13
  • 20
  • Thanks for the reply, "fo:table-and-caption" is not yet supported, Is there any other way to achieve this formatting. – Ashu Dec 04 '17 at 12:57
0

There are a few problems with your template:

  • you are not setting provisional-distance-between-starts which, together with provisional-label-separation determines the width of the item label, so you get a width of 24pt - 6pt = 18pt
  • your item labels don't have the required end-indent="label-end()", and the item bodies are missing start-indent="body-start()", so they are not properly sized / positioned.

This revised template should work:

<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>

Just a minor nitpick: you are creating an fo:list-block for each li element in your input, while you could create just one for each ol or ul.


As you don't know in advance the width to reserve for the label, but it depends on the item text itself ... well, maybe you don't need to use an fo:list-block at all!

A right-aligned fo:block should be enough, provided the item text always creates just one line:

<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>
lfurini
  • 3,729
  • 4
  • 30
  • 48
  • Thanks for the reply, I am able to get expected output for sample input by setting provisional-distance-between-starts="14cm", But that's not the case always with increase in list string size it overlaps . Is it possible to calculate "provisional-distance-between-starts" dynamically based on string size or page width. – Ashu Dec 02 '17 at 13:36
  • Basically my string size going to change based on user entered text. Thanks. – Ashu Dec 02 '17 at 13:42
  • Answer updated: if the user entered text is just one line, this is even simpler! – lfurini Dec 02 '17 at 16:56
0

Thanks for the replies, are always useful.

alignment achieved by below 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>
Ashu
  • 43
  • 8