Ordered list numbers instead of letters for sub-items

Here should go questions about transforming XML with XSLT and FOP.
Zach_H
Posts: 3
Joined: Tue Feb 20, 2018 8:41 pm

Ordered list numbers instead of letters for sub-items

Post by Zach_H »

Hello all,

Trying to solve this on my own, I found this topic topic14416.html. One difference between that request and mine is (besides wanting to go from letters to numbers) is that I don't necessarily need/want this to be a specific instance only, I would (ideally) like to change this as default behaviour (removing the need for setting an outputclass in the OL).

From that thread, I borrowed/modified the following code:

Code: Select all


<xsl:template match="*[contains(@class, ' topic/ol ')]/*[contains(@class, ' topic/li ')]">
<xsl:variable name="depth" select="count(ancestor::*[contains(@class, ' topic/ol ')])"/>
<xsl:variable name="format">
<xsl:call-template name="getVariable">
<xsl:with-param name="id" select="concat('Ordered List Format ', $depth)"/>
</xsl:call-template>
</xsl:variable>
<fo:list-item xsl:use-attribute-sets="ol.li">
<xsl:call-template name="commonattributes"/>
<fo:list-item-label xsl:use-attribute-sets="ol.li__label">
<fo:block xsl:use-attribute-sets="ol.li__label__content">
<xsl:call-template name="getVariable">
<xsl:with-param name="id" select="concat('Ordered List Number ', $depth)"/>
<xsl:with-param name="params" as="element()*">
<number>
<xsl:choose>
<xsl:when test="parent::node()/@outputclass='decimal'">
<xsl:number format="1"/>
</xsl:when>

<xsl:when test="@outputclass='decimal'">
<xsl:number format="1"/>
</xsl:when>
<xsl:otherwise>
<xsl:number/>
</xsl:otherwise>
</xsl:choose>
</number>
</xsl:with-param>
</xsl:call-template>
</fo:block>
</fo:list-item-label>
This seems to work when the outputclass is set, except that I want to nest the higher-level numbering into the lower-level, so that, for example, sub-items under "1" would be "1.1, 1.2, etc." and I'm not sure how to format the numbering here.
Zach_H
Posts: 3
Joined: Tue Feb 20, 2018 8:41 pm

Re: Ordered list numbers instead of letters for sub-items

Post by Zach_H »

So having worked on this some more, I realized I was over-complicating it. What I did instead was simply change the line

Code: Select all

<xsl:number format="1"/>
to

Code: Select all

<xsl:number format="1" level="multiple"/>
This does however lead to a new problem, and that's one of label spacing. With my code, the list label overlaps with the body text. I've tried to get the body text to begin after the end of the label, but to no avail. One solution was to set the block spacing attr like so:

Code: Select all

	    <!--Ordered list-->
<xsl:attribute-set name="ol" use-attribute-sets="common.block">
<xsl:attribute name="provisional-distance-between-starts">10mm</xsl:attribute>
<xsl:attribute name="provisional-label-separation">1mm</xsl:attribute>
But, this results in awkward spacing. It looks like this:
Preparing proficiency testing reports
1.           test sentence
2.           test sentence
              1.          test sentence
              2.          test sentence
Does anyone have a solution to that?

For full reference, here is the whole code section currently:

Code: Select all


	<xsl:template match="*[contains(@class, ' topic/ol ')]/*[contains(@class, ' topic/li ')]">
<xsl:variable name="depth" select="count(ancestor::*[contains(@class, ' topic/ol ')])"/>
<xsl:variable name="format">
<xsl:call-template name="getVariable">
<xsl:with-param name="id" select="concat('Ordered List Format ', $depth)"/>
</xsl:call-template>
</xsl:variable>
<fo:list-item xsl:use-attribute-sets="ol.li">
<xsl:call-template name="commonattributes"/>

<!--Maybe try adding "when" cond here to direct sub-items to alt template with alt attrs?-->
<fo:list-item-label xsl:use-attribute-sets="ol.li__label">
<fo:block xsl:use-attribute-sets="ol.li__label__content">
<xsl:call-template name="getVariable">
<xsl:with-param name="id" select="concat('Ordered List Number ', $depth)"/>
<xsl:with-param name="params" as="element()*">
<number>
<!-- This is the original code format (added "level")-->
<xsl:number format="1" level="multiple"/>

