xsl-fo lists, label positioning

Lists

1. list item writes over the label?
2. Table of contents
3. How to present a list in XSL
4. Nested lists in xsl-fo
5. Body-start calcuation for lists
6. Lists, and nested lists
7. Nested list example.
8. Mimic a list using side floats

1.

list item writes over the label?

Eliot Kimber



> I am trying to use a list and the list-item is writing over the 
> list-label.  

You have to set the end-indent of the list item label and the start-indent of the list item block so that they don't overlap. It took me forever to finally figure out this aspect of FO .

The trick is that you set the provisional label length and label-to-body gap on the list block and then use the "label-end()" and "body-start()" functions to calculate the necessary indents:

  <fo:list-block provisional-label-separation="4mm"
      provisional-distance-between-starts="20mm">
    <fo:list-item>
     <fo:list-item-label end-indent="label-end()">
       ...
     </fo:list-item-label>
     <fo:list-item-body start-indent="body-start()">
        ...
     </fo:list-item-body>
   </fo:list-block>

This creates a 20mm label "column" and reserves 4mm gutter out of that 20mm.

2.

Table of contents

Peter Hilton

>I am trying to set up a table of contents with XSL, 
>and there are two things
>I haven't figured out how to do.  These are:
>1. A right-justified page number for each entry.

You can treat each list entry as a list entry, with the
table of contents entry as the list item label, and the page
number as the list item body:


<fo:list-item-label>
  <fo:block text-align="start"><xsl:value-of
  select="heading"/></fo:block>
</fo:list-item-label>
<fo:list-item-body>
  <fo:block text-align="end">
	<fo:page-number-citation/></fo:block>
</fo:list-item-body>

Unfortunately, FOP doesn't seem to support fo:page-number-citation :-(


            

3.

How to present a list in XSL

Nikolai Grigoriev



><fo:block >
> <fo:list-block >
>   <xsl:for-each select="path wanted">
>      <fo:list-item> 
>     <fo:list-item-label>
>        <fo:block>&bull;</fo:block>
>     </fo:list-item-label>
>   <fo:list-item-body>
>     <fo:block><xsl:value-of select="."/></fo:block>
>   </fo:list-item-body>
>        </fo:list-item>
>   </xsl:for-each>
></fo:list-block>
><fo:block>
>
>Does that make sense please?

Yes, it does - in FOP and in our FO2PDF; but not in the XSL
WD.  (2000) Both processors expect you to express lists this
way; you can control bullet position by
provisional-distance-between-starts and
provisional-label-separation attributes in
<fo:list-block>.

However, if our processors were conformant, your list would
be wrong.  The problem is that:

1) start-indent and end-indent for both fo:list-item-label
    and fo:list-item-body are calculated relative to the
    surrounding reference-area (i.e. page in most cases);

2) start-indent and end-indent are inheritable.

Therefore, fo:list-item-label in your list should overlap
with fo:list-item-body, and at this point, the formatter is
obliged to issue an error message. Instead, you should
write:

<fo:list-item> 
   <fo:list-item-label end-indent="label-end()">
      <fo:block>&bull;</fo:block>
   </fo:list-item-label>
   <fo:list-item-body start-indent="body-start()">
      <fo:block><xsl:value-of select="."/></fo:block>
   </fo:list-item-body>
 </fo:list-item>

(This is a thing I dislike most in the whole WD. I argued
against it for a long time, but in vain. This way of
building lists, already present in WD 1999-04-21, has been
reconfirmed and backed up with examples in the recent
draft.)

Conclusion. You face a dilemma:
- - if you want to render something with the present-day tools -
  you are on the right way;
- - if you want to compose a conformant FO - you are wrong.

One more comment: <fo:list-block> is a block-level object
itself.  You need not wrap it into a <fo:block>: every
block-level property can be specified directly on the
<fo:list-block>, and every place where <fo:block> can
go will accept <fo:list-block> as well.


4.

Nested lists in xsl-fo

Toshihiko Makita


 > Finding problems with nested lists.
 > the problem is that the nested list starts on the start-edge,
 > rather than being indented from the parent list.
 

This is not bug. According to the XSL CR, fo:list-item-body generates no reference areas. So the nested list's reference area is the same as parent fo:list-item-body's reference area. If you want to indent nested lists from parent fo:list-item-body's indent position, please specify inherited values by using from-parent() function.

 [before]
 &lt;fo:list-block start-indent="0.25in"
 provisional-distance-between-starts="10mm"
 provisional-label-separation="5mm">
 
 ==>Explicitly specifying start-indent="0.25in" cancels 
 inherited value. In
 this context, inherited value is parent fo:list-item-body's 
 start-indent
 (start-indent="body-start()")

 [after]
 &lt;fo:list-block start-indent="from-parent(start-indent) + 0.25in"
 provisional-distance-between-starts="10mm"
 provisional-label-separation="5mm">
 

