1 <xsl:stylesheet version="1.0"
2 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
3 xmlns:d="http://docbook.org/ns/docbook"
4 xmlns:w="http://schemas.microsoft.com/office/word/2003/wordml"
5 xmlns:v="urn:schemas-microsoft-com:vml"
6 xmlns:w10="urn:schemas-microsoft-com:office:word"
7 xmlns:sl="http://schemas.microsoft.com/schemaLibrary/2003/core"
8 xmlns:aml="http://schemas.microsoft.com/aml/2001/core"
9 xmlns:wx="http://schemas.microsoft.com/office/word/2003/auxHint"
10 xmlns:o="urn:schemas-microsoft-com:office:office"
11 xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"
12 xmlns:dbk='http://docbook.org/ns/docbook'
13 xmlns:rnd='http://docbook.org/ns/docbook/roundtrip'
14 xmlns:xlink='http://www.w3.org/1999/xlink'
15 xmlns:exsl='http://exslt.org/common'
16 exclude-result-prefixes='w v w10 sl aml wx o dt'
17 extension-element-prefixes='exsl'>
19 <xsl:import href='normalise-common.xsl'/>
21 <xsl:output method='xml' indent="yes"/>
23 <!-- ********************************************************************
25 This file is part of the XSL DocBook Stylesheet distribution.
26 See ../README or http://nwalsh.com/docbook/xsl/ for copyright
27 and other information.
29 ******************************************************************** -->
31 <xsl:strip-space elements='*'/>
32 <xsl:preserve-space elements='w:t'/>
38 <xsl:template match="w:wordDocument">
40 <xsl:apply-templates select='w:body'/>
44 <xsl:template match='wx:borders |
47 <xsl:template match='w:p'>
48 <xsl:variable name='style'>
49 <xsl:call-template name='rnd:map-paragraph-style'>
50 <xsl:with-param name='style' select='w:pPr/w:pStyle/@w:val'/>
54 <xsl:when test='aml:annotation[@w:type = "Word.Deletion"] and
55 not(aml:annotation[@w:type != "Word.Deletion"]) and
56 count(*) = count(aml:annotation|w:pPr)'/>
58 <!-- Eliminate paragraphs that have no content.
59 These are section or page breaks.
61 <xsl:when test='not(w:r|w:hlink|w:tbl) and
66 <xsl:attribute name='rnd:style'>
67 <xsl:value-of select='$style'/>
69 <xsl:if test='w:pPr/w:pStyle/@w:val and
70 $style != w:pPr/w:pStyle/@w:val'>
71 <xsl:attribute name='rnd:original-style'>
72 <xsl:value-of select='w:pPr/w:pStyle/@w:val'/>
76 <xsl:if test='w:r[1][w:rPr/w:rStyle/@w:val = "d:attributes"] and
77 w:r[2][w:rPr/w:rStyle/@w:val = "CommentReference"]'>
78 <xsl:apply-templates select='w:r[2]//w:r[w:rPr/w:rStyle/@w:val = "attribute-name"]'
79 mode='rnd:attributes'/>
82 <xsl:apply-templates/>
88 <xsl:template match='*' mode='rnd:attributes'>
89 <xsl:attribute name='{w:t}'>
90 <xsl:apply-templates select='following-sibling::w:r[w:rPr/w:rStyle/@w:val = "attribute-value"][1]'
91 mode='rnd:attribute-value'/>
95 <xsl:template match='w:r'>
96 <xsl:param name='do-vert-align' select='true()'/>
98 <xsl:variable name='role'>
100 <xsl:when test='w:rPr/w:b and
102 <xsl:text>bold-italic</xsl:text>
104 <xsl:when test='w:rPr/w:b'>
105 <xsl:text>bold</xsl:text>
107 <xsl:when test='w:rPr/w:i'>
108 <xsl:text>italic</xsl:text>
110 <xsl:when test='w:rPr/w:u'>
111 <xsl:text>underline</xsl:text>
113 <!-- TODO: add support for other styles -->
116 <xsl:variable name='style'>
117 <xsl:if test='w:rPr/w:rStyle'>
118 <xsl:value-of select='w:rPr/w:rStyle/@w:val'/>
123 <xsl:when test='w:rPr/w:rStyle/@w:val = "d:attributes"'/>
124 <xsl:when test='w:rPr/w:rStyle/@w:val = "CommentReference"'/>
125 <xsl:when test='w:pict'>
126 <!-- "filename" is where the image data gets extracted to -->
127 <xsl:variable name='filename'>
128 <xsl:call-template name='rnd:image-filename'/>
130 <!-- "target" is the URL that will be the target of the imagedata hyperlink.
131 This may or may not be related to the physical filename.
133 <xsl:variable name='target'>
134 <xsl:call-template name='rnd:image-target'>
135 <xsl:with-param name='filename' select='$filename'/>
139 <xsl:call-template name='rnd:handle-image-data'>
140 <xsl:with-param name='filename' select='$filename'/>
141 <xsl:with-param name='data' select='w:pict/w:binData'/>
144 <dbk:inlinemediaobject>
146 <dbk:imagedata fileref='{$target}'>
147 <xsl:if test='w:pict/v:shape/@style'>
148 <xsl:attribute name='width'>
149 <xsl:value-of select='normalize-space(substring-before(substring-after(w:pict/v:shape/@style, "width:"), ";"))'/>
151 <xsl:attribute name='depth'>
152 <xsl:value-of select='normalize-space(substring-after(w:pict/v:shape/@style, "height:"))'/>
157 </dbk:inlinemediaobject>
159 <xsl:when test='$do-vert-align and
160 w:rPr/w:vertAlign/@w:val = "d:subscript"'>
162 <xsl:apply-templates select='.'>
163 <xsl:with-param name='do-vert-align' select='false()'/>
164 </xsl:apply-templates>
167 <xsl:when test='$do-vert-align and
168 w:rPr/w:vertAlign/@w:val = "d:superscript"'>
170 <xsl:apply-templates select='.'>
171 <xsl:with-param name='do-vert-align' select='false()'/>
172 </xsl:apply-templates>
175 <xsl:when test='w:endnoteRef and
176 parent::w:p/parent::w:endnote and
177 count(w:rPr|w:endnoteRef) = count(*)'/>
178 <xsl:when test='w:footnoteRef'/> <!-- is a label supplied? -->
179 <xsl:when test='w:footnote|w:endnote'>
181 <xsl:apply-templates select='w:footnote|w:endnote'/>
184 <xsl:when test='$role != "" or $style != ""'>
186 <xsl:if test='$role != ""'>
187 <xsl:attribute name='role'>
188 <xsl:value-of select='$role'/>
191 <xsl:if test='$style != ""'>
192 <xsl:attribute name='rnd:style'>
193 <xsl:call-template name='rnd:map-character-style'>
194 <xsl:with-param name='style' select='$style'/>
198 <xsl:apply-templates/>
202 <xsl:apply-templates/>
207 <!-- An application may wish to override these templates -->
209 <!-- rnd:image-filename determines the filename of the physical file
210 to which the image data should be written.
212 <xsl:template name='rnd:image-filename'>
213 <xsl:param name='pict' select='w:pict'/>
216 <xsl:when test='contains($pict/w:binData/@w:name, "wordml://")'>
217 <xsl:value-of select='substring-after($pict/w:binData/@w:name, "wordml://")'/>
220 <xsl:text>image</xsl:text>
221 <xsl:value-of select='count($pict/preceding::w:pict) + 1'/>
222 <xsl:text>.jpg</xsl:text>
227 <!-- rnd:image-target determines the URL for the image data.
228 This may or may not be related to the physical filename.
230 <xsl:template name='rnd:image-target'>
231 <xsl:param name='filename'/>
232 <xsl:param name='pict' select='w:pict'/>
234 <xsl:value-of select='$filename'/>
237 <!-- rnd:handle-image-data receives the base64-encoded data and a filename
238 for the physical file to which the data should be written.
239 Since XSLT cannot natively handle binary data, this implementation
240 just writes the undecoded data to the nominated file.
241 A real application would decode the data into a binary representation.
243 <xsl:template name='rnd:handle-image-data'>
244 <xsl:param name='filename'/>
245 <xsl:param name='data'/>
247 <xsl:if test='element-available("exsl:document")'>
248 <exsl:document href='{$filename}.b64' method='text'>
249 <xsl:value-of select='w:pict/w:binData'/>
254 <xsl:template match='w:hlink'>
255 <dbk:link xlink:href='{@w:dest}'>
256 <xsl:apply-templates/>
260 <!-- Soft returns don't really have an equivalent in DocBook,
261 - except in literal line environments.
263 <xsl:template match='w:br'>
264 <xsl:text>
</xsl:text>
267 <xsl:template match='w:tbl'>
268 <xsl:variable name='tbl.style'
269 select='key("d:style", w:tblPr/w:tblStyle/@w:val) | .'/>
271 <xsl:variable name='border.top'>
273 <xsl:when test='$tbl.style/w:tblPr/w:tblBorders/w:top[not(@w:val = "d:nil" or @w:val = "d:none")]'>1</xsl:when>
274 <xsl:when test='$tbl.style/w:tblPr/w:tblBorders/w:top[@w:val = "d:nil" or @w:val = "d:none"]'>0</xsl:when>
275 <xsl:when test='w:tr[1]/w:tc[w:tcPr/w:tcBorders/w:top[not(@w:val = "d:nil" or @w:val = "d:none")]]'>1</xsl:when>
276 <xsl:otherwise>0</xsl:otherwise>
279 <xsl:variable name='border.bottom'>
281 <xsl:when test='$tbl.style/w:tblPr/w:tblBorders/w:bottom[not(@w:val = "d:nil" or @w:val = "d:none")]'>1</xsl:when>
282 <xsl:when test='$tbl.style/w:tblPr/w:tblBorders/w:bottom[@w:val = "d:nil" or @w:val = "d:none"]'>0</xsl:when>
283 <xsl:when test='w:tr[1]/w:tc[w:tcPr/w:tcBorders/w:bottom[not(@w:val = "d:nil" or @w:val = "d:none")]]'>1</xsl:when>
284 <xsl:otherwise>0</xsl:otherwise>
287 <xsl:variable name='border.left'>
289 <xsl:when test='$tbl.style/w:tblPr/w:tblBorders/w:left[not(@w:val = "d:nil" or @w:val = "d:none")]'>1</xsl:when>
290 <xsl:when test='$tbl.style/w:tblPr/w:tblBorders/w:left[@w:val = "d:nil" or @w:val = "d:none"]'>0</xsl:when>
291 <xsl:when test='w:tr[1]/w:tc[w:tcPr/w:tcBorders/w:left[not(@w:val = "d:nil" or @w:val = "d:none")]]'>1</xsl:when>
292 <xsl:otherwise>0</xsl:otherwise>
295 <xsl:variable name='border.right'>
297 <xsl:when test='$tbl.style/w:tblPr/w:tblBorders/w:right[not(@w:val = "d:nil" or @w:val = "d:none")]'>1</xsl:when>
298 <xsl:when test='$tbl.style/w:tblPr/w:tblBorders/w:right[@w:val = "d:nil" or @w:val = "d:none"]'>0</xsl:when>
299 <xsl:when test='w:tr[1]/w:tc[w:tcPr/w:tcBorders/w:rightt[not(@w:val = "d:nil" or @w:val = "d:none")]]'>1</xsl:when>
300 <xsl:otherwise>0</xsl:otherwise>
306 <xsl:when test='$border.top = "1" and $border.bottom = "1" and
307 $border.left = "1" and $border.right = "1"'>
308 <xsl:attribute name='frame'>all</xsl:attribute>
310 <xsl:when test='$border.top = "1" and $border.bottom = "1"'>
311 <xsl:attribute name='frame'>topbot</xsl:attribute>
313 <xsl:when test='$border.left = "1" and $border.right = "1"'>
314 <xsl:attribute name='frame'>sides</xsl:attribute>
316 <xsl:when test='$border.top = "1"'>
317 <xsl:attribute name='frame'>top</xsl:attribute>
319 <xsl:when test='$border.bottom = "1"'>
320 <xsl:attribute name='frame'>bottom</xsl:attribute>
324 <!-- TODO: analyse column widths -->
327 <xsl:apply-templates select='w:tblGrid'/>
329 <xsl:when test='$tbl.style/w:tblStylePr[@w:type = "firstRow"]/w:trPr/w:tblHeader'>
331 <xsl:apply-templates select='w:tr[1]'/>
334 <xsl:apply-templates select='w:tr[position() != 1]'/>
339 <xsl:apply-templates select='w:tr'/>
346 <xsl:template match='w:tblPr'/>
347 <xsl:template match='w:tblGrid/w:gridCol'>
348 <dbk:colspec colwidth='{@w:w}*'
349 colname='column-{count(preceding-sibling::w:gridCol) + 1}'/>
351 <xsl:template match='w:tr'>
353 <xsl:apply-templates/>
356 <xsl:template match='w:tc'>
357 <xsl:variable name='tbl.style'
358 select='ancestor::w:tbl[1] |
359 key("d:style", ancestor::w:tbl[1]/w:tblPr/w:tblStyle/@w:val)'/>
362 <xsl:if test='$tbl.style/w:tblPr/w:tblBorders/w:insideH[not(@w:val = "d:nil" or @w:val = "d:none")] |
363 w:tcPr/w:tcBorders/w:bottom[not(@w:val = "d:nil" or @w:val = "d:none")]'>
364 <xsl:attribute name='rowsep'>1</xsl:attribute>
366 <xsl:if test='$tbl.style/w:tblPr/w:tblBorders/w:insideV[not(@w:val = "d:nil" or @w:val = "d:none")] |
367 w:tcPr/w:tcBorders/w:right[not(@w:val = "d:nil" or @w:val = "d:none")]'>
368 <xsl:attribute name='colsep'>1</xsl:attribute>
371 <xsl:variable name='this.colnum'
372 select='count(preceding-sibling::w:tc) + 1 +
373 sum(preceding-sibling::w:tc/w:tcPr/w:gridSpan/@w:val) -
374 count(preceding-sibling::w:tc/w:tcPr/w:gridSpan[@w:val])'/>
376 <xsl:if test='w:tcPr/w:gridSpan[@w:val > 1]'>
377 <xsl:attribute name='namest'>
378 <xsl:text>column-</xsl:text>
379 <xsl:value-of select='$this.colnum'/>
381 <xsl:attribute name='nameend'>
382 <xsl:text>column-</xsl:text>
383 <xsl:value-of select='$this.colnum + w:tcPr/w:gridSpan/@w:val - 1'/>
387 <xsl:if test='w:tcPr/w:vmerge[@w:val = "d:restart"]'>
388 <xsl:attribute name='morerows'>
389 <xsl:call-template name='rnd:count-rowspan'>
390 <xsl:with-param name='row' select='../following-sibling::w:tr[1]'/>
391 <xsl:with-param name='colnum' select='$this.colnum'/>
396 <xsl:apply-templates/>
400 <xsl:template match='w:pStyle |
406 <xsl:template name='rnd:count-rowspan'>
407 <xsl:param name='row' select='/..'/>
408 <xsl:param name='colnum' select='0'/>
410 <xsl:variable name='cell'
411 select='$row/w:tc[count(preceding-sibling::w:tc) + 1 +
412 sum(preceding-sibling::w:tc/w:tcPr/w:gridSpan/@w:val) -
413 count(preceding-sibling::w:tc/w:tcPr/w:gridSpan[@w:val]) = $colnum]'/>
416 <xsl:when test='not($cell)'>
417 <xsl:text>0</xsl:text>
419 <xsl:when test='$cell/w:tcPr/w:vmerge[not(@w:val = "d:restart")]'>
420 <xsl:variable name='remainder'>
421 <xsl:call-template name='rnd:count-rowspan'>
422 <xsl:with-param name='row'
423 select='$row/following-sibling::w:tr[1]'/>
424 <xsl:with-param name='colnum' select='$colnum'/>
427 <xsl:value-of select='$remainder + 1'/>
429 <xsl:otherwise>0</xsl:otherwise>
433 <xsl:template match='w:hdr|w:ftr'/>
435 <xsl:template match='aml:annotation'>
437 <xsl:when test='@w:type = "Word.Deletion"'/>
439 <xsl:apply-templates/>