Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

convert xhtml to wiki syntax using xslt

i would like to convert xhtml to dokuwiki syntax using xslt.

now, one thing i can not seem to work my head around is how to handle nested lists. the dokuwiki syntax uses an asterisk (*) for a list item which is prepended by two white spaces per nesting level (c.f. wiki syntax).

my question: in the following example, how can the <xsl:template mach="li"> that matches the list item 2.1.1 be aware of it's nesting level, in order to prepend the right amount of white spaces?

* list item 1
* list item 2
  * list item 2.1
    * list item 2.1.1
  * list item 2.2
  * list item 2.3
* list item 3

corresponds to

  • list item 1
  • list item 2
    • list item 2.1
      • list item 2.1.1
    • list item 2.2
    • list item 2.3
  • list item 3

which is how the following html is displayed:

<ul>
    <li>
        list item 1
    </li>
    <li>
        list item 2
        <ul>
            <li>
                list item 2.1
                <ul>
                    <li>list item 2.1.1</li>
                </ul>
            </li>
            <li>list item 2.2</li>
            <li>list item 2.3</li>
        </ul>
    </li>
    <li>
        list item 3
    </li>
</ul>
like image 872
Pierre Spring Avatar asked Mar 08 '26 05:03

Pierre Spring


1 Answers

The following transformation:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>

 <xsl:strip-space elements="*"/>

 <xsl:variable name="vBlanks"
  select="'                                        '"/>
 <xsl:variable name="vnNestSpaces" select="2"/>


    <xsl:template match="li">
      <xsl:variable name="vNestLevel"
           select="count(ancestor::li)"/>
      <xsl:value-of select=
       "concat('&#xA;',
               substring($vBlanks,1,$vnNestSpaces*$vNestLevel),
               '*  ', normalize-space(text()[1])
               )"/>
      <xsl:apply-templates select="*"/>
    </xsl:template>
</xsl:stylesheet>

when applied on the original XML document:

<ul>
    <li> list item 1
    </li>
    <li> list item 2        
        <ul>
            <li> list item 2.1                
                <ul>
                    <li>list item 2.1.1</li>
                </ul>
            </li>
            <li>list item 2.2</li>
            <li>list item 2.3</li>
        </ul>
    </li>
    <li> list item 3    </li>
</ul>

produces the desired result:

*  list item 1
*  list item 2
  *  list item 2.1
    *  list item 2.1.1
  *  list item 2.2
  *  list item 2.3
*  list item 3

Do note the following:

  1. The required indentation is determined by the value of count(ancesstor::li).

  2. The space for indenting is taken directly from a sufficiently large blank line (contains enough blanks for 20 levels of nesting). There is no need to recursively output the spaces one by one.

  3. The transformation is more efficient, due to 2. above.

  4. Note the use of the XPath substring() function.

like image 90
Dimitre Novatchev Avatar answered Mar 10 '26 18:03

Dimitre Novatchev