[xsl] ooxml grouping

Subject: [xsl] ooxml grouping
From: Andreas Peter <info@xxxxxxxxxx>
Date: Sun, 14 Dec 2008 11:50:27 +0100
Hello List,

for about two weeks (unfortunately not fulltime) I am trying to transform a simple sample MS Word document to a structured xml document. But now I need the help from the experts.

My input document looks like the following:


<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:document xmlns:ve="http://schemas.openxmlformats.org/markup-compatibility/2006";
xmlns:o ="urn:schemas-microsoft-com:office:office"
xmlns:r ="http://schemas.openxmlformats.org/officeDocument/2006/relationships";
xmlns:m ="http://schemas.openxmlformats.org/officeDocument/2006/math"; xmlns:v="urn:schemas-microsoft-com:vml"
xmlns:wp ="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing";
xmlns:w10 ="urn:schemas-microsoft-com:office:word"
xmlns:w ="http://schemas.openxmlformats.org/wordprocessingml/2006/main";
xmlns:wne ="http://schemas.microsoft.com/office/word/2006/wordml";>
<w:body>
<w:p w:rsidR="00C10400" w:rsidRPr="00C34BB4" w:rsidRDefault="00C10400" w:rsidP="00C10400">
<w:pPr>
<w:pStyle w:val="chaptitle"/>
</w:pPr>
<w:r>
<w:t>16</w:t>
</w:r>
<w:r w:rsidRPr="00C10400">
<w:rPr>
<w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math" w:cs="Cambria Math"/>
</w:rPr>
<w:t>b</w:t>
</w:r>
<w:r>
<w:t>chaptertitle</w:t>
</w:r>
</w:p>
<w:p w:rsidR="00C10400" w:rsidRPr="00C34BB4" w:rsidRDefault="00C10400" w:rsidP="00C10400">
<w:pPr>
<w:pStyle w:val="authors"/>
</w:pPr>
<w:r>
<w:t>author</w:t>
</w:r>
</w:p>
<w:p w:rsidR="00C10400" w:rsidRPr="004262E6" w:rsidRDefault="00C10400" w:rsidP="00C10400">
<w:pPr>
<w:pStyle w:val="boxtype"/>
</w:pPr>
<w:r>
<w:t>box_8</w:t>
</w:r>
</w:p>
<w:p w:rsidR="00C10400" w:rsidRPr="00C34BB4" w:rsidRDefault="00C10400" w:rsidP="00C10400">
<w:pPr>
<w:pStyle w:val="boxtitle"/>
</w:pPr>
<w:r>
<w:t>boxtitle</w:t>
</w:r>
</w:p>
<w:p w:rsidR="00C10400" w:rsidRPr="00C34BB4" w:rsidRDefault="00C10400" w:rsidP="00C10400">
<w:pPr>
<w:pStyle w:val="bodytext"/>
</w:pPr>
<w:r>
<w:t xml:space="preserve">bodytext </w:t>
</w:r>
<w:r w:rsidRPr="007B59BB">
<w:rPr>
<w:rStyle w:val="specialchar"/>
</w:rPr>
<w:t>specialcharacter</w:t>
</w:r>
<w:r w:rsidRPr="00D2553A">
<w:rPr>
<w:rStyle w:val="sub"/>
</w:rPr>
<w:t>subscript</w:t>
</w:r>
<w:r>
<w:t xml:space="preserve">bodytext </w:t>
</w:r>
<w:r w:rsidRPr="007B59BB">
<w:rPr>
<w:rStyle w:val="specialchar"/>
</w:rPr>
<w:t>specialcharacter</w:t>
</w:r>
<w:r w:rsidRPr="00D2553A">
<w:rPr>
<w:rStyle w:val="sub"/>
</w:rPr>
<w:t>subscript</w:t>
</w:r>
<w:r>
<w:t xml:space="preserve">bodytext </w:t>
</w:r>
<w:r w:rsidRPr="007B59BB">
<w:rPr>
<w:rStyle w:val="specialchar"/>
</w:rPr>
<w:t>specialcharacter</w:t>
</w:r>
<w:r>
<w:t xml:space="preserve">bodytext </w:t>
</w:r>
<w:r w:rsidRPr="007B59BB">
<w:rPr>
<w:rStyle w:val="specialchar"/>
</w:rPr>
<w:t>specialcharacter</w:t>
</w:r>
<w:r w:rsidRPr="00D2553A">
<w:rPr>
<w:rStyle w:val="sub"/>
</w:rPr>
<w:t>subscript</w:t>
</w:r>
<w:r>
<w:t xml:space="preserve">bodytext </w:t>
</w:r>
<w:r w:rsidRPr="00880217">
<w:t>bodytext</w:t>
</w:r>
<w:r>
<w:t>,</w:t>
</w:r>
<w:r w:rsidRPr="00880217">
<w:t xml:space="preserve"> bodytext</w:t>
</w:r>
<w:r>
<w:t xml:space="preserve">bodytext </w:t>
</w:r>
<w:r w:rsidRPr="007B59BB">
<w:rPr>
<w:rStyle w:val="specialchar"/>
</w:rPr>
<w:t>specialcharacter</w:t>
</w:r>
<w:r w:rsidRPr="00D2553A">
<w:rPr>
<w:rStyle w:val="sub"/>
</w:rPr>
<w:t>subscript</w:t>
</w:r>
<w:r>
<w:t xml:space="preserve">bodytext </w:t>
</w:r>
<w:r w:rsidRPr="007B59BB">
<w:rPr>
<w:rStyle w:val="specialchar"/>
</w:rPr>
<w:t>specialcharacter</w:t>
</w:r>
<w:r w:rsidRPr="00D2553A">
<w:rPr>
<w:rStyle w:val="sub"/>
</w:rPr>
<w:t>subscript</w:t>
</w:r>
<w:r>
<w:t xml:space="preserve">bodytext </w:t>
</w:r>
<w:r w:rsidRPr="007B59BB">
<w:rPr>
<w:rStyle w:val="specialchar"/>
</w:rPr>
<w:t>specialcharacter</w:t>
</w:r>
<w:r w:rsidRPr="00D2553A">
<w:rPr>
<w:rStyle w:val="sub"/>
</w:rPr>
<w:t>subscript</w:t>
</w:r>
<w:r>
<w:t xml:space="preserve">bodytext </w:t>
</w:r>
<w:r w:rsidRPr="007B59BB">
<w:rPr>
<w:rStyle w:val="specialchar"/>
</w:rPr>
<w:t>specialcharacter</w:t>
</w:r>
<w:r w:rsidRPr="00D2553A">
<w:rPr>
<w:rStyle w:val="sub"/>
</w:rPr>
<w:t>subscript</w:t>
</w:r>
<w:r>
<w:t xml:space="preserve">bodytext </w:t>
</w:r>
<w:r w:rsidRPr="007B59BB">
<w:rPr>
<w:rStyle w:val="specialchar"/>
</w:rPr>
<w:t>specialcharacter</w:t>
</w:r>
<w:r w:rsidRPr="00D2553A">
<w:rPr>
<w:rStyle w:val="sub"/>
</w:rPr>
<w:t>subscript</w:t>
</w:r>
<w:r>
<w:t xml:space="preserve">bodytext </w:t>
</w:r>
<w:r w:rsidRPr="007B59BB">
<w:rPr>
<w:rStyle w:val="specialchar"/>
</w:rPr>
<w:t>specialcharacter</w:t>
</w:r>
<w:r w:rsidRPr="00D2553A">
<w:rPr>
<w:rStyle w:val="sub"/>
</w:rPr>
<w:t>subscript</w:t>
</w:r>
<w:r>
<w:t>bodytext</w:t>
</w:r>
</w:p>
<w:p w:rsidR="00C10400" w:rsidRPr="004262E6" w:rsidRDefault="00C10400" w:rsidP="00C10400">
<w:pPr>
<w:pStyle w:val="boxtypeend"/>
</w:pPr>
<w:r>
<w:t>box_8_end</w:t>
</w:r>
</w:p>
<w:p w:rsidR="00C10400" w:rsidRPr="004262E6" w:rsidRDefault="00C10400" w:rsidP="00C10400">
<w:pPr>
<w:pStyle w:val="boxtype"/>
</w:pPr>
<w:r>
<w:t>box_5</w:t>
</w:r>
</w:p>
<w:p w:rsidR="00C10400" w:rsidRPr="00C34BB4" w:rsidRDefault="00C10400" w:rsidP="00C10400">
<w:pPr>
<w:pStyle w:val="boxtitle"/>
</w:pPr>
<w:r>
<w:t>boxtitle</w:t>
</w:r>
</w:p>
<w:p w:rsidR="00C10400" w:rsidRPr="00C34BB4" w:rsidRDefault="00C10400" w:rsidP="00C10400">
<w:pPr>
<w:pStyle w:val="bodytext"/>
</w:pPr>
<w:r>
<w:t>bodytext</w:t>
</w:r>
</w:p>
<w:p w:rsidR="00C10400" w:rsidRPr="004262E6" w:rsidRDefault="00C10400" w:rsidP="00C10400">
<w:pPr>
<w:pStyle w:val="boxtypeend"/>
</w:pPr>
<w:bookmarkStart w:id="0" w:name="_Toc188456515"/>
<w:bookmarkStart w:id="1" w:name="_Toc188616690"/>
<w:r>
<w:t>box_5_end</w:t>
</w:r>
</w:p>
<w:p w:rsidR="00C10400" w:rsidRPr="00C34BB4" w:rsidRDefault="00C10400" w:rsidP="00C10400">
<w:pPr>
<w:pStyle w:val="h1"/>
</w:pPr>
<w:r>
<w:t>heading_1</w:t>
</w:r>
<w:r w:rsidRPr="00C10400">
<w:rPr>
<w:rFonts w:ascii="Cambria Math" w:hAnsi="Cambria Math" w:cs="Cambria Math"/>
</w:rPr>
<w:t>b</w:t>
</w:r>
<w:r>
<w:t>heading_1_text</w:t>
</w:r>
<w:bookmarkEnd w:id="0"/>
<w:bookmarkEnd w:id="1"/>
</w:p>
<w:p w:rsidR="00C10400" w:rsidRPr="00C34BB4" w:rsidRDefault="00C10400" w:rsidP="00C10400">
<w:pPr>
<w:pStyle w:val="bodytext"/>
</w:pPr>
<w:r>
<w:lastRenderedPageBreak/>
<w:t xml:space="preserve">bodytext </w:t>
</w:r>
<w:r w:rsidRPr="007B59BB">
<w:rPr>
<w:rStyle w:val="emph1"/>
</w:rPr>
<w:t>emhapsis_1</w:t>
</w:r>
<w:r>
<w:t xml:space="preserve"> bodytext </w:t>
</w:r>
<w:r w:rsidRPr="007B59BB">
<w:rPr>
<w:rStyle w:val="emph1"/>
</w:rPr>
<w:t>emphasis_1</w:t>
</w:r>
<w:r>
<w:t xml:space="preserve"> bodytext </w:t>
</w:r>
<w:r w:rsidRPr="007B59BB">
<w:rPr>
<w:rStyle w:val="emph1"/>
</w:rPr>
<w:t>emphasis_1</w:t>
</w:r>
<w:r>
<w:t xml:space="preserve"> bodytext </w:t>
</w:r>
<w:r w:rsidRPr="007B59BB">
<w:rPr>
<w:rStyle w:val="emph1"/>
</w:rPr>
<w:t>emphasis_1</w:t>
</w:r>
<w:r>
<w:t xml:space="preserve"> bodytext </w:t>
</w:r>
<w:r w:rsidRPr="007B59BB">
<w:rPr>
<w:rStyle w:val="emph1"/>
</w:rPr>
<w:t>emphasis_1</w:t>
</w:r>
<w:r>
<w:t xml:space="preserve"> bodytext</w:t>
</w:r>
<w:r w:rsidR="00966174">
<w:rPr>
<w:rStyle w:val="FootnoteReference"/>
</w:rPr>
<w:footnoteReference w:id="2"/>
</w:r>
</w:p>
<w:p w:rsidR="00C10400" w:rsidRPr="00C34BB4" w:rsidRDefault="00C10400" w:rsidP="00C10400">
<w:pPr>
<w:pStyle w:val="bodytext"/>
</w:pPr>
<w:r>
<w:t xml:space="preserve">bodytext </w:t>
</w:r>
<w:r w:rsidRPr="007B59BB">
<w:rPr>
<w:rStyle w:val="emph1"/>
</w:rPr>
<w:t>emphasis_1</w:t>
</w:r>
<w:r>
<w:t xml:space="preserve"> bodytext </w:t>
</w:r>
<w:r w:rsidRPr="007B59BB">
<w:rPr>
<w:rStyle w:val="emph1"/>
</w:rPr>
<w:t>emphasis_1</w:t>
</w:r>
<w:r>
<w:t xml:space="preserve"> bodytext</w:t>
</w:r>
<w:r w:rsidRPr="007B59BB">
<w:rPr>
<w:rStyle w:val="crossref"/>
</w:rPr>
<w:t>xref</w:t>
</w:r>
<w:r>
<w:t>bodytext</w:t>
</w:r>
<w:r w:rsidRPr="007B59BB">
<w:rPr>
<w:rStyle w:val="crossref"/>
</w:rPr>
<w:t>xref</w:t>
</w:r>
<w:r>
<w:t>bodytext</w:t>
</w:r>
<w:r w:rsidRPr="007B59BB">
<w:rPr>
<w:rStyle w:val="crossref"/>
</w:rPr>
<w:t>xref</w:t>
</w:r>
<w:r>
<w:t>bodytext</w:t>
</w:r>
</w:p>
<w:p w:rsidR="00C10400" w:rsidRPr="004262E6" w:rsidRDefault="00C10400" w:rsidP="00C10400">
<w:pPr>
<w:pStyle w:val="boxtype"/>
</w:pPr>
<w:r>
<w:t>box_1</w:t>
</w:r>
</w:p>
<w:p w:rsidR="00C10400" w:rsidRPr="00C34BB4" w:rsidRDefault="00C10400" w:rsidP="00C10400">
<w:pPr>
<w:pStyle w:val="boxtitle"/>
</w:pPr>
<w:r>
<w:t>boxtitle</w:t>
</w:r>
</w:p>
<w:p w:rsidR="00C10400" w:rsidRPr="00C34BB4" w:rsidRDefault="00C10400" w:rsidP="00C10400">
<w:pPr>
<w:pStyle w:val="bodytext"/>
</w:pPr>
<w:r>
<w:t>bodytext</w:t>
</w:r>
</w:p>
<w:p w:rsidR="00673F5D" w:rsidRPr="008148C1" w:rsidRDefault="00C10400" w:rsidP="00622C83">
<w:pPr>
<w:pStyle w:val="boxtypeend"/>
</w:pPr>
<w:r>
<w:t>box_1_end</w:t>
</w:r>
</w:p>
<w:sectPr w:rsidR="00673F5D" w:rsidRPr="008148C1" w:rsidSect="001706A7">
<w:headerReference w:type="even" r:id="rId8"/>
<w:footerReference w:type="default" r:id="rId9"/>
<w:type w:val="continuous"/>
<w:pgSz w:w="11906" w:h="16838"/>
<w:pgMar w:top="1417" w:right="1417" w:bottom="1134" w:left="1417" w:header="720" w:footer="720"
w:gutter ="0"/>
<w:cols w:space="720"/>
</w:sectPr>
</w:body>
</w:document>