5.

Body-start calcuation for lists

Tony Graham




> > The spec says: "When this function is used outside of a list, it still
> > returns a calculated value as specified."
> > (http://www.w3.org/TR/xsl/slice5.html#section-N8624-Property-Value-Functions
> > ) 
> What is the 'calculated value as specified' outside of a list?

body-start() = the value of the start-indent +
               start-intrusion-adjustment + the value of the
               provisional-distance-between-starts of the closest
               ancestor fo:list-block

David Tolpin adds

The value of the start-indent of what? In the presence of the list-block, it is the value of start-indent of the list-block. In the absence of start-indent, it is the value of nothing.

6.

Lists, and nested lists

Mike Ferrando

wrote it for EAD 2002 tag set not HTML. But the elements (LIST and ITEM) and attributes are almost exactly the same.

Here it is.

My goals:

To indent only on the presence of a nested LIST element

The syntax should be exactly the same (LIST or ITEM) to increase the variable when there is a nested list (recursive) LIST/LIST

Does not receive bullets (or whatever) based on the variable value. This is a local preference. I have included here only one type of list type='simple'.

If LIST[1] the variable will default the value at 5mm.

Since fo:inline does not generate space, XSL Formatter will not generate an ID if empty. Therefore, I have included a non-printable character. CAUTION: This character works, but it will appear as a '.' in the bookmarks.

I have tested it, but you might find something that needs changing due to a pure HTML transformation.

<xsl:template match="list[@type='simple' and not(child::defitem)]">
  <xsl:param name="nest_list"/>
  <!-- children only -->
    <!-- head; (NOT allowed lcpractices) -->
    <!-- item; -->
    <!-- listhead; defitem; -->
    <!-- @id; -->
    <!-- @continuation /continues; starts; -->
    <!-- @numberation /arabic; -->
    <!--              /upperalpha; loweralpha; -->
    <!--              /upperroman; lowerroman; -->
    <!-- @type /simple; deflist; marked; ordered; -->
    <!--       /simple 'no numbers or bullets' -->
    <!--       /deflist = defitem/label; item; --> 
    <!--       /marked = see @mark -->
    <!--       /ordered = 'each list item lettered or numbered' -->
    <!-- @mark /'bullet, box, dash, or etc.' -->
  <xsl:if test="string-length(@id)&gt;0">
    <fo:inline id="{@id}">&amp;#x200B;</fo:inline>
  </xsl:if>
  <fo:list-block provisional-label-separation="5mm">
    <xsl:attribute name="provisional-distance-between-starts">
      <xsl:choose>
        <xsl:when test="string-length($nest_list)!=0">
          <xsl:value-of select="number($nest_list)"/>
          <xsl:text>mm</xsl:text>
        </xsl:when>
        <xsl:otherwise>
          <xsl:text>5mm</xsl:text>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:attribute>
    <xsl:apply-templates select="*[not(name()='head')]">
      <xsl:with-param name="nest_list">
        <xsl:choose>
          <xsl:when test="string-length($nest_list)=0">
            <xsl:number value="5"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="number($nest_list)"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:with-param> 
    </xsl:apply-templates>
  </fo:list-block>
  <xsl:apply-templates select="head" mode="non_children"/>
  <xsl:apply-templates select="text()" mode="kill_txt"/> </xsl:template>

<xsl:template match="item[parent::list[@type='simple']]">
  <xsl:param name="nest_list"/>
  <!-- mixed=true -->
    <!-- archref; bibref; extptr; extref; linkgrp; ptr; ref; -->
    <!-- emph; lb; blockquote; -->
    <!-- address; abbr; date; expan; note; num; title; -->
    <!-- corpname; famname; function; genreform; geogname; -->
    <!-- name; occupation; persname; subject; -->
    <!-- origination; repository; unidate; unittitle; -->
    <!-- chronlist; list; table; -->
    <!-- @id; -->
    <fo:list-item>
      <fo:list-item-label end-indent="label-end()">
        <xsl:attribute name="start-indent">
          <xsl:choose>
            <xsl:when test="string-length($nest_list)=0">
              <xsl:text>5mm</xsl:text>
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="number($nest_list)"/>
              <xsl:text>mm</xsl:text>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:attribute>
        <xsl:if test="number($nest_list)=5">
          <fo:block>&amp;#x2022;</fo:block>
        </xsl:if>
      </fo:list-item-label>
      <fo:list-item-body start-indent="body-start()">
        <fo:block>
          <xsl:if test="string-length(@id)&gt;0">
            <xsl:attribute name="id">
              <xsl:value-of select="@id"/>
            </xsl:attribute>
          </xsl:if>
          <xsl:apply-templates select="text() | *[not(name()='list') and
