XLS Create New Element If Condition Meet - xslt

I'm receiving this error:
The element type "xsl:if" must be terminated by
the matching end-tag ""
when I'm trying to close and open a new fo:block if a certain condition is meet.
<xsl:if test=".[#pdf_break='true']">
</fo:block><fo:block>
</xsl:if>
How must this be written?
Full example of what I'm trying to do:
<fo:block>
<xsl:for-each select="/article/front/article-meta/contrib-group/contrib[#contrib-type='author']">
<fo:basic-link show-destination="new" external-destination="url({$link})" >
<fo:inline> <xsl:value-of select="name/given-names" /> <xsl:value-of select="name/surname" /> <fo:inline font-size="8pt" vertical-align="super" font-family="HelveticaNeueLTCom-Lt_1" padding-right="8pt" padding-left="-8pt"><xsl:for-each select="xref[#ref-type='aff']"><xsl:value-of select="sup" /><xsl:if test="position()!=last()">,</xsl:if></xsl:for-each></fo:inline></fo:inline>
</fo:basic-link>
<xsl:if test=".[#pdf_break='true']">
</fo:block><fo:block>
</xsl:if>
</xsl:for-each>
so basically it should be:
<fo:block>
Some amount of authors listed with links
</fo:block>
when pdf_break is never true, and then:
<fo:block>
Some amount of authors listed with links
</fo:block>
<fo:block>
More authors listed with links
</fo:block>
when the attribute is true.
Example XML:
<contrib-group>
<contrib equal-contrib="yes" contrib-type='author' pdf_break='false'>
<name>
<surnameExample1</surname>
<given-names>Example1</given-names>
</name>
<xref ref-type='aff' rid='ID1'><sup>1</sup></xref>
</contrib>
<contrib equal-contrib="yes" contrib-type='author' pdf_break='false'>
<name>
<surname>Example2</surname>
<given-names>Example2</given-names>
</name>
<xref ref-type='aff' rid='ID2'><sup>2</sup></xref>
<xref ref-type='aff' rid='ID3'><sup>3</sup></xref>
<xref ref-type='aff' rid='ID4'><sup>4</sup></xref>
<xref ref-type='aff' rid='ID5'><sup>5</sup></xref>
</contrib>
<contrib equal-contrib="yes" contrib-type='author' pdf_break='true'>
<name>
<surname>Example3</surname>
<given-names>Example3</given-names>
</name>
<xref ref-type='aff' rid='ID2'><sup>2</sup></xref>
</contrib>
<contrib contrib-type='author' pdf_break='false'>
<name>
<surname>Example4</surname>
<given-names>Example4</given-names>
</name>
<xref ref-type='aff' rid='ID6'><sup>6</sup></xref>
</contrib>
<contrib contrib-type='author' pdf_break='false'>
<name>
<surname>Example5</surname>
<given-names>Example15</given-names>
</name>
<xref ref-type='aff' rid='ID2'><sup>2</sup></xref>
</contrib>
</contrib-group>

