Transform Docbook XML lists into WordML using XSLT stylesheet

271 Views Asked by At

I have the following XML I'd like to translate to WordML:

<document>
<section>
    <para>An ordered list:</para>
    <orderedlist>
        <listitem>first list item</listitem>
        <listitem>second list item
            <orderedlist>
                <listitem>one</listitem>
                <listitem>two
                    <orderedlist>
                        <listitem>one</listitem>
                        <listitem>two</listitem>
                        <listitem>three</listitem>
                    </orderedlist>
                </listitem>
                <listitem>three</listitem>
            </orderedlist>
        </listitem>
        <listitem>third list item</listitem>
    </orderedlist>
</section>
</document>

This is my XSLT 1.0 stylesheet template so far:

<xsl:template match="document/section/orderedlist">
  <xsl:for-each select="listitem">
  <w:p>
    <w:pPr><w:pStyle w:val="Normal"/><w:numPr>
            <w:ilvl w:val="{count(ancestor::orderedlist)-1}"/>  <!-- level of list item (0,1,2 etc.) -->
            <w:numId w:val="{position()}"/>  <!-- the orderedlist should get an ID (1,2,3 etc.) -->
        </w:numPr>
    </w:pPr>
    <w:r><w:t><xsl:value-of select="."/></w:t></w:r>
  </w:p>
  <xsl:apply-templates />
  </xsl:for-each>
</xsl:template>

But this

  1. does not work for the nested lists.
  2. the ID of the list ("position()") should be the same for every listitem of an orderedlist.

Can anybody help me out? Especially with the nested list part.

See: http://xsltransform.net/jyH9rN8

Expected output:

<w:p>
  <w:pPr><w:pStyle w:val="Normal"/><w:numPr><w:ilvl w:val="0"/><w:numId w:val="1"/></w:numPr></w:pPr>
  <w:r><w:t>first list item</w:t></w:r>
</w:p>
<w:p>
  <w:pPr><w:pStyle w:val="Normal"/><w:numPr><w:ilvl w:val="0"/><w:numId w:val="1"/></w:numPr></w:pPr>
  <w:r><w:t>second list item</w:t></w:r>
</w:p>
<w:p>
  <w:pPr><w:pStyle w:val="Normal"/><w:numPr><w:ilvl w:val="1"/><w:numId w:val="1"/></w:numPr></w:pPr>
  <w:r><w:t>one</w:t></w:r>
</w:p>
<w:p>
  <w:pPr><w:pStyle w:val="Normal"/><w:numPr><w:ilvl w:val="1"/><w:numId w:val="1"/></w:numPr></w:pPr>
  <w:r><w:t>two</w:t></w:r>
</w:p>
<w:p>
  <w:pPr><w:pStyle w:val="Normal"/><w:numPr><w:ilvl w:val="2"/><w:numId w:val="1"/></w:numPr></w:pPr>
  <w:r><w:t>one</w:t></w:r>
</w:p>
<w:p>
  <w:pPr><w:pStyle w:val="Normal"/><w:numPr><w:ilvl w:val="2"/><w:numId w:val="1"/></w:numPr></w:pPr>
  <w:r><w:t>two</w:t></w:r>
</w:p>
<w:p>
  <w:pPr><w:pStyle w:val="Normal"/><w:numPr><w:ilvl w:val="2"/><w:numId w:val="1"/></w:numPr></w:pPr>
  <w:r><w:t>three</w:t></w:r>
</w:p>
<w:p>
  <w:pPr><w:pStyle w:val="Normal"/><w:numPr><w:ilvl w:val="1"/><w:numId w:val="1"/></w:numPr></w:pPr>
  <w:r><w:t>three</w:t></w:r>
</w:p>
<w:p>
  <w:pPr><w:pStyle w:val="Normal"/><w:numPr><w:ilvl w:val="0"/><w:numId w:val="1"/></w:numPr></w:pPr>
  <w:r><w:t>third list item</w:t></w:r>
</w:p>
1

There are 1 best solutions below

1
michael.hor257k On BEST ANSWER

It's difficult to read your code because (a) it's not indented properly and (b) it's taken out of context. You could probably have removed a significant portion of it too, leaving only what's essential to understanding the problem.