not(name()='chronlist') and not(name()='table')]"/>
        </fo:block>
        <xsl:apply-templates select="list | chronlist | table">
          <xsl:with-param name="nest_list">
            <xsl:choose>
              <xsl:when test="string-length($nest_list)=0">
                <xsl:number value="5"/>
              </xsl:when>
              <xsl:otherwise>
                <xsl:value-of select="number($nest_list) +5"/>
              </xsl:otherwise>
            </xsl:choose>
          </xsl:with-param> 
        </xsl:apply-templates>
      </fo:list-item-body>
    </fo:list-item>
</xsl:template>

7.

Nested list example.

Mike Ferrando

My goals:

1. create a variable that was only increased by the presence of a nested LIST element

2. the syntax should be exactly the same (LIST or ITEM) to increase the variable when there is a nested list (recursive)

3. LIST/LIST does not receive bullets (or whatever) based on the variable value. This is a local preference. I have included here only one type of list type='simple'.

4. if LIST[1] the variable will default the value at 5mm.

5. since fo:inline does not generate space, XSL Formatter will not generate an ID if empty. Therefore, I have included a non-printable character. CAUTION: This character works, but it will appear as a '.' in the bookmarks.

<xsl:template match="list[@type='simple']">
  <xsl:param name="nest_list"/>
  <fo:list-block provisional-label-separation="5mm">
    <xsl:attribute name="provisional-distance-between-starts">
      <xsl:choose>
        <xsl:when test="string-length($nest_list)!=0">
          <xsl:value-of select="number($nest_list)"/>
          <xsl:text>mm</xsl:text>
        </xsl:when>
        <xsl:otherwise>
          <xsl:text>5mm</xsl:text>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:attribute>
    <xsl:apply-templates select="*[not(name()='head')]">
      <xsl:with-param name="nest_list">
        <xsl:choose>
          <xsl:when test="string-length($nest_list)=0">
            <xsl:number value="5"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="number($nest_list)"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:with-param> 
    </xsl:apply-templates>
  </fo:list-block>
  <xsl:apply-templates select="head" mode="non_children"/>
  <xsl:apply-templates select="text()" mode="kill_txt"/> </xsl:template>

<xsl:template match="item[parent::list[@type='simple']]">
  <xsl:param name="nest_list"/>

    <fo:list-item>
      <fo:list-item-label end-indent="label-end()">
        <xsl:attribute name="start-indent">
          <xsl:choose>
            <xsl:when test="string-length($nest_list)=0">
              <xsl:text>5mm</xsl:text>
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="number($nest_list)"/>
              <xsl:text>mm</xsl:text>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:attribute>
        <xsl:if test="number($nest_list)=5">
          <fo:block>&amp;#x2022;</fo:block>
        </xsl:if>
      </fo:list-item-label>
      <fo:list-item-body start-indent="body-start()">
        <fo:block>
          <xsl:if test="string-length(@id)&gt;0">
            <xsl:attribute name="id">
              <xsl:value-of select="@id"/>
            </xsl:attribute>
          </xsl:if>
          <xsl:apply-templates select="text() | *[not(name()='list') 
          and not(name()='table')]"/>
        </fo:block>
        <xsl:apply-templates select="list | chronlist | table">
          <xsl:with-param name="nest_list">
            <xsl:choose>
              <xsl:when test="string-length($nest_list)=0">
                <xsl:number value="5"/>
              </xsl:when>
              <xsl:otherwise>
                <xsl:value-of select="number($nest_list) +5"/>
              </xsl:otherwise>
            </xsl:choose>
          </xsl:with-param> 
        </xsl:apply-templates>
      </fo:list-item-body>
    </fo:list-item>
</xsl:template>

8.

Mimic a list using side floats

G. Ken Holman

I hope this example helps:

   <fo:block 
 xmlns="http://www.w3.org/1999/XSL/Format" font-size="20pt">
     <fo:block>Mimic a list using side floats</fo:block>
     <fo:block intrusion-displace="block">
       <fo:float 
 float="start"><fo:block>1.1.1&#xa0;</fo:block></fo:float>
       Here is a long body with a short label to the start
       side of the page with some wrapping going
       on to show the effect on the label.
     </fo:block>
     <fo:block intrusion-displace="block">
       <fo:float 
  float="start"><fo:block>1.1.1.1.1.1&#xa0;</fo:block></fo:float>
       Here is a long body with a longer label to the start
       side of the page with some wrapping
       going on to show the effect on the label.
     </fo:block>
   </fo:block>