So I have an xml file containing
...
<chapter>
<para>This line has a quote <quote id="one"/>. Here is some more text.</para>
<para>This also has a quote <quote id="two"/>. Here is some more text.</para>
</chapter>
<references>
<source id="one">
<author>Author 1</author>
<title>Title 1</title>
<year>2001</year>
</source>
<source id="two">
<author>Author 2</author>
<title>Title 2</title>
<year>2002</year>
</source>
</references>
...
I would like to output an xhtml
...
<p>This line has a quote <a href="#one>[1]</a>. Here is some more text.</p>
<p>This also has a quote <a href="#two>[2]</a>. Here is some more text.</p>
<h3>References</h3>
<ol>
<li><a name="one">Author 1, Title 1, 2001</a></li>
<li><a name="two">Author 2, Title 2, 2002</a></li>
</ol>
...
So what I want is a quote inside text with a link to an item in the references list.
I would also like for references to be ordered as they appear in text.
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" />
<xsl:template match="para">
<p><xsl:apply-templates/></p>
</xsl:template>
<xsl:template match="quote">
<a href="#{#id}">
<xsl:text>[</xsl:text>
<xsl:number count="quote" level="any" />
<xsl:text>]</xsl:text>
</a>
</xsl:template>
<xsl:template match="references">
<h3>References</h3>
<ol>
<xsl:apply-templates/>
</ol>
</xsl:template>
<xsl:template match="source">
<li>
<a name="{#id}">
<xsl:apply-templates/>
</a>
</li>
</xsl:template>
<xsl:template match="author|title">
<xsl:value-of select="."/>
<xsl:text>, </xsl:text>
</xsl:template>
<xsl:template match="year">
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>
Related
Context node:
<a>
<c refid="1" />
<c refid="2" />
<c refid="3" />
<c refid="4" />
<c refid="5" />
</a>
It gets the nodes referred to above, using a proprietary command:
<xsl:for-each select="get-a(#refid)">
<a id="1">
<f att1="C"/>
<f att2="I"/>
</a>
<a id="2">
<f att1="C"/>
<f att2="I"/>
</a>
<a id="3">
<!--doesn't have f att1-->
<f att2="I"/>
</a>
<a id="4">
<f att1="R"/>
<f att2="S"/>
</a>
<a id="5">
<f att1="G"/>
<f att2="I"/>
</a>
At present, I have it call a template within a for-each, but that will only do each node separately, obviously.
But it must process them first based on the att2 value (these are set values, always I or S, so no problem), and then within that, based on att1 value to produce something like below, the first P node being the problem:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0">
<!--xsl:output method="xml" indent="no" encoding="UTF-8"/-->
<!-- This takes the first asset (betting that it's correct...) and uses it to establish the parameters below -->
<xsl:variable name="rootSourceAssetXml">
<xsl:copy-of select="/asset[1]"/>
<!--xsl:copy-of select="./asset"/-->
</xsl:variable>
<xsl:template match="/">
<xsl:variable name="xml">
<O>
<xsl:for-each select="$rootSourceAssetXml/asset/child_asset_rel[#key='user.']">
<xsl:sort select="cs:get-asset(#child_asset)/f/#att2" order="ascending" data-type="text"/>
<xsl:sort select="cs:get-asset(#child_asset)/f/#att1" order="descending" data-type="text"/>
<xsl:variable name="getChapter">
<xsl:variable name="getChapterXML" select="cs:get-asset(#child_asset)"/>
<xsl:for-each select="$getChapterXML">
<xsl:if test="$getChapterXML/f/#att2='ebook'">
<xsl:copy-of select="$getChapterXML"/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:call-template name="Group">
<xsl:with-param name="thingGroup" select="$getChapter"/>
<xsl:with-param name="resourceTypeWeb" select="'EBook'"/>
</xsl:call-template>
<xsl:variable name="getChapter">
<xsl:variable name="getChapterXML" select="cs:get-asset(#child_asset)"/>
<xsl:for-each select="$getChapterXML">
<xsl:if test="$getChapterXML/f att2='instructor'">
<xsl:copy-of select="$getChapterXML"/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:call-template name="Group">
<xsl:with-param name="thingGroup" select="$getChapter"/>
<xsl:with-param name="resourceTypeWeb" select="'Instructor'"/>
</xsl:call-template>
</xsl:for-each>
</O>
</xsl:variable> <!-- Closes xml variable block -->
</xsl:template>
<xsl:template name="Group">
<xsl:param name="thingGroup"/>
<xsl:param name="resourceTypeWeb"/>
<xsl:variable name="eachAsset">
<xsl:for-each select="$thingGroup">
<xsl:copy-of select="$thingGroup/asset"/>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="productResourceDescriptionGroupWeb" select="$eachAsset/asset/asset_feature[#feature='XXX:product-resource-description-group-web']/#value_string"/>
<xsl:variable name="productResourceDescriptionDetailWeb" select="$eachAsset/asset/asset_feature[#feature='XXX:product-resource-description-detail-web']/#value_string"/>
<xsl:for-each select="$eachAsset/asset">
<P>
<xsl:attribute name="e"><xsl:value-of select="$resourceTypeWeb"/></xsl:attribute>
<xsl:attribute name="d"><xsl:value-of select="$productResourceDescriptionGroupWeb"/></xsl:attribute>
<xsl:call-template name="Detail">
<xsl:with-param name="resourceTypeWeb" select="$resourceTypeWeb"/>
<xsl:with-param name="topAssetTypeName" select="$topAssetTypeName"/>
<xsl:with-param name="thing" select="$eachAsset"/>
<xsl:with-param name="productResourceDescriptionDetailWeb" select="$productResourceDescriptionDetailWeb"/>
</xsl:call-template>
</P>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Should produce this:
<O>
<P d="C" e="I"> <!-- This C is not a set value but a string, and it could be anything. Once the nodes with the same attribute are isolated, it is fine to grab the att value from node in position 1-->
<id1>
<!-- other info via call template; this works -->
</id1>
<id2>
<!-- other info via call template; this works -->
</id2>
</P>
<P d="NULL" e="I">
<id3>
<!-- other info via call template; this works -->
</id3>
</P>
<P d="G" e="I">
<id5>
<!-- other info via call template; this works -->
</id5>
</P>
<P d="R" e="S">
<id4>
<!-- other info via call template; this works -->
</id4>
</P>
</O>
I have tried for-each-group calling a different template, and for-each with a sort for the value of att1, and other methods with no success.
This gives the right order, but I cannot bring nodes with same C value together:
<xsl:sort select="a/f/#att2"/>
<xsl:sort select="a/f/#att1"/>
The logic should be
for each <a> with same att2 value
for each <a> with same att1 value
output a single P with d=att1 value
then process nodes with same att1
I know XSLT can't "loop" the way I'm used to with Perl, but I feel there is some way to do this by grouping or sorting, I just can't find the right combination. I keep getting so close, but then can't complete it.
Many thanks in advance.
Your question is (still) very confusing. Consider the following simplified example:
Input XML
<root>
<a id="1">
<f att1="C"/>
<f att2="I"/>
</a>
<a id="2">
<f att1="C"/>
<f att2="I"/>
</a>
<a id="3">
<!--doesn't have f att1-->
<f att2="I"/>
</a>
<a id="4">
<f att1="R"/>
<f att2="S"/>
</a>
<a id="5">
<f att1="G"/>
<f att2="I"/>
</a>
</root>
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="root">
<root>
<xsl:for-each-group select="a" group-by="f/#att2">
<xsl:for-each-group select="current-group()" group-by="if (f/#att1) then f/#att1 else 'NULL'">
<P d="{current-grouping-key()}" e="{f/#att2}">
<xsl:for-each select="current-group()">
<abc id="{#id}"/>
</xsl:for-each>
</P>
</xsl:for-each-group>
</xsl:for-each-group>
</root>
</xsl:template>
</xsl:stylesheet>
Result
<?xml version="1.0" encoding="UTF-8"?>
<root>
<P d="C" e="I">
<abc id="1"/>
<abc id="2"/>
</P>
<P d="NULL" e="I">
<abc id="3"/>
</P>
<P d="G" e="I">
<abc id="5"/>
</P>
<P d="R" e="S">
<abc id="4"/>
</P>
</root>
This shows how to implement your stated logic:
for each <a> with same att2 value
for each <a> with same att1 value
output a single P with d=att1 value
then process nodes with same att1
and nothing else.
I need to add .01 to the entry in this line of code in my XSLT script <xsl:apply-templates select="descendant::xhtml:span[#property = 'atom:content-item-name']"/>. This number appears twice in my output. I only need the .01 on the second entry. How would I do that? I guess it would be in effect a counter because if there are 2 questions I'd need it to number as .02, etc.
This is the full XSLT script:
<?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"
xmlns:math="http://exslt.org/math"
xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl"
xmlns:xhtml="http://www.w3.org/1999/xhtml"
xmlns:mml="http://www.w3.org/1998/Math/MathML"
xmlns="http://www.w3.org/1999/xhtml"
exclude-result-prefixes="xs math xd xhtml mml"
version="3.0">
<xsl:output encoding="UTF-8" include-content-type="no" indent="no" method="xhtml" omit-xml-declaration="yes"/>
<!-- attributes, commments, processing instructions, text: copy as is -->
<xsl:template match="#*|comment()|processing-instruction()|text()">
<xsl:copy-of select="."/>
</xsl:template>
<!-- elements: create a new element with the same name, but no namespace -->
<xsl:template match="*">
<xsl:param name="content-item-name"/>
<xsl:element name="{local-name()}">
<xsl:apply-templates select="#*|node()">
<xsl:with-param name="content-item-name" select="$content-item-name"/>
</xsl:apply-templates>
</xsl:element>
</xsl:template>
<!-- process root -->
<xsl:template match="xhtml:html">
<xsl:text disable-output-escaping="yes"><!DOCTYPE html></xsl:text>
<xsl:sequence select="'
'"/>
<html>
<xsl:apply-templates select="#* | node()"/>
</html>
</xsl:template>
<!-- process item, pass content item name variable -->
<xsl:template match="xhtml:li[#property='ktp:question']">
<li>
<xsl:apply-templates select="#*|node()">
<xsl:with-param name="content-item-name" select="descendant::xhtml:span[#property='atom:content-item-name']/#data-value"/>
</xsl:apply-templates>
</li>
</xsl:template>
<!-- branching point for any interaction type-based updates -->
<xsl:template match="xhtml:li[#property='ktp:question']">
<li>
<xsl:apply-templates select="#*|node()">
<xsl:with-param name="interactionType" select="//xhtml:span[#property='ktp:interactionType']"/>
</xsl:apply-templates>
</li>
</xsl:template>
<!-- Change content -->
<xsl:template match="xhtml:ol[#class='ktp-question-set']">
<xsl:variable name="content-item-name" select="xhtml:span[#property='atom:content-item-name']/#data-value"/>
<xsl:variable name="feedbackPara"
select="xhtml:section[#property = 'ktp:stimulus']"/>
<ol property="ktp:questionSet" typeof="ktp:QuestionSet" class="ktp-question-set">
<li class="ktp-question-set-meta">
<section property="ktp:metadata" class="ktp-meta">
<xsl:apply-templates
select="descendant::xhtml:span[#property = 'atom:content-item-name']"/>
</section>
<section property="ktp:tags" class="ktp-meta">
<span class="ktp-meta" property="ktp:questionSetType">shared-stimulus</span>
</section>
</li>
<li class="ktp-stimulus" typeof="ktp:Stimulus" property="ktp:stimulus">
<xsl:apply-templates
select="descendant::xhtml:section[#property = 'ktp:stimulus']"/>
<p class="place-top atom-exclude">Stimulus End: Place content above this line</p>
</li>
<li class="ktp-question" typeof="ktp:Question" property="ktp:question">
<section class="ktp-question-meta">
<section property="ktp:metadata" class="ktp-meta">
<xsl:apply-templates
select="descendant::xhtml:span[#property = 'atom:content-item-name']"/>
</section>
<xsl:apply-templates
select="descendant::xhtml:section[#property = 'ktp:tags']"/>
</section>
<xsl:apply-templates
select="descendant::xhtml:section[#class = 'ktp-question-stem']"/>
<xsl:apply-templates
select="descendant::xhtml:ol[#class = 'ktp-answer-set']"/>
<xsl:apply-templates
select="descendant::xhtml:section[#property = 'ktp:explanation']"/>
</li>
</ol>
</xsl:template>
</xsl:stylesheet>
This is the input section where I need to pull the data-value from:
<section class="ktp-question-meta">
<section property="ktp:metadata" class="ktp-meta"><span property="atom:content-item-name" class="ktp-meta" data-value="lsac820402"></span></section>
<section property="ktp:tags" class="ktp-meta">
<span property="ktp:interactionType" class="ktp-meta">single-select</span>
<span property="ktp:questionType" class="ktp-meta">Assumption (Sufficient)</span>
<span property="ktp:difficulty" class="ktp-meta">★</span>
</section>
This is how I need that section to appear with the .01 added to that data-value:
<section class="ktp-question-meta">
<section property="ktp:metadata" class="ktp-meta">
<span property="atom:content-item-name" class="ktp-meta" data-value="lsac820402.01"></span>
</section>
I want to build a multi level nested list, depending on the category name. This is my xml:
<UserDefinedTable xmlns="DotNetNuke/UserDefinedTable">
<Data>
<UserDefinedRowId>28</UserDefinedRowId>
<Category>KatOne</Category>
<Title>Level 1</Title>
</Data>
<Data>
<UserDefinedRowId>29</UserDefinedRowId>
<Category>KatOneSub</Category>
<Title>Level 2</Title>
</Data>
<Data>
<UserDefinedRowId>30</UserDefinedRowId>
<Category>KatOneSub</Category>
<Title>Level 2</Title>
</Data>
<Data>
<UserDefinedRowId>31</UserDefinedRowId>
<Category>KatTwo</Category>
<Title>Level 1</Title>
</Data>
<Data>
<UserDefinedRowId>32</UserDefinedRowId>
<Category>KatTwoSub</Category>
<Title>Level 2</Title>
</Data>
<Data>
<UserDefinedRowId>33</UserDefinedRowId>
<Category>KatTwoSub</Category>
<Title>Level 2</Title>
</Data>
</UserDefinedTable>
And this is my attempt at the XSLT template:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:udt="DotNetNuke/UserDefinedTable" exclude-result-prefixes="udt">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />
<xsl:variable name="prefix_param">udt_<xsl:value-of select="//udt:Context/udt:ModuleId" />_param</xsl:variable>
<xsl:template match="udt:Data" mode="list">
<xsl:for-each select="udt:Data">
<li>
<span>KatUpper</span>
<ul class="level-two">
<xsl:for-each select="udt:Data">
<li>
KatSub
</li>
</xsl:for-each>
</ul>
</li>
</xsl:for-each>
</xsl:template>
<xsl:template match="/udt:UserDefinedTable">
<xsl:variable name="currentData" select="udt:Data" />
<xsl:if test="$currentData">
<ul class="my-list">
<xsl:apply-templates select="$currentData" mode="list">
</xsl:apply-templates>
</ul>
</xsl:if>
</xsl:template>
<xsl:template name="EditLink">
<xsl:if test="udt:EditLink">
<a href="{udt:EditLink}">
<img border="0" alt="edit" src="{//udt:Context/udt:ApplicationPath}/images/edit.gif" />
</a>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
I would like to make a foreach that check if the cateogry name mathces this or that then it stays on upper level, and inside each iteration i would check for category name to have a nested list inside:
Something like this:
<ul class="my-list">
<li>
<span>KatOne</span>
<ul clasS="levelTwo">
<li>
KatOneSub
</li>
<li>
KatOneSub
</li>
<li>
KatOneSub
</li>
</ul>
</li>
<li>
<span>KatTwo</span>
<ul clasS="levelTwo">
<li>
KatTwoSub
</li>
<li>
KatTwoSub
</li>
</ul>
</li>
</ul>
Your current problem is that within the template matching udt:Data, you do <xsl:for-each select="udt:Data">, but this will be looking for child elements of the current Data element that also called Data. You should really be looking for siblings here.
In XSLT 1.0, you could make use of a key to look up the "Level 2" items based on the first preceding "Level 1" items
<xsl:key name="level2"
match="udt:Data[udt:Title='Level 2']"
use="preceding-sibling::udt:Data[udt:Title='Level 1'][1]/udt:UserDefinedRowId" />
You would then start off by selecting the "Level 1" items
<xsl:variable name="currentData" select="udt:Data[udt:Title='Level 1']" />
<xsl:apply-templates select="$currentData" mode="list" />
Then, to get the "Level 2" items for the current "Level 1" item, you can do use the key
<xsl:for-each select="key('level2', udt:UserDefinedRowId)">
Try this XSLT
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:udt="DotNetNuke/UserDefinedTable"
exclude-result-prefixes="udt">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />
<xsl:key name="level2"
match="udt:Data[udt:Title='Level 2']"
use="preceding-sibling::udt:Data[udt:Title='Level 1'][1]/udt:UserDefinedRowId" />
<xsl:template match="udt:Data" mode="list">
<li>
<span>
<xsl:value-of select="udt:Category" />
</span>
<xsl:if test="key('level2', udt:UserDefinedRowId)">
<ul class="levelTwo">
<xsl:for-each select="key('level2', udt:UserDefinedRowId)">
<li>
<span>
<xsl:value-of select="udt:Category" />
</span>
</li>
</xsl:for-each>
</ul>
</xsl:if>
</li>
</xsl:template>
<xsl:template match="/udt:UserDefinedTable">
<xsl:variable name="currentData" select="udt:Data[udt:Title='Level 1']" />
<xsl:if test="$currentData">
<ul class="my-list">
<xsl:apply-templates select="$currentData" mode="list" />
</ul>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Note, you should change expressions like Title="Level 1" accordingly if you have a better way of identifying Level 1 and Level 2 elements.
I've an XML where there are 10 phrase nodes.
I'm trying to get the second phrase using the below XSLT.
<xsl:value-of select="document(concat('C:\Users\u0138039\Desktop\Proview\Files\','MCPV1_
ORD_34.XML'))/chapter//phrase[2]"/>
to my surprise this is not working.
and when i use the below.
<xsl:value-of select="document(concat('C:\Users\u0138039\Desktop\Proview\Files\','MCPV1_
ORD_34.XML'))/chapter//phrase"/>
Input XML:
<?xml version="1.0" encoding="utf-8"?>
<index>
<secondaryie>certification, 34/12</secondaryie>
</index>
title.xml
<?xml version="1.0" encoding="utf-8"?>
<entry>
<file name="MCPV1_ORD_30.xml"/>
<file name="MCPV1_ORD_31.xml"/>
<file name="MCPV1_ORD_32.xml"/>
<file name="MCPV1_ORD_33.xml"/>
<file name="MCPV1_ORD_34.xml"/>
<file name="MCPV1_ORD_35.xml"/>
</entry>
Chapter 34.xml
<?xml version="1.0" encoding="utf-8"?>
<chapter num="34">
<section level="sect1" number-type="manual" num="nonum">
<para>
<phrase>34/0/2</phrase>
</para>
</section>
<section level="sect1" number-type="manual" num="nonum">
<para>
<phrase>34/0/3</phrase>
</para>
</section>
<section level="sect1" number-type="manual" num="nonum">
<para>
<phrase>34/1</phrase>
</para>
<para>
<phrase>34/1/1</phrase>
</para>
</section>
</chapter>
XSLT:
<xsl:template match="index">
<div class="index">
<xsl:apply-templates/>
</div>
</xsl:template>
<xsl:template match="secondaryie">
<div class="secondaryie">
<xsl:apply-templates/>
</div>
</xsl:template>
<xsl:template match="text()">
<xsl:analyze-string select="." regex="([\w]+)/([\w]+)">
<xsl:matching-substring>
<xsl:variable name="prent">
<xsl:for-each select="document('C:\Users\u0138039\Desktop\Proview\Files\title.xml')/entry/file">
<xsl:value-of select="document(concat('C:\Users\u0138039\Desktop\Proview\Files\',./#name))/chapter[//phrase=.]/#num"/>
</xsl:for-each>
</xsl:variable>
<a href="{$prent}">
<xsl:value-of select="."/>
</a>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
process is i run the Input XML with XSLT and it will loop through title.xml and then match the regex with the phrase present inside the documents(here i took 34 for reference), and it should print the chapter value.
In my XML 34/12 is present so it should print <a href="34"/> where as in my output it is showing <a href=""/>
Can someone please let me know, how can i fix it and why the data is not getting pulled in first case.
Thanks
Instead of this
<xsl:value-of select="document(concat('C:\Users\u0138039\Desktop\Proview\Files\','MCPV1_
ORD_34.XML'))/chapter//phrase[2]"/>
Try this out:
<xsl:value-of select="(document(concat(C:\Users\u0138039\Desktop\Proview\Files\','MCPV1_ORD_34.XML'))/chapter//phrase)[2]"/>
You will get the second node. For your 34.xml I got the node with this value '34/0/3'
I am fairly new at this and I am not sure if it is possible to do what I want to achieve here. I have 3 for-each loops that stores a number for every chapter, section and paragraph. I want to get that stored number from the previous for-each loop and display it in the nested loop, but I can't get it to work.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<head>
<title>Table of Contents, Chapter 3</title>
</head>
<body>
<xsl:for-each select="chapter">
<tr>
<xsl:variable name="capnr">
<xsl:number value="3" format="1. "/>
</xsl:variable>
<xsl:value-of select="$capnr"/>
<xsl:value-of select="#title"/>
</tr>
<br />
<xsl:for-each select="section">
<tr>
<xsl:variable name="secnr">
<xsl:number format="1. "/>
</xsl:variable>
<xsl:value-of select="$capnr"/>
<xsl:value-of select="$secnr"/>
<xsl:value-of select="#title"/>
</tr>
<br />
<xsl:for-each select="paragraph">
<tr>
<xsl:variable name="parnr">
<xsl:number format="1 "/>
</xsl:variable>
<xsl:value-of select="$capnr"/>
<xsl:value-of select="$secnr"/>
<xsl:value-of select="$parnr"/>
<xsl:value-of select="#title"/>
</tr>
</xsl:for-each>
<br />
</xsl:for-each>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
XML:
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="ToC-3.xsl"?>
<chapter title="Chapter 3: Expressions">
<section title="Variables">
<paragraph title="Simple variables"></paragraph>
<paragraph title="Text variables"></paragraph>
<paragraph title="Remote identifiers"></paragraph>
</section>
<section title="The logical operators">
<paragraph title="Precedence of Boolean operators"></paragraph>
</section>
<section title="Designational expressions">
</section>
</chapter>
Without more details on the input and output, this should work. Of note is that the variable name is on the root, to allow all templates to access it. but since there appears to be one XSl per chapter this shouldn't be a problem.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:variable name="capnr">
<xsl:number value="3" format="1."/>
</xsl:variable>
<xsl:template match="/">
<html>
<head>
<title>Table of Contents, Chapter 3</title>
</head>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="chapter">
<h1>
<xsl:value-of select="$capnr"/>
<xsl:value-of select="#title"/>
</h1>
<ol><xsl:apply-templates/></ol>
</xsl:template>
<xsl:template match="section">
<li>
<xsl:value-of select="$capnr"/>
<xsl:value-of select="position()"/>
<xsl:text> - </xsl:text>
<xsl:value-of select="#title"/>
<ol><xsl:apply-templates/></ol>
</li>
</xsl:template>
<xsl:template match="paragraph">
<li>
<xsl:value-of select="$capnr"/>
<xsl:value-of select="count(../preceding-sibling::*) + 1"/>
<xsl:text>.</xsl:text>
<xsl:value-of select="position()"/>
<xsl:text> - </xsl:text>
<xsl:value-of select="#title"/>
<ol><xsl:apply-templates/></ol>
</li>
</xsl:template>
</xsl:stylesheet>
The above when applied to the given input XMl gives:
<html>
<head>
<title>Table of Contents, Chapter 3</title>
</head>
<body>
<h1>3.Chapter 3: Expressions</h1>
<ol><li>3.1 - Variables<ol><li>3.1.1 - Simple variables<ol></ol>
</li>
<li>3.1.2 - Text variables<ol></ol>
</li>
<li>3.1.3 - Remote identifiers<ol></ol>
</li>
</ol>
</li>
<li>3.2 - The logical operators<ol><li>3.2.1 - Precedence of Boolean operators<ol></ol>
</li>
</ol>
</li>
<li>3.3 - Designational expressions<ol></ol>
</li>
</ol>
</body>
</html>