<!--Experiment to test depth detection (it works)-->
<!--
<xsl:choose>
<xsl:when test="$depth = 1">
<xsl:number format="1"/>
</xsl:when>
<xsl:when test="$depth = 2">
<xsl:number format="1"/>
</xsl:when>
<xsl:otherwise>
&#9632; -->
<!--</xsl:otherwise> -->

<!-- This was attempt #1 at changing formatting -->
<!--
<xsl:choose>
<xsl:when test="parent::*[contains(@class, ' topic/ol
')]/parent::*[contains(@class, ' topic/li ')]/parent::*
[contains(@class, ' topics/ol ')]">
<xsl:number format="a"/>
</xsl:when>
-->
<!--
<xsl:when test="parent::node()/@outputclass='lower-alpha'">
<xsl:number level="multiple" format="1"/>
</xsl:when>

<xsl:when test="@outputclass='lower-alpha'">
<xsl:number level="multiple" format="1"/>
</xsl:when>
<xsl:otherwise>
<xsl:number/>
</xsl:otherwise>
</xsl:choose>
-->
</number>
</xsl:with-param>
</xsl:call-template>
</fo:block>
</fo:list-item-label>

<fo:list-item-body xsl:use-attribute-sets="ol.li__body">
<fo:block xsl:use-attribute-sets="ol.li__content">
<xsl:apply-templates/>
</fo:block>
</fo:list-item-body>
</fo:list-item>
</xsl:template>
Zach_H
Posts: 3
Joined: Tue Feb 20, 2018 8:41 pm

Re: Ordered list numbers instead of letters for sub-items

Post by Zach_H »

And finally, a solution! For anyone with a similar problem, at least you'll have this chain to follow!

My solution was to effectively assign the lower-level items to a different attribute set so that I could control the spacing independently. I should add that all of these modifications were to a custom plugin based on the org.dita.pdf2 plugin included with the OT that came with Oxygen. In the template file, I added the following from the included plugin:

Code: Select all


    <xsl:template match="*[contains(@class, ' topic/ol ')]">
<xsl:apply-templates select="*[contains(@class,' ditaot-d/ditaval-startprop ')]" mode="outofline"/>
<fo:list-block xsl:use-attribute-sets="ol">
<xsl:call-template name="commonattributes"/>
<xsl:apply-templates/>
</fo:list-block>
<xsl:apply-templates select="*[contains(@class,' ditaot-d/ditaval-endprop ')]" mode="outofline"/>
</xsl:template>
And I modified the it as follows:

Code: Select all


	<xsl:template match="*[contains(@class, ' topic/ol ')]/*/*[contains(@class, ' topic/ol ')]">
<xsl:apply-templates select="*[contains(@class,' ditaot-d/ditaval-startprop ')]" mode="outofline"/>
<fo:list-block xsl:use-attribute-sets="ol.subitem">
<xsl:call-template name="commonattributes"/>
<xsl:apply-templates/>
</fo:list-block>
<xsl:apply-templates select="*[contains(@class,' ditaot-d/ditaval-endprop ')]" mode="outofline"/>
</xsl:template>
The addition of the code /*/*[contains(@class, ' topic/ol ')] seems to work for finding the nested item (I think I'd need to add another wildcard "/*" if I wanted to go another level deeper), and I just needed to create the new attribute set for ol.subitem.

That was done as follows:

Code: Select all


	<xsl:attribute-set name="ol.subitem" use-attribute-sets="common.block">
<xsl:attribute name="provisional-distance-between-starts">5mm</xsl:attribute>
<xsl:attribute name="provisional-label-separation">1mm</xsl:attribute>
</xsl:attribute-set>
It's worth noting that some experimenting with the spacing on both the ol and ol.subitem attr spacing seem to affect each other. The best layout I found was 1mm between starts on the ol attr, and 5mm for the subitem. Using em units seems to create inconsistent spacing, so some more experimentation may be needed, but for my purposes the hard-set mm units work fine!

Hopefully should anyone need help with a similar issue this thread may be of use to them.
Post Reply