Use:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/*">
<doc xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:for-each-group select="contrib" group-ending-with="contrib[#pdf_break = 'true']">
<fo:block>
<xsl:for-each select="current-group()">
<author><xsl:sequence select="name/surname, name/given-names"/></author>
</xsl:for-each>
</fo:block>
</xsl:for-each-group>
</doc>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the provided XML document:
<contrib-group>
<contrib equal-contrib="yes" contrib-type='author' pdf_break='false'>
<name>
<surname>Example1</surname>
<given-names>Example1</given-names>
</name>
<xref ref-type='aff' rid='ID1'><sup>1</sup></xref>
</contrib>
<contrib equal-contrib="yes" contrib-type='author' pdf_break='false'>
<name>
<surname>Example2</surname>
<given-names>Example2</given-names>
</name>
<xref ref-type='aff' rid='ID2'><sup>2</sup></xref>
<xref ref-type='aff' rid='ID3'><sup>3</sup></xref>
<xref ref-type='aff' rid='ID4'><sup>4</sup></xref>
<xref ref-type='aff' rid='ID5'><sup>5</sup></xref>
</contrib>
<contrib equal-contrib="yes" contrib-type='author' pdf_break='true'>
<name>
<surname>Example3</surname>
<given-names>Example3</given-names>
</name>
<xref ref-type='aff' rid='ID2'><sup>2</sup></xref>
</contrib>
<contrib contrib-type='author' pdf_break='false'>
<name>
<surname>Example4</surname>
<given-names>Example4</given-names>
</name>
<xref ref-type='aff' rid='ID6'><sup>6</sup></xref>
</contrib>
<contrib contrib-type='author' pdf_break='false'>
<name>
<surname>Example5</surname>
<given-names>Example15</given-names>
</name>
<xref ref-type='aff' rid='ID2'><sup>2</sup></xref>
</contrib>
</contrib-group>
The wanted -structured output is produced:
<doc xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:block>
<author>
<surname>Example1</surname>
<given-names>Example1</given-names>
</author>
<author>
<surname>Example2</surname>
<given-names>Example2</given-names>
</author>
<author>
<surname>Example3</surname>
<given-names>Example3</given-names>
</author>
</fo:block>
<fo:block>
<author>
<surname>Example4</surname>
<given-names>Example4</given-names>
</author>
<author>
<surname>Example5</surname>
<given-names>Example15</given-names>
</author>
</fo:block>
</doc>
XSLT 1.0 solution:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:key name="kInGroup" match="contrib"
use="generate-id(preceding-sibling::contrib[#pdf_break = 'true'][1])"/>
<xsl:template match=
"contrib[generate-id()
= generate-id(key('kInGroup',
generate-id(preceding-sibling::contrib[#pdf_break='true']
[1]
)
)[1]
)
]">
<fo:block>
<xsl:apply-templates mode="inGroup" select=
"key('kInGroup',
generate-id(preceding-sibling::contrib[#pdf_break = 'true'][1])
)"/>
</fo:block>
</xsl:template>
<xsl:template match="contrib" mode="inGroup">
<author><xsl:copy-of select="name/*"/></author>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
When applied on the same XML document (above), again the correct-structured output is produced:
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">
<author>
<surname>Example1</surname>
<given-names>Example1</given-names>
</author>
<author>
<surname>Example2</surname>
<given-names>Example2</given-names>
</author>
<author>
<surname>Example3</surname>
<given-names>Example3</given-names>
</author>
</fo:block>
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">
<author>
<surname>Example4</surname>
<given-names>Example4</given-names>
</author>
<author>
<surname>Example5</surname>
<given-names>Example15</given-names>
</author>
</fo:block>

I think, if you have access to XSLT 2 or 3, you can use
<xsl:template match="contrib-group">
<xsl:for-each-group select="contrib[#contrib-type = 'author']" group-starting-with="*[#pdf_break = 'true']">
<fo:block>
<xsl:apply-templates select="current-group()"/>
</fo:block>
</xsl:for-each-group>
</xsl:template>
https://xsltfiddle.liberty-development.net/3NSSEv4/1 is a minimal sample, of course you need to add templates for remaining XML input to XSL-FO transformation.

Related

XSLT 1.0 - repeating table using child context doesn't work

I am using the XML below:
<root>
<Products name="product01">
<Instruments name="ins01"/>
<Instruments name="ins02"/>
<Instruments name="ins01"/>
</Products>
<Products name="product02">
<Instruments name="random text A">
<Bill name="A"/>
</Instruments>
<Instruments name="random text B and C">
<Bill name="B">
<Notes>some text</Notes>
</Bill>
<Bill name="C">
<Notes>some text</Notes>
</Bill>
</Instruments>
<Instruments name="random text A and B">
<Bill name="A">
<Notes>some text</Notes>
</Bill>
<Bill name="B">
<Notes>some text</Notes>
</Bill>
</Instruments>
<Instruments name="random text B">
<Bill name="B">
<Notes>some text</Notes>
</Bill>
</Instruments>
<Instruments name="random text C">
<Bill name="C">
<Notes>some text</Notes>
</Bill>
</Instruments>
<Instruments name="random text C and A">
<Bill name="C">
<Notes>some text</Notes>
</Bill>
<Bill name="A">
<Notes>some text</Notes>
</Bill>
</Instruments>
</Products>
</root>
First, I am grouping after Products, then grouping after Bills, on the left table-column, while the right table-column should only display the Instruments name, based on the Bill Type grouping from first column. As an example of above XML, I am trying to achieve this:
product02
Bill Type: A random text A
random text A and B
random text C and A
Bill Type: B random text B and C
random text A and B
random text B
Bill Type: C random text B and C
random text C
random text C and A
A sample of my template is below:
<xsl:key name="groupProducts" match="/root/Products/Instruments/Bill" use="../../#name" />
<xsl:key name="groupBilling" match="/root/Products/Instruments/Bill" use="concat(../../#name,#name)" />
<xsl:template name="myTemplate">
<fo:block>
<fo:table>
<fo:table-column column-width="proportional-column-width(1)" />
<fo:table-body>
<xsl:for-each select="/root/Products/Instruments/Bill[generate-id(.) = generate-id(key('groupProducts',../../#name)[1])]">
<fo:table-row>
<fo:table-cell>
<fo:block font-weight="bold" margin-top="4pt">
<xsl:value-of select="../../#name" />
</fo:block>
<fo:block>
<fo:table>
<fo:table-column column-width="50.000" column-number="1" />
<fo:table-column column-width="50.000" column-number="2" />
<fo:table-body>
<xsl:for-each select="/root/Products/Instruments/Bill[generate-id(.) = generate-id(key('groupBilling',concat(current()/../../#name,#name))[1])]">
<fo:table-row>
<fo:table-cell>
<fo:block color="blue">
Bill Type: <xsl:value-of select="#name" /></fo:block>
<fo:block />
</fo:table-cell>
<fo:table-cell>
<fo:block>
<fo:table>
<fo:table-column column-width="proportional-column-width(1)" />
<fo:table-body>
<xsl:for-each select="../.">
<fo:table-row>
<fo:table-cell>
<fo:block>
<xsl:value-of select="#name" />
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:for-each>
</fo:table-body>
</fo:table>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:for-each>
</fo:table-body>
</fo:table>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:for-each>
</fo:table-body>
</fo:table>
</fo:block>
</xsl:template>
For the for-each on the right table-column, I also tried the following:
<xsl:for-each select="../.">
../*[score/#naam = current()/score/#naam]
../node()[score/#naam = current()/score/#naam]
/root/Products/Instruments, but none works.
Any help is greatly appreciated.
While I cannot follow your attempted XSLT with fo namespace, consider this shortened XSLT running the Muenchian Method rendering an HTML version of desired output:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" omit-xml-declaration="no" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="bill_key" match="Bill" use="#name"/>
<xsl:template match="/root">
<html>
<xsl:apply-templates select="Products[descendant::Bill]"/>
</html>
</xsl:template>
<xsl:template match="Products">
<table>
<tr>
<td><xsl:value-of select="#name"/></td>
<td></td>
</tr>
<xsl:apply-templates select="Instruments"/>
<tr></tr>
</table>
</xsl:template>
<xsl:template match="Instruments">
<xsl:apply-templates select="Bill[generate-id() =
generate-id(key('bill_key', #name))]"/>
</xsl:template>
<xsl:template match="Bill">
<xsl:for-each select="key('bill_key', #name)">
<tr>
<xsl:if test="position() = 1">
<td><xsl:value-of select="concat('Bill Type: ', #name)"/></td>
</xsl:if>
<xsl:if test="position() > 1">
<td></td>
</xsl:if>
<td><xsl:value-of select="../#name"/></td>
</tr>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Hopefully you can adjust the <table>, <tr>, <td> tags to your fo styling.
Online Demo (click HTML to view output)
HTML Table Output
product02
Bill Type: A random text A
random text A and B
random text C and A
Bill Type: B random text B and C
random text A and B
random text B
Bill Type: C random text B and C
random text C
random text C and A

Group the text nodes as well as element nodes based on few starting text

Please suggest to make group the text() + element node based on few text formats like (Fig.|Figs.|Figure|Table|Tables). If these citations text starts with and ends-with parenthesis like (,[,{,),],} signs, grouping should enclose the parenthesis too, otherwise Fig|Table word + Xref element(s) to be grouped within <col1>***</col1>.
These grouping should applicable any text() nodes except under 'Refs' element.
Input:
<root>
<Para>The citations are like (Fig. <xref refID="f1">1</xref>).</Para>
<Para>The <b>citations are like (Fig. <xref refID="f1">1</xref>).</b></Para>
<Extract>The citations are like (Figs. <xref refID="f1">1</xref> and <xref refID="f2">2</xref>).</Extract>
<DispQuote>The citations are like (Tables <xref refID="t1">1</xref> and <xref refID="t2">2</xref>).</DispQuote>
<Para1>The citations are like (Tables <xref refID="t1">1</xref> and <xref refID="t2">2</xref>; Fig. <xref refID="f1">1</xref>).</Para1>
<Para2>The citations are like (analysation of Fig. <xref refID="f1">1</xref>).</Para2>
<Para>The citations are like (explained in Figs. <xref refID="f1">1</xref> and <xref refID="f2">2</xref>).</Para>
<Para>The citations are like (Chapter 1 and 3 are explained in Tables <xref refID="t1">1</xref> and <xref refID="t2">2</xref>).</Para>
<Refs>The citations are like (Fig. <xref refID="f1">1</xref>).</Refs>
</root>
XSLT2:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="#*|node()">
<xsl:copy><xsl:apply-templates select="#*|node()"/></xsl:copy>
</xsl:template>
<xsl:template match="Para">
<xsl:copy><xsl:call-template name="tempCrossRef1"/></xsl:copy>
</xsl:template>
<xsl:template name="tempCrossRef1">
<!--xsl:analyze-string select="." regex="\([ ]+)|([\+])|([=])|([%])|([/])|([\[])|([\]])"-->
<!-- (Fig. <xref refID="f1">1</xref>) -->
<!--xsl:analyze-string select="node()" regex="\(Fig. ">
<xsl:matching-substring>
<xsl:choose>
<xsl:when test="following-sibling::node()[2][parent::*/name()='xref']">
<col><xsl:apply-templates select="."/></col>
</xsl:when>
<xsl:otherwise><xsl:apply-templates select="."/></xsl:otherwise>
</xsl:choose>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string-->
<xsl:for-each select="node()">
<xsl:choose>
<xsl:when test="ends-with(., 'Fig.')">
<xsl:for-each-group select="self::node()[ends-with(., 'Fig.')]" group-adjacent="boolean(self::xref)">
<xsl:choose>
<xsl:when test="current-grouping-key()">
<xsl:apply-templates select="current-group()" />
</xsl:when>
<xsl:otherwise>
<p1>
<xsl:apply-templates select="current-group()" />
</p1>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:when>
<xsl:otherwise>
<xsl:copy><xsl:apply-templates select="#*|node()"/></xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
<xsl:template match="xref">
<xref>
<xsl:apply-templates select="#*"/>
<xsl:apply-templates />
</xref>
</xsl:template>
</xsl:stylesheet>
Required Result:
<root>
<Para>The citations are like <col1>(Fig. <xref refID="f1">1</xref>)</col1>.</Para>
<Para>The <b>citations are like <col1>(Fig. <xref refID="f1">1</xref>)</col1>.</b></Para>
<Para>The citations are like <col1>(Fig. <xref refID="f1">1</xref>)</col1>.</Para>
<Extract>The citations are like <col1>(Figs. <xref refID="f1">1</xref> and <xref refID="f2">2</xref>)</col1>.</Extract>
<DispQuote>The citations are like <col1>(Tables <xref refID="t1">1</xref> and <xref refID="t2">2</xref>)</col1>.</DispQuote>
<Para1>The citations are like <col1>(Tables <xref refID="t1">1</xref> and <xref refID="t2">2</xref>; Fig. <xref refID="f1">1</xref>)</col1>.</Para1>
<Para2>The citations are like (analysation of <col1>Fig. <xref refID="f1">1</xref></col1>).</Para2>
<Para>The citations are like (explained in <col1>Figs. <xref refID="f1">1</xref> and <xref refID="f2">2</xref></col1>).</Para>
<Para>The citations are like (Chapter 1 and 3 are explained in <col1>Tables <xref refID="t1">1</xref> and <xref refID="t2">2</xref></col1>).</Para>
<Refs>The citations are like (Fig. <xref refID="f1">1</xref>).</Refs><!-- Within this element, grouping not required-->
</root>
Here is an attempt using two steps, the first transforms any of the patterns [(]?(Fig\.|Figs\.|Figure|Table[s]?) into start elements and the end patterns [)] into end elements, the second steps then tries to use group-starting-with/ending-with to wrap such content into col1:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="3.0">
<xsl:param name="start-patterns" as="xs:string">[(]?(Fig\.|Figs\.|Figure|Table[s]?)</xsl:param>
<xsl:param name="end-patterns" as="xs:string">[)]</xsl:param>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:mode name="text-to-elements" on-no-match="shallow-copy"/>
<xsl:template match="root/*[not(self::Refs)][matches(., $start-patterns)]">
<xsl:copy>
<xsl:variable name="text-to-elements" as="node()*">
<xsl:apply-templates mode="text-to-elements"/>
</xsl:variable>
<xsl:for-each-group select="$text-to-elements" group-starting-with="start">
<xsl:choose>
<xsl:when test="self::start">
<xsl:for-each-group select="current-group()" group-ending-with="end">
<xsl:choose>
<xsl:when test="current-group()[last()][self::end]">
<col1>
<xsl:apply-templates select="current-group()"/>
</col1>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
<xsl:template match="start | end">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="text()" mode="text-to-elements">
<xsl:analyze-string select="." regex="{$start-patterns}">
<xsl:matching-substring>
<start>
<xsl:value-of select="."/>
</start>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:analyze-string select="." regex="{$end-patterns}">
<xsl:matching-substring>
<end>
<xsl:value-of select="."/>
</end>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
</xsl:stylesheet>
As you can see at https://xsltfiddle.liberty-development.net/pPgCcow, this approach seems to produce the wanted result for your posted input, except the for element
<Para1>The citations are like (Tables <xref refID="t1">1</xref> and <xref refID="t2">2</xref>; Fig. <xref refID="f1">1</xref>).</Para1>

