Bump to docbook-xsl-stylesheets 1.79.2
[platform/upstream/docbook-xsl-stylesheets.git] / roundtrip / wordml2normalise.xsl
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'>
18
19   <xsl:import href='normalise-common.xsl'/>
20
21   <xsl:output method='xml' indent="yes"/>
22
23   <!-- ********************************************************************
24
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.
28
29        ******************************************************************** -->
30
31   <xsl:strip-space elements='*'/>
32   <xsl:preserve-space elements='w:t'/>
33
34   <xsl:key name='style'
35     match='w:style'
36     use='@w:styleId'/>
37
38   <xsl:template match="w:wordDocument">
39     <dbk:article>
40       <xsl:apply-templates select='w:body'/>
41     </dbk:article>
42   </xsl:template>
43
44   <xsl:template match='wx:borders |
45                        wx:margin-left'/>
46
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'/>
51       </xsl:call-template>
52     </xsl:variable>
53     <xsl:choose>
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)'/>
57
58       <!-- Eliminate paragraphs that have no content.
59            These are section or page breaks.
60         -->
61       <xsl:when test='not(w:r|w:hlink|w:tbl) and
62                       w:pPr/w:sectPr'/>
63
64       <xsl:otherwise>
65         <dbk:para>
66           <xsl:attribute name='rnd:style'>
67             <xsl:value-of select='$style'/>
68           </xsl:attribute>
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'/>
73             </xsl:attribute>
74           </xsl:if>
75
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'/>
80           </xsl:if>
81
82           <xsl:apply-templates/>
83         </dbk:para>
84       </xsl:otherwise>
85     </xsl:choose>
86   </xsl:template>
87
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'/>
92     </xsl:attribute>
93   </xsl:template>
94
95   <xsl:template match='w:r'>
96     <xsl:param name='do-vert-align' select='true()'/>
97
98     <xsl:variable name='role'>
99       <xsl:choose>
100         <xsl:when test='w:rPr/w:b and
101                         w:rPr/w:i'>
102           <xsl:text>bold-italic</xsl:text>
103         </xsl:when>
104         <xsl:when test='w:rPr/w:b'>
105           <xsl:text>bold</xsl:text>
106         </xsl:when>
107         <xsl:when test='w:rPr/w:i'>
108           <xsl:text>italic</xsl:text>
109         </xsl:when>
110         <xsl:when test='w:rPr/w:u'>
111           <xsl:text>underline</xsl:text>
112         </xsl:when>
113         <!-- TODO: add support for other styles -->
114       </xsl:choose>
115     </xsl:variable>
116     <xsl:variable name='style'>
117       <xsl:if test='w:rPr/w:rStyle'>
118         <xsl:value-of select='w:rPr/w:rStyle/@w:val'/>
119       </xsl:if>
120     </xsl:variable>
121
122     <xsl:choose>
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'/>
129         </xsl:variable>
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.
132           -->
133         <xsl:variable name='target'>
134           <xsl:call-template name='rnd:image-target'>
135             <xsl:with-param name='filename' select='$filename'/>
136           </xsl:call-template>
137         </xsl:variable>
138
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'/>
142         </xsl:call-template>
143
144         <dbk:inlinemediaobject>
145           <dbk:imageobject>
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:"), ";"))'/>
150                 </xsl:attribute>
151                 <xsl:attribute name='depth'>
152                   <xsl:value-of select='normalize-space(substring-after(w:pict/v:shape/@style, "height:"))'/>
153                 </xsl:attribute>
154               </xsl:if>
155             </dbk:imagedata>
156           </dbk:imageobject>
157         </dbk:inlinemediaobject>
158       </xsl:when>
159       <xsl:when test='$do-vert-align and
160                       w:rPr/w:vertAlign/@w:val = "d:subscript"'>
161         <dbk:subscript>
162           <xsl:apply-templates select='.'>
163             <xsl:with-param name='do-vert-align' select='false()'/>
164           </xsl:apply-templates>
165         </dbk:subscript>
166       </xsl:when>
167       <xsl:when test='$do-vert-align and
168                       w:rPr/w:vertAlign/@w:val = "d:superscript"'>
169         <dbk:superscript>
170           <xsl:apply-templates select='.'>
171             <xsl:with-param name='do-vert-align' select='false()'/>
172           </xsl:apply-templates>
173         </dbk:superscript>
174       </xsl:when>
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'>
180         <dbk:footnote>
181           <xsl:apply-templates select='w:footnote|w:endnote'/>
182         </dbk:footnote>
183       </xsl:when>
184       <xsl:when test='$role != "" or $style != ""'>
185         <dbk:emphasis>
186           <xsl:if test='$role != ""'>
187             <xsl:attribute name='role'>
188               <xsl:value-of select='$role'/>
189             </xsl:attribute>
190           </xsl:if>
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'/>
195               </xsl:call-template>
196             </xsl:attribute>
197           </xsl:if>
198           <xsl:apply-templates/>
199         </dbk:emphasis>
200       </xsl:when>
201       <xsl:otherwise>
202         <xsl:apply-templates/>
203       </xsl:otherwise>
204     </xsl:choose>
205   </xsl:template>
206
207   <!-- An application may wish to override these templates -->
208
209   <!-- rnd:image-filename determines the filename of the physical file
210        to which the image data should be written.
211     -->
212   <xsl:template name='rnd:image-filename'>
213     <xsl:param name='pict' select='w:pict'/>
214
215     <xsl:choose>
216       <xsl:when test='contains($pict/w:binData/@w:name, "wordml://")'>
217         <xsl:value-of select='substring-after($pict/w:binData/@w:name, "wordml://")'/>
218       </xsl:when>
219       <xsl:otherwise>
220         <xsl:text>image</xsl:text>
221         <xsl:value-of select='count($pict/preceding::w:pict) + 1'/>
222         <xsl:text>.jpg</xsl:text>
223       </xsl:otherwise>
224     </xsl:choose>
225   </xsl:template>
226
227   <!-- rnd:image-target determines the URL for the image data.
228        This may or may not be related to the physical filename.
229     -->
230   <xsl:template name='rnd:image-target'>
231     <xsl:param name='filename'/>
232     <xsl:param name='pict' select='w:pict'/>
233
234     <xsl:value-of select='$filename'/>
235   </xsl:template>
236
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.
242     -->
243   <xsl:template name='rnd:handle-image-data'>
244     <xsl:param name='filename'/>
245     <xsl:param name='data'/>
246
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'/>
250       </exsl:document>
251     </xsl:if>
252   </xsl:template>
253
254   <xsl:template match='w:hlink'>
255     <dbk:link xlink:href='{@w:dest}'>
256       <xsl:apply-templates/>
257     </dbk:link>
258   </xsl:template>
259
260   <!-- Soft returns don't really have an equivalent in DocBook,
261      - except in literal line environments.
262     -->
263   <xsl:template match='w:br'>
264     <xsl:text>&#xa;</xsl:text>
265   </xsl:template>
266
267   <xsl:template match='w:tbl'>
268     <xsl:variable name='tbl.style'
269       select='key("d:style", w:tblPr/w:tblStyle/@w:val) | .'/>
270
271     <xsl:variable name='border.top'>
272       <xsl:choose>
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>
277       </xsl:choose>
278     </xsl:variable>
279     <xsl:variable name='border.bottom'>
280       <xsl:choose>
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>
285       </xsl:choose>
286     </xsl:variable>
287     <xsl:variable name='border.left'>
288       <xsl:choose>
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>
293       </xsl:choose>
294     </xsl:variable>
295     <xsl:variable name='border.right'>
296       <xsl:choose>
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>
301       </xsl:choose>
302     </xsl:variable>
303
304     <dbk:informaltable>
305       <xsl:choose>
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>
309         </xsl:when>
310         <xsl:when test='$border.top = "1" and $border.bottom = "1"'>
311           <xsl:attribute name='frame'>topbot</xsl:attribute>
312         </xsl:when>
313         <xsl:when test='$border.left = "1" and $border.right = "1"'>
314           <xsl:attribute name='frame'>sides</xsl:attribute>
315         </xsl:when>
316         <xsl:when test='$border.top = "1"'>
317           <xsl:attribute name='frame'>top</xsl:attribute>
318         </xsl:when>
319         <xsl:when test='$border.bottom = "1"'>
320           <xsl:attribute name='frame'>bottom</xsl:attribute>
321         </xsl:when>
322       </xsl:choose>
323
324       <!-- TODO: analyse column widths -->
325
326       <dbk:tgroup>
327         <xsl:apply-templates select='w:tblGrid'/>
328         <xsl:choose>
329           <xsl:when test='$tbl.style/w:tblStylePr[@w:type = "firstRow"]/w:trPr/w:tblHeader'>
330             <dbk:thead>
331               <xsl:apply-templates select='w:tr[1]'/>
332             </dbk:thead>
333             <dbk:tbody>
334               <xsl:apply-templates select='w:tr[position() != 1]'/>
335             </dbk:tbody>
336           </xsl:when>
337           <xsl:otherwise>
338             <dbk:tbody>
339               <xsl:apply-templates select='w:tr'/>
340             </dbk:tbody>
341           </xsl:otherwise>
342         </xsl:choose>
343       </dbk:tgroup>
344     </dbk:informaltable>
345   </xsl:template>
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}'/>
350   </xsl:template>
351   <xsl:template match='w:tr'>
352     <dbk:row>
353       <xsl:apply-templates/>
354     </dbk:row>
355   </xsl:template>
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)'/>
360
361     <dbk:entry>
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>
365       </xsl:if>
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>
369       </xsl:if>
370
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])'/>
375
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'/>
380         </xsl:attribute>
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'/>
384         </xsl:attribute>
385       </xsl:if>
386
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'/>
392           </xsl:call-template>
393         </xsl:attribute>
394       </xsl:if>
395
396       <xsl:apply-templates/>
397     </dbk:entry>
398   </xsl:template>
399
400   <xsl:template match='w:pStyle |
401                        w:rStyle |
402                        w:proofErr |
403                        w:fldData |
404                        w:instrText'/>
405
406   <xsl:template name='rnd:count-rowspan'>
407     <xsl:param name='row' select='/..'/>
408     <xsl:param name='colnum' select='0'/>
409
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]'/>
414
415     <xsl:choose>
416       <xsl:when test='not($cell)'>
417         <xsl:text>0</xsl:text>
418       </xsl:when>
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'/>
425           </xsl:call-template>
426         </xsl:variable>
427         <xsl:value-of select='$remainder + 1'/>
428       </xsl:when>
429       <xsl:otherwise>0</xsl:otherwise>
430     </xsl:choose>
431   </xsl:template>
432
433   <xsl:template match='w:hdr|w:ftr'/>
434
435   <xsl:template match='aml:annotation'>
436     <xsl:choose>
437       <xsl:when test='@w:type = "Word.Deletion"'/>
438       <xsl:otherwise>
439         <xsl:apply-templates/>
440       </xsl:otherwise>
441     </xsl:choose>
442   </xsl:template>
443
444 </xsl:stylesheet>