The xslt looks like:



<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
xmlns:ve ="http://schemas.openxmlformats.org/markup-compatibility/2006";
xmlns:o ="urn:schemas-microsoft-com:office:office"
xmlns:r ="http://schemas.openxmlformats.org/officeDocument/2006/relationships";
xmlns:m ="http://schemas.openxmlformats.org/officeDocument/2006/math"; xmlns:v="urn:schemas-microsoft-com:vml"
xmlns:wp ="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing";
xmlns:w10 ="urn:schemas-microsoft-com:office:word"
xmlns:w ="http://schemas.openxmlformats.org/wordprocessingml/2006/main";
xmlns:wne ="http://schemas.microsoft.com/office/word/2006/wordml"; exclude-result-prefixes="wp w10 w wne ve o r m v"
version ="2.0">


<xsl:output encoding="UTF-16" indent="yes" method="xml"/>

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

<xsl:template match="w:body">
<xsl:for-each-group select="w:p" group-starting-with="*[descendant::*/@w:val='chaptitle']">
<chapter>
<title>
<xsl:apply-templates/>
</title>
<xsl:for-each select="current-group()[descendant::*/@w:val='authors']">
<authors>
<xsl:apply-templates/>
</authors>
</xsl:for-each>
<xsl:for-each-group select="current-group()"
group-starting-with ="*[descendant::*/@w:val='h1']|*[descendant::*/@w:val='h2']|*[descendant::*/@w:val='h3']|*[descendant::*/@w:val='h4']|*[descendant::*/@w:val='h5']">
<title>
<xsl:apply-templates/>
</title>
<xsl:for-each-group select="current-group()"
group-starting-with ="*[descendant::*/@w:val='boxtitle']|*[descendant::*/@w:val='boxh1']|*[descendant::*/@w:val='boxh2']|*[descendant::*/@w:val='bodytext']">
<box>
<xsl:choose>
<xsl:when test="current-group()[descendant::*/@w:val='boxtitle']">
<title>
<xsl:apply-templates/>
</title>
</xsl:when>
<xsl:when test="current-group()[descendant::*/@w:val='boxh1']">
<subtitle>
<xsl:apply-templates/>
</subtitle>
</xsl:when>
<xsl:when test="current-group()[descendant::*/@w:val='boxh2']">
<subsubtitle>
<xsl:apply-templates/>
</subsubtitle>
</xsl:when>
<xsl:when test="current-group()[descendant::*/@w:val='bodytext']">
<para>
<xsl:apply-templates select="current-group()"/>
</para>
</xsl:when>
</xsl:choose>
</box>
</xsl:for-each-group>
</xsl:for-each-group>
</chapter>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>



The required output should be:



<?xml version="1.0" encoding="UTF-16"?>
<chapter>
<title>16 chaptertitle</title>
<authors>author</authors>
<!-- may start with box, paragraph, heading, ... -->
<box>
<title>boxtitle</title>
<para>bodytext<specialcharacter>specialcharacter</specialcharacter><subscript>subscript</subscript>bodytext<specialcharacter>specialcharacter</specialcharacter></para>
</box>
<!-- an so on -->
<box>
<title>boxtitle</title>
<para>bodytext</para>
</box>


   <section>
       <title>heading_1_text</title>
       <box>
           <title>...</title>
           <para>all child elements</para>
       </box>
       <box>
           <title>...</title>
           <para>...</para>
       </box>
       <para>
           <!-- if there is a paragraph -->
       </para>
   </section>
</chapter>


I hope this is not too much source code and more or less self explaining.


Thanks in advance,
Andreas

Current Thread