xsl:fo template match not firing on nested list

I need to use a hyphen for the bullet on a nested list applying xsl:fo. I have two templates to match but only one is being applied. If I use just the first template, the outer list gets the template applied. If I use just the second template, the nested list gets the template applied. The pattern I am attempting to match in the second template is any unordered list with a list item as a parent. Any help on getting my desired output is greatly appreciated.
XML
<ThisNode>
<ul>
<li>Item One</li>
<li>Item Two</li>
<li>Item Three
<ul>
<li>Sub-Item One</li>
<li>Sub-Item Two</li>
</ul>
</li>
<li>Item Four</li>
<li>Item Five</li>
</ul>
</ThisNode>
XSLT
<xsl:template match="ul">
<fo:list-block>
<xsl:for-each select="./li">
<fo:list-item>
<fo:list-item-label end-indent="label-end()">
<fo:block font-weight="bold">•</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="8pt">
<fo:block><xsl:value-of select="."/></fo:block>
</fo:list-item-body>
</fo:list-item>
</xsl:for-each>
</fo:list-block>
</xsl:template>
<xsl:template match="li//ul">
<fo:list-block start-indent="8pt">
<xsl:for-each select="./li">
<fo:list-item>
<fo:list-item-label end-indent="label-end()">
<fo:block font-weight="bold">-</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="16pt">
<fo:block><xsl:value-of select="."/></fo:block>
</fo:list-item-body>
</fo:list-item>
</xsl:for-each>
</fo:list-block>
</xsl:template>
<fo:block text-align="left">
<xsl:apply-templates select="./ThisNode"/>
</fo:block>
DESIRED OUTPUT
• Item One
• Item Two
• Item Three
- Sub-Item One
- Sub-Item Two
• Item Four
• Item Five
ACTUAL OUTPUT USING EITHER JUST THE 1ST TEMPLATE OR USING BOTH
• Item One
• Item Two
• Item ThreeSub-Item OneSub-Item Two
• Item Four
• Item Five
ACTUAL OUTPUT USING ONLY THE 2ND TEMPLATE
Item One Item Two Item Three
- Sub-Item One
- Sub-Item Two
Item Four Item Five
This looks like a good place for a call-template with a mode, to distinguish between the 2 cases. The outer template calls the inner template:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:template match="/">
<fo:block text-align="left">
<xsl:apply-templates select="ThisNode"/>
</fo:block>
</xsl:template>
<xsl:template match="ul">
<fo:list-block>
<xsl:for-each select="li">
<fo:list-item>
<fo:list-item-label end-indent="label-end()">
<fo:block font-weight="bold">•</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="8pt">
<fo:block>
<!-- I'm not quite sure what you want here -->
<xsl:value-of select="text()"/>
<xsl:apply-templates select="ul" mode="inner"/>
</fo:block>
</fo:list-item-body>
</fo:list-item>
</xsl:for-each>
</fo:list-block>
</xsl:template>
<xsl:template match="ul" mode="inner">
<fo:list-block start-indent="8pt">
<xsl:for-each select="./li">
<fo:list-item>
<fo:list-item-label end-indent="label-end()">
<fo:block font-weight="bold">-</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="16pt">
<fo:block>
<xsl:value-of select="."/>
</fo:block>
</fo:list-item-body>
</fo:list-item>
</xsl:for-each>
</fo:list-block>
</xsl:template>
</xsl:stylesheet>
The following stylesheet illustrates a possible solution. Your approach is not far off - however, it fails to account for the behaviour of XSLT processors. This expression:
<xsl:value-of select="."/>
by default returns any text nodes that are children of the context node. But in your case (template match for li elements), all descendant text nodes are output, not only the immediate children of li.
Therefore, the stylesheet below uses
<xsl:value-of select="child::text()"/>
to retrieve the text content of a li element instead and <xsl:apply-templates> to process any li elements that are sub-items of it.
As your title states,
xsl:fo template match not firing on nested list
You diagnosed it correctly. This is because - once inside a template match for li - you do not let the XSLT processor process descendant li elements.
Stylesheet
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/ThisNode">
<fo:root>
<fo:layout-master-set>
<fo:simple-page-master master-name="simple"
page-height="29.7cm"
page-width="21cm"
margin-top="1cm"
margin-bottom="2cm"
margin-left="2.5cm"
margin-right="2.5cm">
<fo:region-body margin-top="3cm"/>
<fo:region-before extent="3cm"/>
<fo:region-after extent="1.5cm"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="simple">
<fo:flow flow-name="xsl-region-body">
<xsl:apply-templates/>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
<xsl:template match="ul[parent::ThisNode]">
<fo:list-block>
<xsl:apply-templates/>
</fo:list-block>
</xsl:template>
<xsl:template match="ul[parent::li]">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="li">
<fo:list-item>
<xsl:choose>
<xsl:when test="parent::ul/parent::ThisNode">
<fo:list-item-label start-indent="1cm">
<fo:block font-weight="bold">•</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="1.5cm">
<fo:block><xsl:value-of select="child::text()"/></fo:block>
</fo:list-item-body>
</xsl:when>
<xsl:otherwise>
<fo:list-item-label start-indent="3cm">
<fo:block font-weight="bold">-</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="3.5cm">
<fo:block><xsl:value-of select="."/></fo:block>
</fo:list-item-body>
</xsl:otherwise>
</xsl:choose>
</fo:list-item>
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
Output (XSL-FO)
<?xml version="1.0" encoding="UTF-8"?>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="simple" page-height="29.7cm" page-width="21cm" margin-top="1cm"
margin-bottom="2cm"
margin-left="2.5cm"
margin-right="2.5cm">
<fo:region-body margin-top="3cm"/>
<fo:region-before extent="3cm"/>
<fo:region-after extent="1.5cm"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="simple">
<fo:flow flow-name="xsl-region-body">
<fo:list-block>
<fo:list-item>
<fo:list-item-label start-indent="1cm">
<fo:block font-weight="bold">•</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="1.5cm">
<fo:block>Item One</fo:block>
</fo:list-item-body>
</fo:list-item>Item One
<fo:list-item>
<fo:list-item-label start-indent="1cm">
<fo:block font-weight="bold">•</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="1.5cm">
<fo:block>Item Two</fo:block>
</fo:list-item-body>
</fo:list-item>Item Two
<fo:list-item>
<fo:list-item-label start-indent="1cm">
<fo:block font-weight="bold">•</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="1.5cm">
<fo:block>Item Three
</fo:block>
</fo:list-item-body>
</fo:list-item>Item Three
<fo:list-item>
<fo:list-item-label start-indent="3cm">
<fo:block font-weight="bold">-</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="3.5cm">
<fo:block>Sub-Item One</fo:block>
</fo:list-item-body>
</fo:list-item>Sub-Item One
<fo:list-item>
<fo:list-item-label start-indent="3cm">
<fo:block font-weight="bold">-</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="3.5cm">
<fo:block>Sub-Item Two</fo:block>
</fo:list-item-body>
</fo:list-item>Sub-Item Two
<fo:list-item>
<fo:list-item-label start-indent="1cm">
<fo:block font-weight="bold">•</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="1.5cm">
<fo:block>Item Four</fo:block>
</fo:list-item-body>
</fo:list-item>Item Four
<fo:list-item>
<fo:list-item-label start-indent="1cm">
<fo:block font-weight="bold">•</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="1.5cm">
<fo:block>Item Five</fo:block>
</fo:list-item-body>
</fo:list-item>Item Five
</fo:list-block>
</fo:flow>
</fo:page-sequence>
</fo:root>
Output (PDF)

