htmltoword 0.4.1 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3e11d37752ec6cbe7fe7e2efb735a86e9a070767
4
- data.tar.gz: 3a56eb81b62cc9a2c6e3bf589b53d2362ee30627
3
+ metadata.gz: 2892b27fc27f383e30166ab8cee5a1732f35490d
4
+ data.tar.gz: 14274353b1ff25283ac773cfcf1063a3c8ddafa9
5
5
  SHA512:
6
- metadata.gz: a804913b7fa5611a226149d615f26ad54d85c0bf15813c9dae3f4e8e5d6008617866befa9818d0e26d327d5f3879ff77ed54dca9eff6ce0d0ed23fb9bdfb1803
7
- data.tar.gz: a29c50d03ae0132a382166f5cb77812dbaaaf1e70e00b70830aa084fbc92b76d9a1b964e182bbb756dc55028cb9f27a103964585919fa312836bb8349d048433
6
+ metadata.gz: cfb540c3101ad30c07476017a7b08c2c3bb956054ba8a247fc6bf169f9fcddcf6e4cca46a1130f8a7123c70ca7ea729e1b17178c83b794c1e555205106f6433d
7
+ data.tar.gz: 4a35e7b0d637210acec1e10982dab20fe140190004bcfce4661542956de45acb83831e596f827d43a9498cca6a519d6da1564fdb872a50ea909534093766950d
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Ruby Html to word Gem [![Code Climate](https://codeclimate.com/github/nickfrandsen/htmltoword.png)](https://codeclimate.com/github/nickfrandsen/htmltoword) [![Build Status](https://travis-ci.org/nickfrandsen/htmltoword.png)](https://travis-ci.org/nickfrandsen/htmltoword)
1
+ # Ruby Html to word Gem
2
2
 
3
3
  This simple gem allows you to create MS Word docx documents from simple html documents. This makes it easy to create dynamic reports and forms that can be downloaded by your users as simple MS Word docx files.
4
4
 
data/bin/htmltoword ADDED
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env ruby
2
+ require 'methadone'
3
+ require 'rmultimarkdown'
4
+ require_relative '../lib/htmltoword'
5
+
6
+ include Methadone::Main
7
+ include Methadone::CLILogging
8
+
9
+ main do |input, output|
10
+ puts "Converting #{input} to #{output}" if options[:verbose]
11
+ markup = File.read input
12
+ if options[:format] == 'markdown'
13
+ markup = markdown2html(markup)
14
+ end
15
+ File.open(output, "w") do |out|
16
+ out << Htmltoword::Document.create(markup, options[:template_name], options[:extras])
17
+ end
18
+ puts "Done" if options[:verbose]
19
+ end
20
+
21
+ def markdown2html(text)
22
+ MultiMarkdown.new(text.to_s).to_html
23
+ end
24
+
25
+ version Htmltoword::VERSION
26
+ description 'Convert simple html input (or markdown) to MS Word (docx)'
27
+ arg :input, :required
28
+ arg :output, :required
29
+
30
+ on('--verbose', '-v', 'Be verbose')
31
+ on('--extras', '-e', 'Use extra formatting features')
32
+ on('--template', '-t', 'Use custom word base template (.docx file)')
33
+ on('-f FORMAT', '--format', 'Format', /markdown|html/)
34
+
35
+ # options['ip-address'] = '127.0.0.1'
36
+ # on('-i IP_ADDRESS', '--ip-address', 'IP Address', /^\d+\.\d+\.\d+\.\d+$/)
37
+
38
+ go!
@@ -26,6 +26,14 @@ module Htmltoword
26
26
  'word/document.xml'
27
27
  end
28
28
 
29
+ def numbering_xml_file
30
+ 'word/numbering.xml'
31
+ end
32
+
33
+ def numbering_xslt
34
+ File.join(Htmltoword.config.default_xslt_path, 'numbering.xslt')
35
+ end
36
+
29
37
  def xslt_template(extras = false)
30
38
  File.join(Htmltoword.config.default_xslt_path, (extras ? 'htmltoword.xslt' : 'base.xslt'))
31
39
  end
@@ -44,9 +52,11 @@ module Htmltoword
44
52
  buffer = Zip::OutputStream.write_buffer do |out|
45
53
  template_zip.each do |entry|
46
54
  out.put_next_entry entry.name
47
- if @replaceable_files[entry.name]
48
- source = entry.get_input_stream.read.sub(/(<w:body>)(.*?)(<w:sectPr)/, "\\1#{@replaceable_files[entry.name]}\\3")
55
+ if @replaceable_files[entry.name] && entry.name == Document.doc_xml_file
56
+ source = entry.get_input_stream.read.sub(/(<w:body>)((.|\n)*?)(<w:sectPr)/, "\\1#{@replaceable_files[entry.name]}\\4")
49
57
  out.write(source)
58
+ elsif @replaceable_files[entry.name]
59
+ out.write(@replaceable_files[entry.name])
50
60
  else
51
61
  out.write(template_zip.read(entry.name))
52
62
  end
@@ -59,10 +69,17 @@ module Htmltoword
59
69
  def replace_file(html, file_name = Document.doc_xml_file, extras = false)
60
70
  html = html.presence || '<body></body>'
61
71
  source = Nokogiri::HTML(html.gsub(/>\s+</, '><'))
62
- template = Document.xslt_template(extras)
63
- xslt = Nokogiri::XSLT(File.open(template))
64
- source = xslt.apply_to(source).gsub(/\s*xmlns:(\w+)="(.*?)\s*"/,'')
65
- @replaceable_files[file_name] = source
72
+ transform_and_replace(source, Document.numbering_xslt, Document.numbering_xml_file)
73
+ transform_and_replace(source, Document.xslt_template(extras), file_name, extras)
74
+ end
75
+
76
+ private
77
+
78
+ def transform_and_replace source, xslt, file, remove_ns = false
79
+ xslt = Nokogiri::XSLT(File.open(xslt))
80
+ content = xslt.apply_to(source)
81
+ content.gsub!(/\s*xmlns:(\w+)="(.*?)\s*"/,'') if remove_ns
82
+ @replaceable_files[file] = content
66
83
  end
67
84
  end
68
85
  end
Binary file
@@ -1,3 +1,3 @@
1
1
  module Htmltoword
2
- VERSION = "0.4.1"
2
+ VERSION = "0.4.2"
3
3
  end
@@ -16,6 +16,8 @@
16
16
  exclude-result-prefixes="java msxsl ext w o v WX aml w10"
17
17
  extension-element-prefixes="func">
18
18
  <xsl:output method="xml" encoding="utf-8" omit-xml-declaration="yes" indent="yes" />
19
+ <xsl:include href="./functions.xslt"/>
20
+ <xsl:include href="./tables.xslt"/>
19
21
 
20
22
  <xsl:template match="/">
21
23
  <xsl:apply-templates />
@@ -47,7 +49,20 @@
47
49
  </w:p>
48
50
  </xsl:template>
49
51
 
50
- <xsl:template match="div[not(ancestor::td) and not(ancestor::th) and not(ancestor::p) and not(descendant::div) and not(descendant::p) and not(descendant::h1) and not(descendant::h2) and not(descendant::h3) and not(descendant::h4) and not(descendant::h5) and not(descendant::h6) and not(descendant::table) and not(descendant::li)]">
52
+ <xsl:template match="br[not(ancestor::p) and not(ancestor::div) and not(name(..)='td') and not(name(..)='li') or preceding-sibling::div or following-sibling::div
53
+ or preceding-sibling::p or following-sibling::p]">
54
+ <w:p>
55
+ <w:r></w:r>
56
+ </w:p>
57
+ </xsl:template>
58
+
59
+ <xsl:template match="br">
60
+ <w:r>
61
+ <w:br />
62
+ </w:r>
63
+ </xsl:template>
64
+
65
+ <xsl:template match="div[not(ancestor::li) and not(ancestor::td) and not(ancestor::th) and not(ancestor::p) and not(descendant::div) and not(descendant::p) and not(descendant::h1) and not(descendant::h2) and not(descendant::h3) and not(descendant::h4) and not(descendant::h5) and not(descendant::h6) and not(descendant::table) and not(descendant::li)]">
51
66
  <xsl:comment>Divs should create a p if nothing above them has and nothing below them will</xsl:comment>
52
67
  <w:p>
53
68
  <xsl:call-template name="text-alignment" />
@@ -72,19 +87,39 @@
72
87
  </w:p>
73
88
  </xsl:template>
74
89
 
75
- <xsl:template match="p">
90
+ <xsl:template match="p[not(ancestor::li)]">
76
91
  <w:p>
77
92
  <xsl:call-template name="text-alignment" />
78
93
  <xsl:apply-templates />
79
94
  </w:p>
80
95
  </xsl:template>
81
96
 
97
+ <xsl:template match="ol|ul">
98
+ <xsl:param name="local_level" select="0"/>
99
+ <xsl:param name="global_level" select="count(preceding::ol[not(ancestor::ol or ancestor::ul)]) + count(preceding::ul[not(ancestor::ol or ancestor::ul)]) + 1"/>
100
+ <xsl:apply-templates>
101
+ <xsl:with-param name="local_level" select="$local_level + 1" />
102
+ <xsl:with-param name="global_level" select="$global_level" />
103
+ </xsl:apply-templates>
104
+ </xsl:template>
105
+
82
106
  <xsl:template match="li">
107
+ <xsl:param name="local_level" />
108
+ <xsl:param name="global_level" />
83
109
  <w:p>
84
- <w:r>
85
- <w:t xml:space="preserve"><xsl:value-of select="."/></w:t>
86
- </w:r>
110
+ <w:pPr>
111
+ <w:pStyle w:val="ListParagraph"></w:pStyle>
112
+ <w:numPr>
113
+ <w:ilvl w:val="{$local_level - 1}"/>
114
+ <w:numId w:val="{$global_level}"/>
115
+ </w:numPr>
116
+ </w:pPr>
117
+ <xsl:apply-templates select="*[not(name()='ol' or name()='ul')]|text()"/>
87
118
  </w:p>
119
+ <xsl:apply-templates select="./ol|./ul">
120
+ <xsl:with-param name="local_level" select="$local_level" />
121
+ <xsl:with-param name="global_level" select="$global_level" />
122
+ </xsl:apply-templates>
88
123
  </xsl:template>
89
124
 
90
125
  <xsl:template match="span[not(ancestor::td) and (preceding-sibling::h1 or preceding-sibling::h2 or preceding-sibling::h3 or preceding-sibling::h4 or preceding-sibling::h5 or preceding-sibling::h6 or preceding-sibling::table or preceding-sibling::p or preceding-sibling::ol or preceding-sibling::ul or preceding-sibling::div or following-sibling::h1 or following-sibling::h2 or following-sibling::h3 or following-sibling::h4 or following-sibling::h5 or following-sibling::h6 or following-sibling::table or following-sibling::p or following-sibling::ol or following-sibling::ul or following-sibling::div)]
@@ -113,7 +148,7 @@
113
148
  </w:p>
114
149
  </xsl:template>
115
150
 
116
- <xsl:template match="text()[not(parent::td) and (preceding-sibling::h1 or preceding-sibling::h2 or preceding-sibling::h3 or preceding-sibling::h4 or preceding-sibling::h5 or preceding-sibling::h6 or preceding-sibling::table or preceding-sibling::p or preceding-sibling::ol or preceding-sibling::ul or preceding-sibling::div or following-sibling::h1 or following-sibling::h2 or following-sibling::h3 or following-sibling::h4 or following-sibling::h5 or following-sibling::h6 or following-sibling::table or following-sibling::p or following-sibling::ol or following-sibling::ul or following-sibling::div)]">
151
+ <xsl:template match="text()[not(parent::li) and not(parent::td) and (preceding-sibling::h1 or preceding-sibling::h2 or preceding-sibling::h3 or preceding-sibling::h4 or preceding-sibling::h5 or preceding-sibling::h6 or preceding-sibling::table or preceding-sibling::p or preceding-sibling::ol or preceding-sibling::ul or preceding-sibling::div or following-sibling::h1 or following-sibling::h2 or following-sibling::h3 or following-sibling::h4 or following-sibling::h5 or following-sibling::h6 or following-sibling::table or following-sibling::p or following-sibling::ol or following-sibling::ul or following-sibling::div)]">
117
152
  <xsl:comment>
118
153
  In the following situation:
119
154
 
@@ -176,121 +211,6 @@
176
211
 
177
212
  <xsl:template match="details" />
178
213
 
179
- <xsl:template name="tableborders">
180
- <xsl:variable name="border">
181
- <xsl:choose>
182
- <xsl:when test="contains(concat(' ', @class, ' '), ' table-bordered ')">6</xsl:when>
183
- <xsl:when test="not(@border)">0</xsl:when>
184
- <xsl:otherwise><xsl:value-of select="./@border * 6"/></xsl:otherwise>
185
- </xsl:choose>
186
- </xsl:variable>
187
- <xsl:variable name="bordertype">
188
- <xsl:choose>
189
- <xsl:when test="$border=0">none</xsl:when>
190
- <xsl:otherwise>single</xsl:otherwise>
191
- </xsl:choose>
192
- </xsl:variable>
193
- <w:tblBorders>
194
- <w:top w:val="{$bordertype}" w:sz="{$border}" w:space="0" w:color="auto"/>
195
- <w:left w:val="{$bordertype}" w:sz="{$border}" w:space="0" w:color="auto"/>
196
- <w:bottom w:val="{$bordertype}" w:sz="{$border}" w:space="0" w:color="auto"/>
197
- <w:right w:val="{$bordertype}" w:sz="{$border}" w:space="0" w:color="auto"/>
198
- <w:insideH w:val="{$bordertype}" w:sz="{$border}" w:space="0" w:color="auto"/>
199
- <w:insideV w:val="{$bordertype}" w:sz="{$border}" w:space="0" w:color="auto"/>
200
- </w:tblBorders>
201
- </xsl:template>
202
-
203
- <xsl:template match="table">
204
- <w:tbl>
205
- <w:tblPr>
206
- <w:tblStyle w:val="TableGrid"/>
207
- <xsl:call-template name="tableborders"/>
208
- <w:tblLook w:val="0600" w:firstRow="0" w:lastRow="0" w:firstColumn="0" w:lastColumn="0" w:noHBand="1" w:noVBand="1"/>
209
- </w:tblPr>
210
- <xsl:apply-templates />
211
- </w:tbl>
212
- </xsl:template>
213
-
214
- <xsl:template match="tbody">
215
- <xsl:apply-templates />
216
- </xsl:template>
217
-
218
- <xsl:template match="thead">
219
- <xsl:choose>
220
- <xsl:when test="count(./tr) = 0">
221
- <w:tr><xsl:apply-templates /></w:tr>
222
- </xsl:when>
223
- <xsl:otherwise>
224
- <xsl:apply-templates />
225
- </xsl:otherwise>
226
- </xsl:choose>
227
- </xsl:template>
228
-
229
- <xsl:template match="tr">
230
- <xsl:if test="string-length(.) > 0">
231
- <w:tr>
232
- <xsl:apply-templates />
233
- </w:tr>
234
- </xsl:if>
235
- </xsl:template>
236
-
237
- <xsl:template match="th">
238
- <w:tc>
239
- <w:p>
240
- <w:r>
241
- <w:rPr>
242
- <w:b />
243
- </w:rPr>
244
- <w:t xml:space="preserve"><xsl:value-of select="."/></w:t>
245
- </w:r>
246
- </w:p>
247
- </w:tc>
248
- </xsl:template>
249
-
250
- <xsl:template match="td">
251
- <w:tc>
252
- <xsl:call-template name="block">
253
- <xsl:with-param name="current" select="." />
254
- <xsl:with-param name="class" select="@class" />
255
- <xsl:with-param name="style" select="@style" />
256
- </xsl:call-template>
257
- </w:tc>
258
- </xsl:template>
259
-
260
- <xsl:template name="block">
261
- <xsl:param name="current" />
262
- <xsl:param name="class" />
263
- <xsl:param name="style" />
264
- <xsl:if test="count($current/*|$current/text()) = 0">
265
- <w:p/>
266
- </xsl:if>
267
- <xsl:for-each select="$current/*|$current/text()">
268
- <xsl:choose>
269
- <xsl:when test="name(.) = 'table'">
270
- <xsl:apply-templates select="." />
271
- <w:p/>
272
- </xsl:when>
273
- <xsl:when test="contains('|p|h1|h2|h3|h4|h5|h6|ul|ol|', concat('|', name(.), '|'))">
274
- <xsl:apply-templates select="." />
275
- </xsl:when>
276
- <xsl:when test="descendant::table|descendant::p|descendant::h1|descendant::h2|descendant::h3|descendant::h4|descendant::h5|descendant::h6|descendant::li">
277
- <xsl:call-template name="block">
278
- <xsl:with-param name="current" select="."/>
279
- </xsl:call-template>
280
- </xsl:when>
281
- <xsl:otherwise>
282
- <w:p>
283
- <xsl:call-template name="text-alignment">
284
- <xsl:with-param name="class" select="$class" />
285
- <xsl:with-param name="style" select="$style" />
286
- </xsl:call-template>
287
- <xsl:apply-templates select="." />
288
- </w:p>
289
- </xsl:otherwise>
290
- </xsl:choose>
291
- </xsl:for-each>
292
- </xsl:template>
293
-
294
214
  <xsl:template match="text()">
295
215
  <xsl:if test="string-length(.) > 0">
296
216
  <w:r>
@@ -16,134 +16,11 @@
16
16
  exclude-result-prefixes="java msxsl ext w o v WX aml w10"
17
17
  extension-element-prefixes="func">
18
18
 
19
- <!-- support function to return substring-before or everything -->
20
- <func:function name="func:substring-before-if-contains">
21
- <xsl:param name="arg"/>
22
- <xsl:param name="delim"/>
23
- <func:result>
24
- <xsl:choose>
25
- <xsl:when test="contains($arg, $delim)">
26
- <xsl:value-of select="substring-before($arg, $delim)"/>
27
- </xsl:when>
28
- <xsl:otherwise>
29
- <xsl:value-of select="$arg"/>
30
- </xsl:otherwise>
31
- </xsl:choose>
32
- </func:result>
33
- </func:function>
34
-
35
- <!-- Full width tables per default -->
36
- <xsl:template match="table">
37
- <w:tbl>
38
- <w:tblPr>
39
- <w:tblStyle w:val="TableGrid"/>
40
- <w:tblW w:w="5000" w:type="pct"/>
41
- <xsl:call-template name="tableborders"/>
42
- <w:tblLook w:val="0600" w:firstRow="0" w:lastRow="0" w:firstColumn="0" w:lastColumn="0" w:noHBand="1" w:noVBand="1"/>
43
- </w:tblPr>
44
- <xsl:apply-templates />
45
- </w:tbl>
46
- </xsl:template>
47
-
48
- <!-- Advanced cell transformation -->
49
- <xsl:template match="td|th">
50
- <w:tc>
51
- <w:tcPr>
52
- <xsl:if test="contains(@class, 'ms-border-')">
53
- <w:tcBorders>
54
- <xsl:for-each select="str:tokenize(@class, ' ')">
55
- <xsl:call-template name="define-border">
56
- <xsl:with-param name="class" select="." />
57
- </xsl:call-template>
58
- </xsl:for-each>
59
- </w:tcBorders>
60
- </xsl:if>
61
- <xsl:if test="contains(@class, 'ms-fill-')">
62
- <xsl:variable name="cell-bg" select="str:tokenize(substring-after(@class, 'ms-fill-'), ' ')[1]"/>
63
- <w:shd w:val="clear" w:color="auto" w:fill="{$cell-bg}" />
64
- </xsl:if>
65
- </w:tcPr>
66
- <xsl:call-template name="block">
67
- <xsl:with-param name="current" select="." />
68
- <xsl:with-param name="class" select="@class" />
69
- <xsl:with-param name="style" select="@style" />
70
- </xsl:call-template>
71
- </w:tc>
72
- </xsl:template>
73
-
74
19
  <!-- use block quotes for spacing (can be nested) -->
75
20
  <xsl:template match="blockquote">
76
21
  <w:p>
77
- <w:pPr>
78
- <w:spacing w:afterLines="200" />
79
- </w:pPr>
22
+ <w:r></w:r>
80
23
  </w:p>
81
24
  <xsl:apply-templates/>
82
25
  </xsl:template>
83
-
84
- <xsl:template match="ol/li">
85
- <w:p>
86
- <w:pPr>
87
- <w:pStyle w:val="ListParagraph"/>
88
- <w:numPr>
89
- <w:ilvl w:val="0"/>
90
- <w:numId w:val="1"/>
91
- </w:numPr>
92
- </w:pPr>
93
- <w:r>
94
- <w:t xml:space="preserve"><xsl:value-of select="."/></w:t>
95
- </w:r>
96
- </w:p>
97
- </xsl:template>
98
-
99
- <xsl:template match="ul/li">
100
- <w:p>
101
- <w:pPr>
102
- <w:pStyle w:val="ListParagraph"/>
103
- <w:numPr>
104
- <w:ilvl w:val="0"/>
105
- <w:numId w:val="10"/>
106
- </w:numPr>
107
- </w:pPr>
108
- <w:r>
109
- <w:t xml:space="preserve"><xsl:value-of select="."/></w:t>
110
- </w:r>
111
- </w:p>
112
- </xsl:template>
113
-
114
- <xsl:template match="ol">
115
- <xsl:apply-templates />
116
- </xsl:template>
117
-
118
- <xsl:template match="ul">
119
- <xsl:apply-templates />
120
- </xsl:template>
121
-
122
- <xsl:template name="define-border">
123
- <xsl:param name="class" />
124
- <xsl:if test="contains($class, 'ms-border-')">
125
- <xsl:variable name="border" select="substring-after($class, 'ms-border-')"/>
126
- <xsl:variable name="border-properties" select="str:tokenize($border, '-')"/>
127
- <xsl:variable name="border-location" select="$border-properties[1]" />
128
- <xsl:variable name="border-value" select="$border-properties[2]" />
129
- <xsl:variable name="border-color">
130
- <xsl:choose>
131
- <xsl:when test="string-length($border-properties[3]) > 0"><xsl:value-of select="$border-properties[3]"/></xsl:when>
132
- <xsl:otherwise>000000</xsl:otherwise>
133
- </xsl:choose>
134
- </xsl:variable>
135
- <xsl:variable name="border-size">
136
- <xsl:choose>
137
- <xsl:when test="string-length($border-properties[4]) > 0"><xsl:value-of select="$border-properties[4] * 6"/></xsl:when>
138
- <xsl:otherwise>6</xsl:otherwise>
139
- </xsl:choose>
140
- </xsl:variable>
141
- <xsl:element name="w:{$border-location}">
142
- <xsl:attribute name="w:val"><xsl:value-of select="$border-value" /></xsl:attribute>
143
- <xsl:attribute name="w:sz"><xsl:value-of select="$border-size" /></xsl:attribute>
144
- <xsl:attribute name="w:space">0</xsl:attribute>
145
- <xsl:attribute name="w:color"><xsl:value-of select="$border-color" /></xsl:attribute>
146
- </xsl:element>
147
- </xsl:if>
148
- </xsl:template>
149
26
  </xsl:stylesheet>
@@ -0,0 +1,34 @@
1
+ <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
2
+ xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
3
+ xmlns:o="urn:schemas-microsoft-com:office:office"
4
+ xmlns:v="urn:schemas-microsoft-com:vml"
5
+ xmlns:WX="http://schemas.microsoft.com/office/word/2003/auxHint"
6
+ xmlns:aml="http://schemas.microsoft.com/aml/2001/core"
7
+ xmlns:w10="urn:schemas-microsoft-com:office:word"
8
+ xmlns:pkg="http://schemas.microsoft.com/office/2006/xmlPackage"
9
+ xmlns:msxsl="urn:schemas-microsoft-com:xslt"
10
+ xmlns:ext="http://www.xmllab.net/wordml2html/ext"
11
+ xmlns:java="http://xml.apache.org/xalan/java"
12
+ xmlns:str="http://exslt.org/strings"
13
+ xmlns:func="http://exslt.org/functions"
14
+ xmlns:fn="http://www.w3.org/2005/xpath-functions"
15
+ version="1.0"
16
+ exclude-result-prefixes="java msxsl ext w o v WX aml w10"
17
+ extension-element-prefixes="func">
18
+
19
+ <!-- support function to return substring-before or everything -->
20
+ <func:function name="func:substring-before-if-contains">
21
+ <xsl:param name="arg"/>
22
+ <xsl:param name="delim"/>
23
+ <func:result>
24
+ <xsl:choose>
25
+ <xsl:when test="contains($arg, $delim)">
26
+ <xsl:value-of select="substring-before($arg, $delim)"/>
27
+ </xsl:when>
28
+ <xsl:otherwise>
29
+ <xsl:value-of select="$arg"/>
30
+ </xsl:otherwise>
31
+ </xsl:choose>
32
+ </func:result>
33
+ </func:function>
34
+ </xsl:stylesheet>
@@ -16,5 +16,6 @@
16
16
  exclude-result-prefixes="java msxsl ext w o v WX aml w10"
17
17
  extension-element-prefixes="func">
18
18
  <xsl:import href="./base.xslt"/>
19
- <xsl:import href="./extras.xslt"/>
19
+ <!--Extra templates and customizations-->
20
+ <xsl:include href="./extras.xslt"/>
20
21
  </xsl:stylesheet>
@@ -0,0 +1,194 @@
1
+ <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
2
+ xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
3
+ xmlns:o="urn:schemas-microsoft-com:office:office"
4
+ xmlns:v="urn:schemas-microsoft-com:vml"
5
+ xmlns:WX="http://schemas.microsoft.com/office/word/2003/auxHint"
6
+ xmlns:aml="http://schemas.microsoft.com/aml/2001/core"
7
+ xmlns:w10="urn:schemas-microsoft-com:office:word"
8
+ xmlns:pkg="http://schemas.microsoft.com/office/2006/xmlPackage"
9
+ xmlns:msxsl="urn:schemas-microsoft-com:xslt"
10
+ xmlns:ext="http://www.xmllab.net/wordml2html/ext"
11
+ xmlns:java="http://xml.apache.org/xalan/java"
12
+ xmlns:str="http://exslt.org/strings"
13
+ xmlns:func="http://exslt.org/functions"
14
+ xmlns:fn="http://www.w3.org/2005/xpath-functions"
15
+ version="1.0"
16
+ exclude-result-prefixes="java msxsl ext w o v WX aml w10"
17
+ extension-element-prefixes="func">
18
+ <xsl:output method="xml" encoding="utf-8" omit-xml-declaration="yes" indent="yes" />
19
+ <xsl:include href="./functions.xslt"/>
20
+
21
+ <func:function name="func:list-type">
22
+ <xsl:param name="tag_name"/>
23
+ <xsl:param name="style"/>
24
+ <xsl:param name="class"/>
25
+ <func:result>
26
+ <xsl:choose>
27
+ <xsl:when test="contains($style, 'list-style-type:') or string-length(normalize-space($class)) > 0">
28
+ <xsl:variable name="lstyle" select="func:substring-before-if-contains(substring-after($style, 'list-style-type:'), ';')"/>
29
+ <xsl:choose>
30
+ <xsl:when test="contains($lstyle, 'lower-alpha') or contains($lstyle, 'lower-latin') or contains($class, 'alfalower')">lowerLetter</xsl:when>
31
+ <xsl:when test="contains($lstyle, 'upper-alpha') or contains($lstyle, 'upper-latin') or contains($class, 'alfaupper')">upperLetter</xsl:when>
32
+ <xsl:when test="contains($lstyle, 'lower-roman') or contains($class, 'romanlower')">lowerRoman</xsl:when>
33
+ <xsl:when test="contains($lstyle, 'upper-roman') or contains($class, 'romanupper')">upperRoman</xsl:when>
34
+ <xsl:when test="contains($lstyle, 'none') or contains($class, 'manuell')">none</xsl:when>
35
+ <xsl:when test="contains($lstyle, 'decimal') or contains($class, 'num') or contains($class, 'token')">decimal</xsl:when>
36
+ <xsl:when test="contains($lstyle, 'disc')">bullet,●</xsl:when>
37
+ <xsl:when test="contains($lstyle, 'circle')">bullet,o</xsl:when>
38
+ <xsl:when test="contains($lstyle, 'square')">bullet,■</xsl:when>
39
+ <xsl:otherwise>none</xsl:otherwise>
40
+ </xsl:choose>
41
+ </xsl:when>
42
+ <xsl:otherwise>
43
+ <xsl:choose>
44
+ <xsl:when test="$tag_name = 'ol'">decimal</xsl:when>
45
+ <xsl:otherwise>bullet,●</xsl:otherwise>
46
+ </xsl:choose>
47
+ </xsl:otherwise>
48
+ </xsl:choose>
49
+ </func:result>
50
+ </func:function>
51
+
52
+ <xsl:template match="/">
53
+ <w:numbering xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas"
54
+ xmlns:mo="http://schemas.microsoft.com/office/mac/office/2008/main"
55
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
56
+ xmlns:mv="urn:schemas-microsoft-com:mac:vml" xmlns:o="urn:schemas-microsoft-com:office:office"
57
+ xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
58
+ xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math"
59
+ xmlns:v="urn:schemas-microsoft-com:vml"
60
+ xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing"
61
+ xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"
62
+ xmlns:w10="urn:schemas-microsoft-com:office:word"
63
+ xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
64
+ xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml"
65
+ xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup"
66
+ xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk"
67
+ xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml"
68
+ xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape">
69
+ <xsl:apply-templates />
70
+ <xsl:variable name="nlists" select="count(//ol[not(ancestor::ol) and not(ancestor::ul)]) + count(//ul[not(ancestor::ol) and not(ancestor::ul)])"/>
71
+ <xsl:call-template name="define-abstractNum"/>
72
+ </w:numbering>
73
+ </xsl:template>
74
+
75
+ <xsl:template match="ol|ul">
76
+ <xsl:param name="local_level" select="0"/>
77
+ <xsl:param name="global_level" select="count(preceding::ol[not(ancestor::ol or ancestor::ul)]) + count(preceding::ul[not(ancestor::ol or ancestor::ul)]) + 1"/>
78
+ <xsl:variable name="style" select="func:list-type(name(.), concat(' ', @style, ' '), concat(' ', @class, ' '))"/>
79
+ <xsl:choose>
80
+ <xsl:when test="$local_level = 0">
81
+ <w:abstractNum w:abstractNumId="{$global_level - 1}">
82
+ <w:nsid w:val="{concat('099A08C', $global_level)}"/>
83
+ <w:multiLevelType w:val="hybridMultilevel"/>
84
+ <xsl:call-template name="numbering_level">
85
+ <xsl:with-param name="ilvl" select="$local_level"/>
86
+ <xsl:with-param name="style" select="$style"/>
87
+ </xsl:call-template>
88
+ <xsl:apply-templates>
89
+ <xsl:with-param name="local_level" select="$local_level + 1" />
90
+ <xsl:with-param name="global_level" select="$global_level" />
91
+ </xsl:apply-templates>
92
+ <xsl:if test="count(.//ol) + count(.//ul) = 0">
93
+ <xsl:call-template name="autocomplete">
94
+ <xsl:with-param name="ilvl" select="$local_level + 1"/>
95
+ <xsl:with-param name="style" select="$style"/>
96
+ </xsl:call-template>
97
+ </xsl:if>
98
+ </w:abstractNum>
99
+ </xsl:when>
100
+ <xsl:otherwise>
101
+ <xsl:call-template name="numbering_level">
102
+ <xsl:with-param name="ilvl" select="$local_level"/>
103
+ <xsl:with-param name="style" select="$style"/>
104
+ </xsl:call-template>
105
+ <xsl:apply-templates>
106
+ <xsl:with-param name="local_level" select="$local_level + 1" />
107
+ <xsl:with-param name="global_level" select="$global_level" />
108
+ </xsl:apply-templates>
109
+
110
+ <xsl:if test="count(.//ol) + count(.//ul) = 0">
111
+ <xsl:call-template name="autocomplete">
112
+ <xsl:with-param name="ilvl" select="$local_level + 1"/>
113
+ <xsl:with-param name="style" select="$style"/>
114
+ </xsl:call-template>
115
+ </xsl:if>
116
+ </xsl:otherwise>
117
+ </xsl:choose>
118
+ </xsl:template>
119
+
120
+ <xsl:template match="li">
121
+ <xsl:param name="local_level" />
122
+ <xsl:param name="global_level" />
123
+ <xsl:apply-templates select="./ol|./ul">
124
+ <xsl:with-param name="local_level" select="$local_level" />
125
+ <xsl:with-param name="global_level" select="$global_level" />
126
+ </xsl:apply-templates>
127
+ </xsl:template>
128
+
129
+ <xsl:template match="*">
130
+ <xsl:apply-templates/>
131
+ </xsl:template>
132
+
133
+ <xsl:template match="text()"/>
134
+
135
+ <xsl:template name="numbering_level">
136
+ <xsl:param name="style" />
137
+ <xsl:param name="ilvl" />
138
+ <w:lvl w:ilvl="{$ilvl}">
139
+ <w:start w:val="1"/>
140
+ <w:numFmt w:val="{func:substring-before-if-contains($style, ',')}"/>
141
+ <xsl:choose>
142
+ <xsl:when test="contains($style, 'bullet')">
143
+ <xsl:variable name="list-symbol" select="substring-after($style, ',')"/>
144
+ <w:lvlText w:val="{$list-symbol}"/>
145
+ </xsl:when>
146
+ <xsl:when test="$style = 'none'">
147
+ <w:lvlText w:val=""/>
148
+ </xsl:when>
149
+ <xsl:otherwise>
150
+ <w:lvlText w:val="%{$ilvl + 1}."/>
151
+ </xsl:otherwise>
152
+ </xsl:choose>
153
+ <w:lvlJc w:val="left"/>
154
+ <w:pPr>
155
+ <w:ind w:left="{720 * ($ilvl + 1)}" w:hanging="360"/>
156
+ </w:pPr>
157
+ <xsl:if test="contains($style, 'bullet')">
158
+ <w:rPr>
159
+ <w:rFonts w:ascii="Symbol" w:hAnsi="Symbol" w:hint="default"/>
160
+ </w:rPr>
161
+ </xsl:if>
162
+ </w:lvl>
163
+ </xsl:template>
164
+
165
+ <xsl:template name="autocomplete">
166
+ <xsl:param name="ilvl"/>
167
+ <xsl:param name="style" />
168
+ <xsl:if test="$ilvl &lt; 6">
169
+ <xsl:call-template name="numbering_level">
170
+ <xsl:with-param name="ilvl" select="$ilvl"/>
171
+ <xsl:with-param name="style" select="$style"/>
172
+ </xsl:call-template>
173
+ <xsl:call-template name="autocomplete">
174
+ <xsl:with-param name="ilvl" select="$ilvl + 1"/>
175
+ <xsl:with-param name="style" select="$style"/>
176
+ </xsl:call-template>
177
+ </xsl:if>
178
+ </xsl:template>
179
+
180
+ <xsl:template name="define-abstractNum">
181
+ <xsl:param name="current" select="0"/>
182
+ <xsl:param name="max" select="count(//ol[not(ancestor::ol) and not(ancestor::ul)]) + count(//ul[not(ancestor::ol) and not(ancestor::ul)])"/>
183
+ <xsl:if test="$current &lt; $max">
184
+ <w:num w:numId="{$current + 1}">
185
+ <w:abstractNumId w:val="{$current}"/>
186
+ </w:num>
187
+ <xsl:call-template name="define-abstractNum">
188
+ <xsl:with-param name="current" select="$current + 1"/>
189
+ <xsl:with-param name="max" select="$max"/>
190
+ </xsl:call-template>
191
+ </xsl:if>
192
+ </xsl:template>
193
+
194
+ </xsl:stylesheet>
@@ -0,0 +1,187 @@
1
+ <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
2
+ xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
3
+ xmlns:o="urn:schemas-microsoft-com:office:office"
4
+ xmlns:v="urn:schemas-microsoft-com:vml"
5
+ xmlns:WX="http://schemas.microsoft.com/office/word/2003/auxHint"
6
+ xmlns:aml="http://schemas.microsoft.com/aml/2001/core"
7
+ xmlns:w10="urn:schemas-microsoft-com:office:word"
8
+ xmlns:pkg="http://schemas.microsoft.com/office/2006/xmlPackage"
9
+ xmlns:msxsl="urn:schemas-microsoft-com:xslt"
10
+ xmlns:ext="http://www.xmllab.net/wordml2html/ext"
11
+ xmlns:java="http://xml.apache.org/xalan/java"
12
+ xmlns:str="http://exslt.org/strings"
13
+ xmlns:func="http://exslt.org/functions"
14
+ xmlns:fn="http://www.w3.org/2005/xpath-functions"
15
+ version="1.0"
16
+ exclude-result-prefixes="java msxsl ext w o v WX aml w10"
17
+ extension-element-prefixes="func">
18
+
19
+ <!--XSLT support for tables -->
20
+
21
+ <!-- Full width tables per default -->
22
+ <xsl:template match="table">
23
+ <w:tbl>
24
+ <w:tblPr>
25
+ <w:tblStyle w:val="TableGrid"/>
26
+ <w:tblW w:w="5000" w:type="pct"/>
27
+ <xsl:call-template name="tableborders"/>
28
+ <w:tblLook w:val="0600" w:firstRow="0" w:lastRow="0" w:firstColumn="0" w:lastColumn="0" w:noHBand="1" w:noVBand="1"/>
29
+ </w:tblPr>
30
+ <xsl:apply-templates />
31
+ </w:tbl>
32
+ </xsl:template>
33
+
34
+ <xsl:template match="tbody">
35
+ <xsl:apply-templates />
36
+ </xsl:template>
37
+
38
+ <xsl:template match="thead">
39
+ <xsl:choose>
40
+ <xsl:when test="count(./tr) = 0">
41
+ <w:tr><xsl:apply-templates /></w:tr>
42
+ </xsl:when>
43
+ <xsl:otherwise>
44
+ <xsl:apply-templates />
45
+ </xsl:otherwise>
46
+ </xsl:choose>
47
+ </xsl:template>
48
+
49
+ <xsl:template match="tr">
50
+ <xsl:if test="string-length(.) > 0">
51
+ <w:tr>
52
+ <xsl:apply-templates />
53
+ </w:tr>
54
+ </xsl:if>
55
+ </xsl:template>
56
+
57
+ <xsl:template match="th">
58
+ <w:tc>
59
+ <xsl:call-template name="table-cell-properties"/>
60
+ <w:p>
61
+ <w:r>
62
+ <w:rPr>
63
+ <w:b />
64
+ </w:rPr>
65
+ <w:t xml:space="preserve"><xsl:value-of select="."/></w:t>
66
+ </w:r>
67
+ </w:p>
68
+ </w:tc>
69
+ </xsl:template>
70
+
71
+ <xsl:template match="td">
72
+ <w:tc>
73
+ <xsl:call-template name="table-cell-properties"/>
74
+ <xsl:call-template name="block">
75
+ <xsl:with-param name="current" select="." />
76
+ <xsl:with-param name="class" select="@class" />
77
+ <xsl:with-param name="style" select="@style" />
78
+ </xsl:call-template>
79
+ </w:tc>
80
+ </xsl:template>
81
+
82
+ <xsl:template name="block">
83
+ <xsl:param name="current" />
84
+ <xsl:param name="class" />
85
+ <xsl:param name="style" />
86
+ <xsl:if test="count($current/*|$current/text()) = 0">
87
+ <w:p/>
88
+ </xsl:if>
89
+ <xsl:for-each select="$current/*|$current/text()">
90
+ <xsl:choose>
91
+ <xsl:when test="name(.) = 'table'">
92
+ <xsl:apply-templates select="." />
93
+ <w:p/>
94
+ </xsl:when>
95
+ <xsl:when test="contains('|p|h1|h2|h3|h4|h5|h6|ul|ol|', concat('|', name(.), '|'))">
96
+ <xsl:apply-templates select="." />
97
+ </xsl:when>
98
+ <xsl:when test="descendant::table|descendant::p|descendant::h1|descendant::h2|descendant::h3|descendant::h4|descendant::h5|descendant::h6|descendant::li">
99
+ <xsl:call-template name="block">
100
+ <xsl:with-param name="current" select="."/>
101
+ </xsl:call-template>
102
+ </xsl:when>
103
+ <xsl:otherwise>
104
+ <w:p>
105
+ <xsl:call-template name="text-alignment">
106
+ <xsl:with-param name="class" select="$class" />
107
+ <xsl:with-param name="style" select="$style" />
108
+ </xsl:call-template>
109
+ <xsl:apply-templates select="." />
110
+ </w:p>
111
+ </xsl:otherwise>
112
+ </xsl:choose>
113
+ </xsl:for-each>
114
+ </xsl:template>
115
+
116
+ <xsl:template name="tableborders">
117
+ <xsl:variable name="border">
118
+ <xsl:choose>
119
+ <xsl:when test="contains(concat(' ', @class, ' '), ' table-bordered ')">6</xsl:when>
120
+ <xsl:when test="not(@border)">0</xsl:when>
121
+ <xsl:otherwise><xsl:value-of select="./@border * 6"/></xsl:otherwise>
122
+ </xsl:choose>
123
+ </xsl:variable>
124
+ <xsl:variable name="bordertype">
125
+ <xsl:choose>
126
+ <xsl:when test="$border=0">none</xsl:when>
127
+ <xsl:otherwise>single</xsl:otherwise>
128
+ </xsl:choose>
129
+ </xsl:variable>
130
+ <w:tblBorders>
131
+ <w:top w:val="{$bordertype}" w:sz="{$border}" w:space="0" w:color="auto"/>
132
+ <w:left w:val="{$bordertype}" w:sz="{$border}" w:space="0" w:color="auto"/>
133
+ <w:bottom w:val="{$bordertype}" w:sz="{$border}" w:space="0" w:color="auto"/>
134
+ <w:right w:val="{$bordertype}" w:sz="{$border}" w:space="0" w:color="auto"/>
135
+ <w:insideH w:val="{$bordertype}" w:sz="{$border}" w:space="0" w:color="auto"/>
136
+ <w:insideV w:val="{$bordertype}" w:sz="{$border}" w:space="0" w:color="auto"/>
137
+ </w:tblBorders>
138
+ </xsl:template>
139
+
140
+ <xsl:template name="table-cell-properties">
141
+ <w:tcPr>
142
+ <xsl:if test="contains(@class, 'ms-border-')">
143
+ <w:tcBorders>
144
+ <xsl:for-each select="str:tokenize(@class, ' ')">
145
+ <xsl:call-template name="define-border">
146
+ <xsl:with-param name="class" select="." />
147
+ </xsl:call-template>
148
+ </xsl:for-each>
149
+ </w:tcBorders>
150
+ </xsl:if>
151
+ <xsl:if test="contains(@class, 'ms-fill-')">
152
+ <xsl:variable name="cell-bg" select="str:tokenize(substring-after(@class, 'ms-fill-'), ' ')[1]"/>
153
+ <w:shd w:val="clear" w:color="auto" w:fill="{$cell-bg}" />
154
+ </xsl:if>
155
+ </w:tcPr>
156
+ </xsl:template>
157
+
158
+ <xsl:template name="define-border">
159
+ <xsl:param name="class" />
160
+ <xsl:if test="contains($class, 'ms-border-')">
161
+ <xsl:variable name="border" select="substring-after($class, 'ms-border-')"/>
162
+ <xsl:variable name="border-properties" select="str:tokenize($border, '-')"/>
163
+ <xsl:variable name="border-location" select="$border-properties[1]" />
164
+ <xsl:variable name="border-value" select="$border-properties[2]" />
165
+ <xsl:variable name="border-color">
166
+ <xsl:choose>
167
+ <xsl:when test="string-length($border-properties[3]) > 0"><xsl:value-of select="$border-properties[3]"/></xsl:when>
168
+ <xsl:otherwise>000000</xsl:otherwise>
169
+ </xsl:choose>
170
+ </xsl:variable>
171
+ <xsl:variable name="border-size">
172
+ <xsl:choose>
173
+ <xsl:when test="string-length($border-properties[4]) > 0"><xsl:value-of select="$border-properties[4] * 6"/></xsl:when>
174
+ <xsl:otherwise>6</xsl:otherwise>
175
+ </xsl:choose>
176
+ </xsl:variable>
177
+ <xsl:element name="w:{$border-location}">
178
+ <xsl:attribute name="w:val"><xsl:value-of select="$border-value" /></xsl:attribute>
179
+ <xsl:attribute name="w:sz"><xsl:value-of select="$border-size" /></xsl:attribute>
180
+ <xsl:attribute name="w:space">0</xsl:attribute>
181
+ <xsl:attribute name="w:color"><xsl:value-of select="$border-color" /></xsl:attribute>
182
+ </xsl:element>
183
+ </xsl:if>
184
+ </xsl:template>
185
+
186
+
187
+ </xsl:stylesheet>
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: htmltoword
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nicholas Frandsen, Cristina Matonte
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-03 00:00:00.000000000 Z
11
+ date: 2015-06-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack
@@ -125,24 +125,28 @@ dependencies:
125
125
  description: Convert html to word docx document.
126
126
  email:
127
127
  - nick.rowe.frandsen@gmail.com, anitsirc1@gmail.com
128
- executables: []
128
+ executables:
129
+ - htmltoword
129
130
  extensions: []
130
131
  extra_rdoc_files: []
131
132
  files:
132
133
  - README.md
133
134
  - Rakefile
135
+ - bin/htmltoword
134
136
  - lib/htmltoword.rb
135
137
  - lib/htmltoword/action_controller.rb
136
138
  - lib/htmltoword/configuration.rb
137
139
  - lib/htmltoword/document.rb
138
140
  - lib/htmltoword/htmltoword_helper.rb
139
141
  - lib/htmltoword/templates/default.docx
140
- - lib/htmltoword/templates/default_old.docx
141
142
  - lib/htmltoword/version.rb
142
143
  - lib/htmltoword/xslt/base.xslt
143
144
  - lib/htmltoword/xslt/extras.xslt
145
+ - lib/htmltoword/xslt/functions.xslt
144
146
  - lib/htmltoword/xslt/htmltoword.xslt
147
+ - lib/htmltoword/xslt/numbering.xslt
145
148
  - lib/htmltoword/xslt/style2.xslt
149
+ - lib/htmltoword/xslt/tables.xslt
146
150
  homepage: http://github.com/karnov/htmltoword
147
151
  licenses:
148
152
  - MIT