I suspect something like this could work you:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:w="http://schemas.microsoft.com/office/word/2003/wordml">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="/document">
    <w:wordDocument>
        <xsl:apply-templates/>
    </w:wordDocument>
</xsl:template>

<xsl:template match="listitem">
    <w:p>
        <w:pPr>
            <w:pStyle w:val="Normal"/>
            <w:numPr>
                <!-- level of list item (0,1,2 etc.) -->
                <w:ilvl w:val="{count(ancestor::orderedlist)-1}"/>
                <!-- the ordered list should get an ID (1,2,3 etc.) -->
                <w:numId w:val="{generate-id(..)}"/>
            </w:numPr>
        </w:pPr>
        <w:r>
            <w:t>
                <xsl:value-of select="text()"/>
            </w:t>
        </w:r>
    </w:p>
    <xsl:apply-templates />
</xsl:template>

<xsl:template match="text()"/>

</xsl:stylesheet>

When applied to your input example, the result will be:

<?xml version="1.0" encoding="UTF-8"?>
<w:wordDocument xmlns:w="http://schemas.microsoft.com/office/word/2003/wordml">
   <w:p>
      <w:pPr>
         <w:pStyle w:val="Normal"/>
         <w:numPr>
            <w:ilvl w:val="0"/>
            <w:numId w:val="d0e5"/>
         </w:numPr>
      </w:pPr>
      <w:r>
         <w:t>first list item</w:t>
      </w:r>
   </w:p>
   <w:p>
      <w:pPr>
         <w:pStyle w:val="Normal"/>
         <w:numPr>
            <w:ilvl w:val="0"/>
            <w:numId w:val="d0e5"/>
         </w:numPr>
      </w:pPr>
      <w:r>
         <w:t>second list item
                </w:t>
      </w:r>
   </w:p>
   <w:p>
      <w:pPr>
         <w:pStyle w:val="Normal"/>
         <w:numPr>
            <w:ilvl w:val="1"/>
            <w:numId w:val="d0e10"/>
         </w:numPr>
      </w:pPr>
      <w:r>
         <w:t>one</w:t>
      </w:r>
   </w:p>
   <w:p>
      <w:pPr>
         <w:pStyle w:val="Normal"/>
         <w:numPr>
            <w:ilvl w:val="1"/>
            <w:numId w:val="d0e10"/>
         </w:numPr>
      </w:pPr>
      <w:r>
         <w:t>two
                        </w:t>
      </w:r>
   </w:p>
   <w:p>
      <w:pPr>
         <w:pStyle w:val="Normal"/>
         <w:numPr>
            <w:ilvl w:val="2"/>
            <w:numId w:val="d0e15"/>
         </w:numPr>
      </w:pPr>
      <w:r>
         <w:t>one</w:t>
      </w:r>
   </w:p>
   <w:p>
      <w:pPr>
         <w:pStyle w:val="Normal"/>
         <w:numPr>
            <w:ilvl w:val="2"/>
            <w:numId w:val="d0e15"/>
         </w:numPr>
      </w:pPr>
      <w:r>
         <w:t>two</w:t>
      </w:r>
   </w:p>
   <w:p>
      <w:pPr>
         <w:pStyle w:val="Normal"/>
         <w:numPr>
            <w:ilvl w:val="2"/>
            <w:numId w:val="d0e15"/>
         </w:numPr>
      </w:pPr>
      <w:r>
         <w:t>three</w:t>
      </w:r>
   </w:p>
   <w:p>
      <w:pPr>
         <w:pStyle w:val="Normal"/>
         <w:numPr>
            <w:ilvl w:val="1"/>
            <w:numId w:val="d0e10"/>
         </w:numPr>
      </w:pPr>
      <w:r>
         <w:t>three</w:t>
      </w:r>
   </w:p>
   <w:p>
      <w:pPr>
         <w:pStyle w:val="Normal"/>
         <w:numPr>
            <w:ilvl w:val="0"/>
            <w:numId w:val="d0e5"/>
         </w:numPr>
      </w:pPr>
      <w:r>
         <w:t>third list item</w:t>
      </w:r>
   </w:p>
</w:wordDocument>

or similar (the id format is processor-dependent).