[xsl] transform html h1 with a div

Subject: [xsl] transform html h1 with a div
From: Giuseppe Briotti <g.briotti@xxxxxxxxx>
Date: Thu, 25 Oct 2012 11:12:08 +0200
The question is how to create a hierarchical div structure, based on
h1, h2, h*... html tags

As example transform this:

<?xml version="1.0" encoding="UTF-8"?>
<radice>
    <h1>titolo 1A</h1>
    <h2>titolo 2A</h2>
    <p>questo h il testo dopo il titolo 2A</p>
    <h1>titolo 1B</h1>
    <p>questo h il 10 testo dopo il titolo 1B</p>
    <p>questo h il 20 testo dopo il titolo 1B</p>
    <p>questo h il 30 testo dopo il titolo 1B</p>
</radice>

to this

<?xml version="1.0" encoding="UTF-8"?>
<radice>
    <div class="h1">
        <h1>titolo 1A</h1>
        <div class="h2">
            <h2>titolo 2A</h2>
            <p>questo h il testo dopo il titolo 2A</p>
         </div>
     </div>

    <div class="h1">
         <h1>titolo 1B</h1>
         <p>questo h il 10 testo dopo il titolo 1B</p>
         <p>questo h il 20 testo dopo il titolo 1B</p>
         <p>questo h il 30 testo dopo il titolo 1B</p>
     </div>
</radice>

I'm usign XSLT 2.0 and Saxon HE 9.4

I developed this but surely I'm missing something:
<?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="2.0">
    <xsl:template match="/">
        <xsl:element name="body">
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="h1 | h2">
        <xsl:element name="div">
            <xsl:variable name="contenuto"
select="./following-sibling::node()[. &lt;&lt;
current()/following-sibling::node[local-name()='h2' or
local-name()='h1'][1]]"/>
            <xsl:variable name="successivo"
select="./following-sibling::node()[local-name()='h2' or
local-name()='h1'][1]"/>
            <xsl:attribute name="class"><xsl:value-of
select="local-name()"/></xsl:attribute>
            <xsl:element name="{local-name()}"><xsl:apply-templates
select="./child::node()"/></xsl:element>
            <xsl:apply-templates select="following-sibling::node()[.
&lt;&lt; current()/following-sibling::node[local-name()='h2' or
local-name()='h1'][1]]"/>
            <xsl:apply-templates
select="following-sibling::node[local-name()='h2' or
local-name()='h1'][1]"/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="p">
        <xsl:element name="p"><xsl:apply-templates/></xsl:element>
    </xsl:template>

</xsl:stylesheet>

The output result in

<?xml version="1.0" encoding="UTF-8"?>
<body>
    <div class="h1"><h1>titolo 1A</h1></div>
    <div class="h2"><h2>titolo 2A</h2></div>
    <p>questo h il testo dopo il titolo 2A</p>
    <div class="h1"><h1>titolo 1B</h1></div>
    <p>questo h il 10 testo dopo il titolo 1B</p>
    <p>questo h il 20 testo dopo il titolo 1B</p>
    <p>questo h il 30 testo dopo il titolo 1B</p>
</body>

I placed the two variables "contenuto" and "successivo" to check what
happens. The $successivo is, as espected, the first h1 or h2 following
the current h1 or h2.
The $contenuto is always undefined.

I think that there are two kind of problem:

1. the XPath expression "following-sibling::node()[. &lt;&lt;
current()/following-sibling::node[local-name()='h2' or
local-name()='h1'][1]]" is wrong (Saxon 9.4 supports XPath2) but I
cannot understand where.

2. the <p> is processed anyway, thus probably I must create two
templates for <p>: an empty one (i.e. skip) and a mode="content" that
process the p normally.

So, what I'm missing? Can you suggest a smarter approach?

Thanks all in advance!

--

Giuseppe Briotti

"Alme Sol, curru nitido diem qui
promis et celas aliusque et idem
nasceris, possis nihil urbe Roma
visere maius."
(Orazio)

Current Thread