[xsl] Re: WordML Question and normalize-space() question

Subject: [xsl] Re: WordML Question and normalize-space() question
From: Jordan Soet <jds@xxxxxxxxxxxxxxxxxx>
Date: Tue, 23 May 2006 23:34:25 +0800
Hi,

Thanks everyone who responded to my question. I ended up using the suggestion by David Carlisle, since it seemed simple and normalizing the white space was fine (and actually preferred - I guess I should have been more specific), but thanks everyone else who responded too.

As far as the WordML question goes, I figured it out about 10 minutes after I sent out the e-mail (yay Murphy's law). I just had to apply the templates to the text() children of the formatting nodes instead of the actual nodes. For posterity's sake I'll post my solution here, since when I was looking online to see if anyone had done anything similar I couldn't find anything, but I'd guess that converting from XHTML to WordML would be a not unusual task.

(note that I'm just cutting and pasting the relevant parts from a bigger stylesheet, so it may have some mistakes)

<?xml version="1.0" encoding="ISO-8859-1"?>

<xsl:stylesheet version="1.0"
       xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
       xmlns:w="http://schemas.microsoft.com/office/word/2003/wordml";
       xmlns:xhtml="http://www.w3.org/1999/xhtml";
       xmlns:xp="http://www.giuntilabs.com/exact/xp_v1d0";
       xmlns:xlink="http://www.w3.org/1999/xlink";
       xmlns:v="urn:schemas-microsoft-com:vml"
       xmlns:o="urn:schemas-microsoft-com:office:office">


<xsl:template match="topic">
<xsl:processing-instruction name="mso-application">progid="Word.Document"</xsl:processing-instruction>
<w:wordDocument xmlns:w="http://schemas.microsoft.com/office/word/2003/wordml";
xmlns:v="urn:schemas-microsoft-com:vml"
xmlns:o="urn:schemas-microsoft-com:office:office"
xml:space="preserve">
<w:fonts>
<w:defaultFonts w:ascii="Verdana" w:fareast="Verdana"
w:h-ansi="Verdana" w:cs="Verdana"/>
</w:fonts>
<w:lists>
<w:listDef w:listDefId="0"><w:lsid w:val="0C931306"/><w:plt w:val="HybridMultilevel"/><w:tmpl w:val="1D0A726C"/><w:lvl w:ilvl="0" w:tplc="04090001"><w:start w:val="1"/><w:nfc w:val="23"/><w:lvlText w:val="?"/><w:lvlJc w:val="left"/><w:pPr><w:tabs><w:tab w:val="list" w:pos="720"/></w:tabs><w:ind w:left="720" w:hanging="360"/></w:pPr><w:rPr><w:rFonts w:ascii="Symbol" w:h-ansi="Symbol" w:hint="default"/></w:rPr></w:lvl><w:lvl w:ilvl="1" w:tplc="04090003"><w:start w:val="1"/><w:nfc w:val="23"/><w:lvlText w:val="o"/><w:lvlJc w:val="left"/><w:pPr><w:tabs><w:tab w:val="list" w:pos="1440"/></w:tabs><w:ind w:left="1440" w:hanging="360"/></w:pPr><w:rPr><w:rFonts w:ascii="Courier New" w:h-ansi="Courier New" w:cs="Courier New" w:hint="default"/></w:rPr></w:lvl><w:lvl w:ilvl="2" w:tplc="04090005"><w:start w:val="1"/><w:nfc w:val="23"/><w:lvlText w:val="?"/><w:lvlJc w:val="left"/><w:pPr><w:tabs><w:tab w:val="list" w:pos="2160"/></w:tabs><w:ind w:left="2160" w:hanging="360"/></w:pPr><w:rPr><w:rFonts w:ascii="Wingdings" w:h-ansi="Wingdings" w:hint="default"/></w:rPr></w:lvl><w:lvl w:ilvl="3" w:tplc="04090001" w:tentative="on"><w:start w:val="1"/><w:nfc w:val="23"/><w:lvlText w:val="?"/><w:lvlJc w:val="left"/><w:pPr><w:tabs><w:tab w:val="list" w:pos="2880"/></w:tabs><w:ind w:left="2880" w:hanging="360"/></w:pPr><w:rPr><w:rFonts w:ascii="Symbol" w:h-ansi="Symbol" w:hint="default"/></w:rPr></w:lvl><w:lvl w:ilvl="4" w:tplc="04090003" w:tentative="on"><w:start w:val="1"/><w:nfc w:val="23"/><w:lvlText w:val="o"/><w:lvlJc w:val="left"/><w:pPr><w:tabs><w:tab w:val="list" w:pos="3600"/></w:tabs><w:ind w:left="3600" w:hanging="360"/></w:pPr><w:rPr><w:rFonts w:ascii="Courier New" w:h-ansi="Courier New" w:cs="Courier New" w:hint="default"/></w:rPr></w:lvl><w:lvl w:ilvl="5" w:tplc="04090005" w:tentative="on"><w:start w:val="1"/><w:nfc w:val="23"/><w:lvlText w:val="?"/><w:lvlJc w:val="left"/><w:pPr><w:tabs><w:tab w:val="list" w:pos="4320"/></w:tabs><w:ind w:left="4320" w:hanging="360"/></w:pPr><w:rPr><w:rFonts w:ascii="Wingdings" w:h-ansi="Wingdings" w:hint="default"/></w:rPr></w:lvl><w:lvl w:ilvl="6" w:tplc="04090001" w:tentative="on"><w:start w:val="1"/><w:nfc w:val="23"/><w:lvlText w:val="?"/><w:lvlJc w:val="left"/><w:pPr><w:tabs><w:tab w:val="list" w:pos="5040"/></w:tabs><w:ind w:left="5040" w:hanging="360"/></w:pPr><w:rPr><w:rFonts w:ascii="Symbol" w:h-ansi="Symbol" w:hint="default"/></w:rPr></w:lvl><w:lvl w:ilvl="7" w:tplc="04090003" w:tentative="on"><w:start w:val="1"/><w:nfc w:val="23"/><w:lvlText w:val="o"/><w:lvlJc w:val="left"/><w:pPr><w:tabs><w:tab w:val="list" w:pos="5760"/></w:tabs><w:ind w:left="5760" w:hanging="360"/></w:pPr><w:rPr><w:rFonts w:ascii="Courier New" w:h-ansi="Courier New" w:cs="Courier New" w:hint="default"/></w:rPr></w:lvl><w:lvl w:ilvl="8" w:tplc="04090005" w:tentative="on"><w:start w:val="1"/><w:nfc w:val="23"/><w:lvlText w:val="?"/><w:lvlJc w:val="left"/><w:pPr><w:tabs><w:tab w:val="list" w:pos="6480"/></w:tabs><w:ind w:left="6480" w:hanging="360"/></w:pPr><w:rPr><w:rFonts w:ascii="Wingdings" w:h-ansi="Wingdings" w:hint="default"/></w:rPr></w:lvl></w:listDef>
<w:listDef w:listDefId="1"><w:lsid w:val="084A36DE"/><w:plt w:val="HybridMultilevel"/><w:tmpl w:val="55B6A106"/><w:lvl w:ilvl="0" w:tplc="0409000F"><w:start w:val="1"/><w:lvlText w:val="%1."/><w:lvlJc w:val="left"/><w:pPr><w:tabs><w:tab w:val="list" w:pos="720"/></w:tabs><w:ind w:left="720" w:hanging="360"/></w:pPr></w:lvl><w:lvl w:ilvl="1" w:tplc="04090019" w:tentative="on"><w:start w:val="1"/><w:nfc w:val="4"/><w:lvlText w:val="%2."/><w:lvlJc w:val="left"/><w:pPr><w:tabs><w:tab w:val="list" w:pos="1440"/></w:tabs><w:ind w:left="1440" w:hanging="360"/></w:pPr></w:lvl><w:lvl w:ilvl="2" w:tplc="0409001B" w:tentative="on"><w:start w:val="1"/><w:nfc w:val="2"/><w:lvlText w:val="%3."/><w:lvlJc w:val="right"/><w:pPr><w:tabs><w:tab w:val="list" w:pos="2160"/></w:tabs><w:ind w:left="2160" w:hanging="180"/></w:pPr></w:lvl><w:lvl w:ilvl="3" w:tplc="0409000F" w:tentative="on"><w:start w:val="1"/><w:lvlText w:val="%4."/><w:lvlJc w:val="left"/><w:pPr><w:tabs><w:tab w:val="list" w:pos="2880"/></w:tabs><w:ind w:left="2880" w:hanging="360"/></w:pPr></w:lvl><w:lvl w:ilvl="4" w:tplc="04090019" w:tentative="on"><w:start w:val="1"/><w:nfc w:val="4"/><w:lvlText w:val="%5."/><w:lvlJc w:val="left"/><w:pPr><w:tabs><w:tab w:val="list" w:pos="3600"/></w:tabs><w:ind w:left="3600" w:hanging="360"/></w:pPr></w:lvl><w:lvl w:ilvl="5" w:tplc="0409001B" w:tentative="on"><w:start w:val="1"/><w:nfc w:val="2"/><w:lvlText w:val="%6."/><w:lvlJc w:val="right"/><w:pPr><w:tabs><w:tab w:val="list" w:pos="4320"/></w:tabs><w:ind w:left="4320" w:hanging="180"/></w:pPr></w:lvl><w:lvl w:ilvl="6" w:tplc="0409000F" w:tentative="on"><w:start w:val="1"/><w:lvlText w:val="%7."/><w:lvlJc w:val="left"/><w:pPr><w:tabs><w:tab w:val="list" w:pos="5040"/></w:tabs><w:ind w:left="5040" w:hanging="360"/></w:pPr></w:lvl><w:lvl w:ilvl="7" w:tplc="04090019" w:tentative="on"><w:start w:val="1"/><w:nfc w:val="4"/><w:lvlText w:val="%8."/><w:lvlJc w:val="left"/><w:pPr><w:tabs><w:tab w:val="list" w:pos="5760"/></w:tabs><w:ind w:left="5760" w:hanging="360"/></w:pPr></w:lvl><w:lvl w:ilvl="8" w:tplc="0409001B" w:tentative="on"><w:start w:val="1"/><w:nfc w:val="2"/><w:lvlText w:val="%9."/><w:lvlJc w:val="right"/><w:pPr><w:tabs><w:tab w:val="list" w:pos="6480"/></w:tabs><w:ind w:left="6480" w:hanging="180"/></w:pPr></w:lvl></w:listDef>
<xsl:for-each select="/descendant::xhtml:ul">
<w:list w:ilfo="{position()}">
<w:ilst w:val="0"/>
</w:list>
</xsl:for-each>
<xsl:for-each select="/descendant::xhtml:ol">
<w:list w:ilfo="{count(/descendant::xhtml:ul) + position()}">
<w:ilst w:val="1"/>
<w:lvlOverride>
<w:startOverride w:val="1"/>
</w:lvlOverride>
</w:list>
</xsl:for-each>
<w:list w:ilfo="{count(/descendant::xhtml:ul) + count(/descendant::xhtml:ol) + 1}">
<w:ilst w:val="1"/>
<w:lvlOverride>
<w:startOverride w:val="1"/>
</w:lvlOverride>
</w:list>
</w:lists>
<w:styles>
<w:styles>
<w:style w:type="paragraph" w:default="on" w:styleId="Normal">
<w:name w:val="Normal"/>
<w:rPr>
<w:sz w:val="22"/>
</w:rPr>
</w:style>
<w:style w:type="paragraph" w:styleId="NormalParagraph">
<w:name w:val="Normal Paragraph"/>
<w:pPr>
<w:spacing w:before="150"/>
</w:pPr>
<w:rPr>
<w:sz w:val="22"/>
</w:rPr>
</w:style>
<w:style w:type="paragraph" w:styleId="Heading1">
<w:name w:val="Heading 1"/>
<w:pPr>
<w:keepNext w:val="on"/>
<w:spacing w:before="300"/>
</w:pPr>
<w:rPr>
<w:sz w:val="28"/>
<w:b/>
</w:rPr>
</w:style>
<w:style w:type="paragraph" w:styleId="Credits">
<w:name w:val="Credits"/>
<w:rPr>
<w:sz w:val="16"/>
<w:color w:val="C0C0C0"/>
</w:rPr>
</w:style>
<w:style w:type="paragraph" w:styleId="InstructionRed">
<w:name w:val="Instruction Red"/>
<w:rPr>
<w:sz w:val="17"/>
<w:color w:val="800000"/>
<w:b/>
</w:rPr>
</w:style>
<w:style w:type="paragraph" w:styleId="Header">
<w:name w:val="Header"/>
<w:rPr>
<w:sz w:val="22"/>
</w:rPr>
</w:style>
<w:style w:type="paragraph" w:styleId="Footer">
<w:name w:val="Footer"/>
<w:rPr>
<w:sz w:val="16"/>
</w:rPr>
</w:style>
</w:styles>
<w:docPr>
<w:view w:val="print" w:percent="80"/>
</w:docPr>
</xsl:template>


<xsl:template match="xhtml:p">
<w:p>
<w:pPr>
<w:pStyle w:val="NormalParagraph"/>
<xsl:if test="@align">
<w:jc w:val="{@align}"/>
</xsl:if>
</w:pPr>
<xsl:apply-templates/>
</w:p>
<xsl:call-template name="Resource_Links"/>
</xsl:template>



<xsl:template match="xhtml:p/text()|xhtml:td/text()|xhtml:th/text()|Description/text()">
<xsl:variable name="x" select="normalize-space(concat('!',.,'!'))"/>
<w:r>
<w:t><xsl:value-of select="substring($x,2,string-length($x)-2)"/></w:t>
</w:r>
</xsl:template>




<xsl:template match="xhtml:li">
<w:p>
<w:pPr>
<w:listPr>
<w:ilvl w:val="{count(ancestor::xhtml:ul|ancestor::xhtml:ol)-1}"/>
<w:ilfo>
<xsl:attribute name="w:val">
<xsl:choose>
<xsl:when test="parent::xhtml:ul">
<xsl:value-of select="count(preceding::xhtml:ul) + 1"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="count(/descendant::xhtml:ul) + count(preceding::xhtml:ol) + 1"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
</w:ilfo>
</w:listPr>
</w:pPr>
<xsl:apply-templates select="text()|*[not(self::xhtml:ul|self::xhtml:ol)]"/>
</w:p>
<xsl:apply-templates select="xhtml:ul|xhtml:ol"/>
<xsl:call-template name="Resource_Links"/>
</xsl:template>


<xsl:template match="xhtml:li/text()">
   <w:r>
       <w:t>
           <xsl:value-of select="."/>
       </w:t>
   </w:r>
</xsl:template>

<xsl:template match="xhtml:u/text()">
   <xsl:call-template name="FormatProperties"/>
</xsl:template>



<xsl:template match="xhtml:strong/text()|xhtml:b/text()|b/text()">
   <xsl:call-template name="FormatProperties"/>
</xsl:template>



<xsl:template match="xhtml:em/text()|i/text()">
   <xsl:call-template name="FormatProperties"/>
</xsl:template>



<xsl:template match="xhtml:a/text()|link/text()|Link_Text/text()">
   <xsl:call-template name="FormatProperties"/>
</xsl:template>



<xsl:template match="xhtml:font/text()">
   <xsl:call-template name="FormatProperties"/>
</xsl:template>


<xsl:template name="FormatProperties">
<w:r>
<w:rPr>
<xsl:if test="ancestor::xhtml:strong|ancestor::xhtml:b|ancestor::b">
<w:b/>
</xsl:if>
<xsl:if test="ancestor::xhtml:em|ancestor::i">
<w:i/>
</xsl:if>
<xsl:if test="ancestor::xhtml:u">
<w:u w:val="single"/>
</xsl:if>
<xsl:if test="ancestor::xhtml:a|ancestor::link|ancestor::Link_Text">
<w:color w:val="0000FF"/>
<w:u w:val="single"/>
</xsl:if>
</w:rPr>
<w:t><xsl:value-of select="."/></w:t>
</w:r>
</xsl:template>



<xsl:template match="xhtml:br|br"> <w:br/> </xsl:template>


</xsl:stylesheet>



The stuff about how to generate the lists I got from here: http://www.tkachenko.com/blog/archives/000136.html


And I didn't include my conversion for the tables, because I did a bit of preprocessing on the xml file to make it easier to deal with and so that part wouldn't make much sense.


Thanks again, Jordan

Current Thread