XSL-FO - how to continue numbers in two list-blocks?

Does somebody know how to achieve this with XSL-FO transformation? The question details should be clear from the codes below.
Input:
<section>
<title>Section 1</title>
<orderedlist>
<listitem><para>item 1.1</para></listitem>
<listitem>
<para>item 1.2</para>
<orderedlist>
<listitem><para>item a</para></listitem>
<listitem><para>item b</para></listitem>
</orderedlist>
</listitem>
</orderedlist>
</section>
<section>
<title>Section 2</title>
<orderedlist>
<listitem><para>item 2.1</para></listitem>
<listitem><para>item 2.2</para></listitem>
</orderedlist>
</section>
Desired output:
Section 1
1. item 1.1
2. item 1.2
a. item a
b. item b
Section 2
3. item 2.1
4. item 2.2
Here is the XSL file for lists:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format">
<!-- templates for lists - supports numbered and itemized types -->
<!-- the maximum depth is currently 2 -->
<xsl:template match="orderedlist">
<fo:list-block start-indent="0.5cm" space-before="0.2cm"
provisional-distance-between-starts="0.7cm">
<xsl:apply-templates />
</fo:list-block>
</xsl:template>
<xsl:template match="orderedlist//orderedlist">
<fo:list-block start-indent="1.2cm" provisional-distance-between-starts="0.7cm"
padding-top="-0.2cm" padding-bottom="0.2cm">
<xsl:apply-templates />
</fo:list-block>
</xsl:template>
<xsl:template match="itemizedlist">
<fo:list-block start-indent="0.5cm" space-before="0.2cm"
provisional-distance-between-starts="0.7cm">
<xsl:apply-templates />
</fo:list-block>
</xsl:template>
<xsl:template match="itemizedlist//itemizedlist">
<fo:list-block start-indent="1.2cm" provisional-distance-between-starts="0.7cm"
padding-top="-0.2cm" padding-bottom="0.2cm">
<xsl:apply-templates />
</fo:list-block>
</xsl:template>
<xsl:template match="orderedlist/listitem">
<fo:list-item margin-top="0.1cm">
<fo:list-item-label end-indent="label-end()">
<fo:block>
<xsl:number count="listitem" format="1." />
</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="body-start()">
<fo:block>
<xsl:apply-templates />
</fo:block>
</fo:list-item-body>
</fo:list-item>
</xsl:template>
<xsl:template match="orderedlist//orderedlist/listitem">
<fo:list-item>
<fo:list-item-label end-indent="label-end()">
<fo:block>
<xsl:number count="listitem" format="a." />
</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="body-start()">
<fo:block>
<xsl:apply-templates />
</fo:block>
</fo:list-item-body>
</fo:list-item>
</xsl:template>
<xsl:template match="itemizedlist/listitem">
<fo:list-item margin-top="0.1cm">
<fo:list-item-label end-indent="label-end()">
<fo:block>•</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="body-start()">
<fo:block>
<xsl:apply-templates />
</fo:block>
</fo:list-item-body>
</fo:list-item>
</xsl:template>
<xsl:template match="itemizedlist//itemizedlist/listitem">
<fo:list-item>
<fo:list-item-label end-indent="label-end()">
<fo:block>•</fo:block>
</fo:list-item-label>
<fo:list-item-body start-indent="body-start()">
<fo:block>
<xsl:apply-templates />
</fo:block>
</fo:list-item-body>
</fo:list-item>
</xsl:template>
</xsl:stylesheet>
Assuming you input sample is (added the sections topmost element to make the sample well-formed):
<sections>
<section>
<title>Section 1</title>
<orderedlist>
<listitem><para>item 1.1</para></listitem>
<listitem>
<para>item 1.2</para>
<orderedlist>
<listitem><para>item a</para></listitem>
<listitem><para>item b</para></listitem>
</orderedlist>
</listitem>
</orderedlist>
</section>
<section>
<title>Section 2</title>
<orderedlist>
<listitem><para>item 2.1</para></listitem>
<listitem><para>item 2.2</para></listitem>
</orderedlist>
</section>
</sections>
at a given listitem of first level you can use:
count(
preceding-sibling::listitem
|
../../preceding-sibling::section/orderedlist/listitem)
+ 1
For example:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:output indent="yes"/>
<xsl:template match="sections">
<fo:block>
<xsl:apply-templates select="section"/>
</fo:block>
</xsl:template>
<xsl:template match="section">
<fo:list-block>
<xsl:apply-templates select="title | orderedlist/listitem"/>
</fo:list-block>
</xsl:template>
<xsl:template match="title">
<fo:list-item>
<xsl:value-of select="."/>
</fo:list-item>
</xsl:template>
<xsl:template match="listitem">
<fo:list-item>
<xsl:number
value="count(
preceding-sibling::listitem
|
../../preceding-sibling::section/orderedlist/listitem)
+ 1" format="1. "/>
</fo:list-item>
</xsl:template>
</xsl:stylesheet>
produces:
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:list-block>
<fo:list-item>Section 1</fo:list-item>
<fo:list-item>1. </fo:list-item>
<fo:list-item>2. </fo:list-item>
</fo:list-block>
<fo:list-block>
<fo:list-item>Section 2</fo:list-item>
<fo:list-item>3. </fo:list-item>
<fo:list-item>4. </fo:list-item>
</fo:list-block>
</fo:block>
Do you have a particular reason for not using DocBook and the DocBook-XSL stylesheets? That would give you a lot "for free" (perhaps you know that already).
In DocBook, what you ask for is already implemented. There is a continuation attribute on <orderedlist> that indicates whether the numbering in a list continues from the preceding list. This is supported in the DocBook-XSL styleheets for FO output (check out fo/lists.xsl and common/common.xsl to see how it's done).

XSL conditional formatting

I am using xsl to transform xml to kml format. I would like to add conditional logic to the xsl to switch the styleUrl based on part of an attribute value. The attribute name is FROM_SYSTEM_ID. The format of the attribute value is "A-123-CAM-1" where "CAM" is part of the string to determine which style definition to use (in this case CAM stands for Camera, CAB stands for Cabinet, etc).
How can I parse this attribute to perform the needed style definition switch?
Following is my xsl template:
<xsl:template match="Line">
<Folder>
<name>
Lines
<!--<xsl:value-of select="#name"/>-->
</name>
<xsl:for-each select="Row">
<Placemark>
<name>
<xsl:value-of select="#FROM_SYSTEM_ID"/>
</name>
<description>
<xsl:value-of select="#TO_SYSTEM_ID"/>
</description>
<styleUrl>#msn_open-diamond00</styleUrl>
<LineString>
<tessellate>1</tessellate>
<coordinates>
<xsl:value-of select="#FromLong"/>,<xsl:value-of select="#FromLat"/>,0 <xsl:value-of select="#ToLong"/>,<xsl:value-of select="#ToLat"/>,0
</coordinates>
</LineString>
</Placemark>
</xsl:for-each>
</Folder>
</xsl:template>
Following is a sample of the XML:
<Line>
<Row PrimaryRoute="A-123" FROM_SYSTEM_ID="A-123-CAB-1"
TO_SYSTEM_ID="A-123-CAM-3" FromLat="42.624948852000"
FromLong="-83.107221652500"
ToLat="42.624940325900" ToLong="-83.107353167000" />
<Row PrimaryRoute="A-123" FROM_SYSTEM_ID="A-123-CAM-1"
TO_SYSTEM_ID="A-123-HH-16" FromLat="42.641662528600"
FromLong="-83.151500129600"
ToLat="42.641709802200" ToLong="-83.151552587600" />
<!-- additional rows here -->
</Line>
You can extract the CAM or CAB portion of the FROM_SYSTEM_ID attribute using a combination of substring-after and substring-before:
<xsl:value-of select="
substring-before(
substring-after(
substring-after(#FROM_SYSTEM_ID, '-'), '-'), '-')"/>
Putting this together with your stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="Line">
<Folder>
<name>
Lines
<!--<xsl:value-of select="#name"/>-->
</name>
<xsl:for-each select="Row">
<Placemark>
<name>
<xsl:value-of select="#FROM_SYSTEM_ID"/>
</name>
<description>
<xsl:value-of select="#TO_SYSTEM_ID"/>
</description>
<styleUrl>
<xsl:value-of select="
substring-before(
substring-after(
substring-after(#FROM_SYSTEM_ID, '-'), '-'), '-')"/>
</styleUrl>
<LineString>
<tessellate>1</tessellate>
<coordinates>
<xsl:value-of select="#FromLong"/>,<xsl:value-of select="#FromLat"/>,0 <xsl:value-of select="#ToLong"/>,<xsl:value-of select="#ToLat"/>,0
</coordinates>
</LineString>
</Placemark>
</xsl:for-each>
</Folder>
</xsl:template>
</xsl:stylesheet>
Applied to this input:
<Line>
<Row PrimaryRoute="A-123" FROM_SYSTEM_ID="A-123-CAB-1"
TO_SYSTEM_ID="A-123-CAM-3" FromLat="42.624948852000"
FromLong="-83.107221652500"
ToLat="42.624940325900" ToLong="-83.107353167000" />
<Row PrimaryRoute="A-123" FROM_SYSTEM_ID="A-123-CAM-1"
TO_SYSTEM_ID="A-123-HH-16" FromLat="42.641662528600"
FromLong="-83.151500129600"
ToLat="42.641709802200" ToLong="-83.151552587600" />
</Line>
Produces the following result:
<Folder>
<name>Lines</name>
<Placemark>
<name>A-123-CAB-1</name>
<description>A-123-CAM-3</description>
<styleUrl>CAB</styleUrl>
<LineString>
<tessellate>1</tessellate>
<coordinates>-83.107221652500,42.624948852000,0
-83.107353167000,42.624940325900,0
</coordinates>
</LineString>
</Placemark>
<Placemark>
<name>A-123-CAM-1</name>
<description>A-123-HH-16</description>
<styleUrl>CAM</styleUrl>
<LineString>
<tessellate>1</tessellate>
<coordinates>-83.151500129600,42.641662528600,0
-83.151552587600,42.641709802200,0
</coordinates>
</LineString>
</Placemark>
</Folder>