1 <xsl:stylesheet version="1.0"
2 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
3 xmlns:w="http://schemas.microsoft.com/office/word/2003/wordml"
4 xmlns:v="urn:schemas-microsoft-com:vml"
5 xmlns:w10="urn:schemas-microsoft-com:office:word"
6 xmlns:sl="http://schemas.microsoft.com/schemaLibrary/2003/core"
7 xmlns:aml="http://schemas.microsoft.com/aml/2001/core"
8 xmlns:wx="http://schemas.microsoft.com/office/word/2003/auxHint"
9 xmlns:o="urn:schemas-microsoft-com:office:office"
10 xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"
11 xmlns:dbk='http://docbook.org/ns/docbook'
12 xmlns:rnd='http://docbook.org/ns/docbook/roundtrip'
13 xmlns:xlink='http://www.w3.org/1999/xlink'
14 xmlns:exsl='http://exslt.org/common'
15 exclude-result-prefixes='w v w10 sl aml wx o dt'
16 extension-element-prefixes='exsl'>
18 <xsl:import href='normalise-common.xsl'/>
20 <xsl:output method='xml' indent="yes"/>
22 <!-- ********************************************************************
23 $Id: wordml2normalise.xsl 8105 2008-08-15 01:29:11Z balls $
24 ********************************************************************
26 This file is part of the XSL DocBook Stylesheet distribution.
27 See ../README or http://nwalsh.com/docbook/xsl/ for copyright
28 and other information.
30 ******************************************************************** -->
32 <xsl:strip-space elements='*'/>
33 <xsl:preserve-space elements='w:t'/>
39 <xsl:template match="w:wordDocument">
41 <xsl:apply-templates select='w:body'/>
45 <xsl:template match='wx:borders |
48 <xsl:template match='w:p'>
49 <xsl:variable name='style'>
50 <xsl:call-template name='rnd:map-paragraph-style'>
51 <xsl:with-param name='style' select='w:pPr/w:pStyle/@w:val'/>
55 <xsl:when test='aml:annotation[@w:type = "Word.Deletion"] and
56 not(aml:annotation[@w:type != "Word.Deletion"]) and
57 count(*) = count(aml:annotation|w:pPr)'/>
59 <!-- Eliminate paragraphs that have no content.
60 These are section or page breaks.
62 <xsl:when test='not(w:r|w:hlink|w:tbl) and
67 <xsl:attribute name='rnd:style'>
68 <xsl:value-of select='$style'/>
70 <xsl:if test='w:pPr/w:pStyle/@w:val and
71 $style != w:pPr/w:pStyle/@w:val'>
72 <xsl:attribute name='rnd:original-style'>
73 <xsl:value-of select='w:pPr/w:pStyle/@w:val'/>
77 <xsl:if test='w:r[1][w:rPr/w:rStyle/@w:val = "attributes"] and
78 w:r[2][w:rPr/w:rStyle/@w:val = "CommentReference"]'>
79 <xsl:apply-templates select='w:r[2]//w:r[w:rPr/w:rStyle/@w:val = "attribute-name"]'
80 mode='rnd:attributes'/>
83 <xsl:apply-templates/>
89 <xsl:template match='*' mode='rnd:attributes'>
90 <xsl:attribute name='{w:t}'>
91 <xsl:apply-templates select='following-sibling::w:r[w:rPr/w:rStyle/@w:val = "attribute-value"][1]'
92 mode='rnd:attribute-value'/>
96 <xsl:template match='w:r'>
97 <xsl:param name='do-vert-align' select='true()'/>
99 <xsl:variable name='role'>
101 <xsl:when test='w:rPr/w:b and
103 <xsl:text>bold-italic</xsl:text>
105 <xsl:when test='w:rPr/w:b'>
106 <xsl:text>bold</xsl:text>
108 <xsl:when test='w:rPr/w:i'>
109 <xsl:text>italic</xsl:text>
111 <xsl:when test='w:rPr/w:u'>
112 <xsl:text>underline</xsl:text>
114 <!-- TODO: add support for other styles -->
117 <xsl:variable name='style'>
118 <xsl:if test='w:rPr/w:rStyle'>
119 <xsl:value-of select='w:rPr/w:rStyle/@w:val'/>
124 <xsl:when test='w:rPr/w:rStyle/@w:val = "attributes"'/>
125 <xsl:when test='w:rPr/w:rStyle/@w:val = "CommentReference"'/>
126 <xsl:when test='w:pict'>
127 <!-- "filename" is where the image data gets extracted to -->
128 <xsl:variable name='filename'>
129 <xsl:call-template name='rnd:image-filename'/>
131 <!-- "target" is the URL that will be the target of the imagedata hyperlink.
132 This may or may not be related to the physical filename.
134 <xsl:variable name='target'>
135 <xsl:call-template name='rnd:image-target'>
136 <xsl:with-param name='filename' select='$filename'/>
140 <xsl:call-template name='rnd:handle-image-data'>
141 <xsl:with-param name='filename' select='$filename'/>
142 <xsl:with-param name='data' select='w:pict/w:binData'/>
145 <dbk:inlinemediaobject>
147 <dbk:imagedata fileref='{$target}'>
148 <xsl:if test='w:pict/v:shape/@style'>
149 <xsl:attribute name='width'>
150 <xsl:value-of select='normalize-space(substring-before(substring-after(w:pict/v:shape/@style, "width:"), ";"))'/>
152 <xsl:attribute name='depth'>
153 <xsl:value-of select='normalize-space(substring-after(w:pict/v:shape/@style, "height:"))'/>
158 </dbk:inlinemediaobject>
160 <xsl:when test='$do-vert-align and
161 w:rPr/w:vertAlign/@w:val = "subscript"'>
163 <xsl:apply-templates select='.'>
164 <xsl:with-param name='do-vert-align' select='false()'/>
165 </xsl:apply-templates>
168 <xsl:when test='$do-vert-align and
169 w:rPr/w:vertAlign/@w:val = "superscript"'>
171 <xsl:apply-templates select='.'>
172 <xsl:with-param name='do-vert-align' select='false()'/>
173 </xsl:apply-templates>
176 <xsl:when test='w:endnoteRef and
177 parent::w:p/parent::w:endnote and
178 count(w:rPr|w:endnoteRef) = count(*)'/>
179 <xsl:when test='w:footnoteRef'/> <!-- is a label supplied? -->
180 <xsl:when test='w:footnote|w:endnote'>
182 <xsl:apply-templates select='w:footnote|w:endnote'/>
185 <xsl:when test='$role != "" or $style != ""'>
187 <xsl:if test='$role != ""'>
188 <xsl:attribute name='role'>
189 <xsl:value-of select='$role'/>
192 <xsl:if test='$style != ""'>
193 <xsl:attribute name='rnd:style'>
194 <xsl:call-template name='rnd:map-character-style'>
195 <xsl:with-param name='style' select='$style'/>
199 <xsl:apply-templates/>
203 <xsl:apply-templates/>
208 <!-- An application may wish to override these templates -->
210 <!-- rnd:image-filename determines the filename of the physical file
211 to which the image data should be written.
213 <xsl:template name='rnd:image-filename'>
214 <xsl:param name='pict' select='w:pict'/>
217 <xsl:when test='contains($pict/w:binData/@w:name, "wordml://")'>
218 <xsl:value-of select='substring-after($pict/w:binData/@w:name, "wordml://")'/>
221 <xsl:text>image</xsl:text>
222 <xsl:value-of select='count($pict/preceding::w:pict) + 1'/>
223 <xsl:text>.jpg</xsl:text>
228 <!-- rnd:image-target determines the URL for the image data.
229 This may or may not be related to the physical filename.
231 <xsl:template name='rnd:image-target'>
232 <xsl:param name='filename'/>
233 <xsl:param name='pict' select='w:pict'/>
235 <xsl:value-of select='$filename'/>
238 <!-- rnd:handle-image-data receives the base64-encoded data and a filename
239 for the physical file to which the data should be written.
240 Since XSLT cannot natively handle binary data, this implementation
241 just writes the undecoded data to the nominated file.
242 A real application would decode the data into a binary representation.
244 <xsl:template name='rnd:handle-image-data'>
245 <xsl:param name='filename'/>
246 <xsl:param name='data'/>
248 <xsl:if test='element-available("exsl:document")'>
249 <exsl:document href='{$filename}.b64' method='text'>
250 <xsl:value-of select='w:pict/w:binData'/>
255 <xsl:template match='w:hlink'>
256 <dbk:link xlink:href='{@w:dest}'>
257 <xsl:apply-templates/>
261 <!-- Soft returns don't really have an equivalent in DocBook,
262 - except in literal line environments.
264 <xsl:template match='w:br'>
265 <xsl:text>
</xsl:text>
268 <xsl:template match='w:tbl'>
269 <xsl:variable name='tbl.style'
270 select='key("style", w:tblPr/w:tblStyle/@w:val) | .'/>
272 <xsl:variable name='border.top'>
274 <xsl:when test='$tbl.style/w:tblPr/w:tblBorders/w:top[not(@w:val = "nil" or @w:val = "none")]'>1</xsl:when>
275 <xsl:when test='$tbl.style/w:tblPr/w:tblBorders/w:top[@w:val = "nil" or @w:val = "none"]'>0</xsl:when>
276 <xsl:when test='w:tr[1]/w:tc[w:tcPr/w:tcBorders/w:top[not(@w:val = "nil" or @w:val = "none")]]'>1</xsl:when>
277 <xsl:otherwise>0</xsl:otherwise>
280 <xsl:variable name='border.bottom'>
282 <xsl:when test='$tbl.style/w:tblPr/w:tblBorders/w:bottom[not(@w:val = "nil" or @w:val = "none")]'>1</xsl:when>
283 <xsl:when test='$tbl.style/w:tblPr/w:tblBorders/w:bottom[@w:val = "nil" or @w:val = "none"]'>0</xsl:when>
284 <xsl:when test='w:tr[1]/w:tc[w:tcPr/w:tcBorders/w:bottom[not(@w:val = "nil" or @w:val = "none")]]'>1</xsl:when>
285 <xsl:otherwise>0</xsl:otherwise>
288 <xsl:variable name='border.left'>
290 <xsl:when test='$tbl.style/w:tblPr/w:tblBorders/w:left[not(@w:val = "nil" or @w:val = "none")]'>1</xsl:when>
291 <xsl:when test='$tbl.style/w:tblPr/w:tblBorders/w:left[@w:val = "nil" or @w:val = "none"]'>0</xsl:when>
292 <xsl:when test='w:tr[1]/w:tc[w:tcPr/w:tcBorders/w:left[not(@w:val = "nil" or @w:val = "none")]]'>1</xsl:when>
293 <xsl:otherwise>0</xsl:otherwise>
296 <xsl:variable name='border.right'>
298 <xsl:when test='$tbl.style/w:tblPr/w:tblBorders/w:right[not(@w:val = "nil" or @w:val = "none")]'>1</xsl:when>
299 <xsl:when test='$tbl.style/w:tblPr/w:tblBorders/w:right[@w:val = "nil" or @w:val = "none"]'>0</xsl:when>
300 <xsl:when test='w:tr[1]/w:tc[w:tcPr/w:tcBorders/w:rightt[not(@w:val = "nil" or @w:val = "none")]]'>1</xsl:when>
301 <xsl:otherwise>0</xsl:otherwise>
307 <xsl:when test='$border.top = "1" and $border.bottom = "1" and
308 $border.left = "1" and $border.right = "1"'>
309 <xsl:attribute name='frame'>all</xsl:attribute>
311 <xsl:when test='$border.top = "1" and $border.bottom = "1"'>
312 <xsl:attribute name='frame'>topbot</xsl:attribute>
314 <xsl:when test='$border.left = "1" and $border.right = "1"'>
315 <xsl:attribute name='frame'>sides</xsl:attribute>
317 <xsl:when test='$border.top = "1"'>
318 <xsl:attribute name='frame'>top</xsl:attribute>
320 <xsl:when test='$border.bottom = "1"'>
321 <xsl:attribute name='frame'>bottom</xsl:attribute>
325 <!-- TODO: analyse column widths -->
328 <xsl:apply-templates select='w:tblGrid'/>
330 <xsl:when test='$tbl.style/w:tblStylePr[@w:type = "firstRow"]/w:trPr/w:tblHeader'>
332 <xsl:apply-templates select='w:tr[1]'/>
335 <xsl:apply-templates select='w:tr[position() != 1]'/>
340 <xsl:apply-templates select='w:tr'/>
347 <xsl:template match='w:tblPr'/>
348 <xsl:template match='w:tblGrid/w:gridCol'>
349 <dbk:colspec colwidth='{@w:w}*'
350 colname='column-{count(preceding-sibling::w:gridCol) + 1}'/>
352 <xsl:template match='w:tr'>
354 <xsl:apply-templates/>
357 <xsl:template match='w:tc'>
358 <xsl:variable name='tbl.style'
359 select='ancestor::w:tbl[1] |
360 key("style", ancestor::w:tbl[1]/w:tblPr/w:tblStyle/@w:val)'/>
363 <xsl:if test='$tbl.style/w:tblPr/w:tblBorders/w:insideH[not(@w:val = "nil" or @w:val = "none")] |
364 w:tcPr/w:tcBorders/w:bottom[not(@w:val = "nil" or @w:val = "none")]'>
365 <xsl:attribute name='rowsep'>1</xsl:attribute>
367 <xsl:if test='$tbl.style/w:tblPr/w:tblBorders/w:insideV[not(@w:val = "nil" or @w:val = "none")] |
368 w:tcPr/w:tcBorders/w:right[not(@w:val = "nil" or @w:val = "none")]'>
369 <xsl:attribute name='colsep'>1</xsl:attribute>
372 <xsl:variable name='this.colnum'
373 select='count(preceding-sibling::w:tc) + 1 +
374 sum(preceding-sibling::w:tc/w:tcPr/w:gridSpan/@w:val) -
375 count(preceding-sibling::w:tc/w:tcPr/w:gridSpan[@w:val])'/>
377 <xsl:if test='w:tcPr/w:gridSpan[@w:val > 1]'>
378 <xsl:attribute name='namest'>
379 <xsl:text>column-</xsl:text>
380 <xsl:value-of select='$this.colnum'/>
382 <xsl:attribute name='nameend'>
383 <xsl:text>column-</xsl:text>
384 <xsl:value-of select='$this.colnum + w:tcPr/w:gridSpan/@w:val - 1'/>
388 <xsl:if test='w:tcPr/w:vmerge[@w:val = "restart"]'>
389 <xsl:attribute name='morerows'>
390 <xsl:call-template name='rnd:count-rowspan'>
391 <xsl:with-param name='row' select='../following-sibling::w:tr[1]'/>
392 <xsl:with-param name='colnum' select='$this.colnum'/>
397 <xsl:apply-templates/>
401 <xsl:template match='w:pStyle |
407 <xsl:template name='rnd:count-rowspan'>
408 <xsl:param name='row' select='/..'/>
409 <xsl:param name='colnum' select='0'/>
411 <xsl:variable name='cell'
412 select='$row/w:tc[count(preceding-sibling::w:tc) + 1 +
413 sum(preceding-sibling::w:tc/w:tcPr/w:gridSpan/@w:val) -
414 count(preceding-sibling::w:tc/w:tcPr/w:gridSpan[@w:val]) = $colnum]'/>
417 <xsl:when test='not($cell)'>
418 <xsl:text>0</xsl:text>
420 <xsl:when test='$cell/w:tcPr/w:vmerge[not(@w:val = "restart")]'>
421 <xsl:variable name='remainder'>
422 <xsl:call-template name='rnd:count-rowspan'>
423 <xsl:with-param name='row'
424 select='$row/following-sibling::w:tr[1]'/>
425 <xsl:with-param name='colnum' select='$colnum'/>
428 <xsl:value-of select='$remainder + 1'/>
430 <xsl:otherwise>0</xsl:otherwise>
434 <xsl:template match='w:hdr|w:ftr'/>
436 <xsl:template match='aml:annotation'>
438 <xsl:when test='@w:type = "Word.Deletion"'/>
440 <xsl:apply-templates/>