htmltoword-1.8.7 0.1.8.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +5 -0
- data/Rakefile +4 -0
- data/lib/htmltoword/document.rb +63 -0
- data/lib/htmltoword/htmltoword_helper.rb +35 -0
- data/lib/htmltoword/version.rb +3 -0
- data/lib/htmltoword.rb +19 -0
- data/templates/default.docx +0 -0
- data/xslt/html_to_wordml.xslt +347 -0
- metadata +167 -0
data/README.md
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
module Htmltoword
|
2
|
+
class Document
|
3
|
+
|
4
|
+
DOC_XML_FILE = 'word/document.xml'
|
5
|
+
BASIC_PATH = ::Htmltoword.root
|
6
|
+
FILE_EXTENSION = '.docx'
|
7
|
+
XSLT_TEMPLATE = File.join(BASIC_PATH, 'xslt', 'html_to_wordml.xslt')
|
8
|
+
|
9
|
+
class << self
|
10
|
+
include HtmltowordHelper
|
11
|
+
|
12
|
+
def create content, file_name
|
13
|
+
word_file = new(template_file, file_name)
|
14
|
+
word_file.replace_file content
|
15
|
+
word_file.save
|
16
|
+
end
|
17
|
+
|
18
|
+
def create_with_content template, file_name, content, set=nil
|
19
|
+
word_file = new(template_file("#{template}#{FILE_EXTENSION}"), file_name)
|
20
|
+
content = replace_values(content, set) if set
|
21
|
+
word_file.replace_file content
|
22
|
+
word_file.save
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(template_path, file_name)
|
27
|
+
@file_name = file_name
|
28
|
+
@replaceable_files = {}
|
29
|
+
@template_path = template_path
|
30
|
+
end
|
31
|
+
|
32
|
+
def file_name
|
33
|
+
@file_name
|
34
|
+
end
|
35
|
+
|
36
|
+
def save
|
37
|
+
Tempfile.open([file_name, FILE_EXTENSION].join(''), Dir::tmpdir) do |output_file|
|
38
|
+
Zip::ZipFile.open(@template_path) do |template_zip|
|
39
|
+
Zip::ZipOutputStream.open(output_file.path) do |out|
|
40
|
+
template_zip.each do |entry|
|
41
|
+
out.put_next_entry entry.name
|
42
|
+
if @replaceable_files[entry.name]
|
43
|
+
out.write(@replaceable_files[entry.name])
|
44
|
+
else
|
45
|
+
out.write(template_zip.read(entry.name))
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
return output_file
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def replace_file html, file_name=DOC_XML_FILE
|
56
|
+
source = Nokogiri::HTML(html.gsub(/>\s+</, '><'))
|
57
|
+
xslt = Nokogiri::XSLT(File.read(XSLT_TEMPLATE))
|
58
|
+
source = xslt.transform(source) unless (source/'/html').blank?
|
59
|
+
@replaceable_files[file_name] = source.to_s
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Htmltoword
|
2
|
+
module HtmltowordHelper
|
3
|
+
|
4
|
+
def template_file template_file_name=nil
|
5
|
+
default_path = File.join(::Htmltoword.templates_path, 'default.docx')
|
6
|
+
template_path = template_file_name.present? ? File.join(::Htmltoword.templates_path, template_file_name) : ''
|
7
|
+
File.exist?(template_path) ? template_path : default_path
|
8
|
+
end
|
9
|
+
|
10
|
+
def replace_values content, set
|
11
|
+
doc = Nokogiri::HTML(content)
|
12
|
+
set.each_pair do |key, value|
|
13
|
+
fields = (doc/"//span[@data-id='#{key}']")
|
14
|
+
fields.each do |f|
|
15
|
+
date_format = f.attr('date-format') || 'long'
|
16
|
+
data_transform = f.attr('data-transform')
|
17
|
+
if value.is_a? Hash
|
18
|
+
view = ActionView::Base.new(ActionController::Base.view_paths, {})
|
19
|
+
final_value = view.render 'partials/answer_table', :answer => value
|
20
|
+
fragment = doc.root.parse(final_value).first
|
21
|
+
new_node = doc.root.add_child(fragment)
|
22
|
+
f.parent.replace new_node
|
23
|
+
elsif value.is_a? Time
|
24
|
+
f.content = I18n.l(value.to_date, :format => date_format.to_sym)
|
25
|
+
elsif data_transform == 'capitalized'
|
26
|
+
f.content = value.mb_chars.capitalize rescue value
|
27
|
+
else
|
28
|
+
f.content = value
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
doc.to_s
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/htmltoword.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require "action_controller"
|
3
|
+
require "action_view"
|
4
|
+
require "nokogiri"
|
5
|
+
require "zip/zip"
|
6
|
+
|
7
|
+
module Htmltoword
|
8
|
+
def self.root
|
9
|
+
File.expand_path '../..', __FILE__
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.templates_path
|
13
|
+
File.join root, "templates"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
require "htmltoword/version"
|
18
|
+
require "htmltoword/htmltoword_helper"
|
19
|
+
require "htmltoword/document"
|
Binary file
|
@@ -0,0 +1,347 @@
|
|
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/common"
|
13
|
+
xmlns:fn="http://www.w3.org/2005/xpath-functions"
|
14
|
+
version="1.0"
|
15
|
+
exclude-result-prefixes="java msxsl ext w o v WX aml w10">
|
16
|
+
|
17
|
+
|
18
|
+
<xsl:output method="xml" encoding="utf-8" omit-xml-declaration="no" indent="yes" />
|
19
|
+
|
20
|
+
<xsl:template match="/">
|
21
|
+
<w:document xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:mo="http://schemas.microsoft.com/office/mac/office/2008/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mv="urn:schemas-microsoft-com:mac:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" mc:Ignorable="w14 wp14">
|
22
|
+
<xsl:apply-templates />
|
23
|
+
</w:document>
|
24
|
+
</xsl:template>
|
25
|
+
|
26
|
+
<xsl:template match="head" />
|
27
|
+
|
28
|
+
<xsl:template match="body">
|
29
|
+
<xsl:comment>
|
30
|
+
KNOWN BUGS:
|
31
|
+
div
|
32
|
+
h2
|
33
|
+
div
|
34
|
+
textnode (WONT BE WRAPPED IN A W:P)
|
35
|
+
div
|
36
|
+
table
|
37
|
+
span
|
38
|
+
text
|
39
|
+
</xsl:comment>
|
40
|
+
<w:body>
|
41
|
+
<xsl:apply-templates/>
|
42
|
+
<w:sectPr>
|
43
|
+
<w:pgSz w:w="11906" w:h="16838"/>
|
44
|
+
<w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1440" w:header="708" w:footer="708" w:gutter="0"/>
|
45
|
+
<w:cols w:space="708"/>
|
46
|
+
<w:docGrid w:linePitch="360"/>
|
47
|
+
</w:sectPr>
|
48
|
+
</w:body>
|
49
|
+
</xsl:template>
|
50
|
+
|
51
|
+
<xsl:template match="body/*[not(*)]">
|
52
|
+
<w:p>
|
53
|
+
<xsl:call-template name="text-alignment" />
|
54
|
+
<w:r>
|
55
|
+
<w:t xml:space="preserve"><xsl:value-of select="."/></w:t>
|
56
|
+
</w:r>
|
57
|
+
</w:p>
|
58
|
+
</xsl:template>
|
59
|
+
|
60
|
+
<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)]">
|
61
|
+
<xsl:comment>Divs should create a p if nothing above them has and nothing below them will</xsl:comment>
|
62
|
+
<w:p>
|
63
|
+
<xsl:call-template name="text-alignment" />
|
64
|
+
<xsl:apply-templates />
|
65
|
+
</w:p>
|
66
|
+
</xsl:template>
|
67
|
+
|
68
|
+
<xsl:template match="div">
|
69
|
+
<xsl:apply-templates />
|
70
|
+
</xsl:template>
|
71
|
+
|
72
|
+
<!-- TODO: make this prettier. Headings shouldn't enter in template from L51 -->
|
73
|
+
<xsl:template match="body/h1|body/h2|body/h3|body/h4|body/h5|body/h6|h1|h2|h3|h4|h5|h6">
|
74
|
+
<w:p>
|
75
|
+
<w:r>
|
76
|
+
<w:rPr>
|
77
|
+
<w:rStyle w:val="{name(.)}"/>
|
78
|
+
</w:rPr>
|
79
|
+
<w:t xml:space="preserve"><xsl:value-of select="."/></w:t>
|
80
|
+
</w:r>
|
81
|
+
</w:p>
|
82
|
+
</xsl:template>
|
83
|
+
|
84
|
+
<xsl:template match="p">
|
85
|
+
<w:p>
|
86
|
+
<xsl:call-template name="text-alignment" />
|
87
|
+
<xsl:apply-templates />
|
88
|
+
</w:p>
|
89
|
+
</xsl:template>
|
90
|
+
|
91
|
+
<xsl:template match="li">
|
92
|
+
<w:p>
|
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="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)]
|
100
|
+
|a[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)]
|
101
|
+
|small[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)]
|
102
|
+
|strong[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)]
|
103
|
+
|em[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)]
|
104
|
+
|i[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)]
|
105
|
+
|b[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)]">
|
106
|
+
<xsl:comment>
|
107
|
+
In the following situation:
|
108
|
+
|
109
|
+
div
|
110
|
+
h2
|
111
|
+
span
|
112
|
+
textnode
|
113
|
+
span
|
114
|
+
textnode
|
115
|
+
p
|
116
|
+
|
117
|
+
The div template will not create a w:p because the div contains a h2. Therefore we need to wrap the inline elements span|a|small in a p here.
|
118
|
+
</xsl:comment>
|
119
|
+
<w:p>
|
120
|
+
<xsl:apply-templates />
|
121
|
+
</w:p>
|
122
|
+
</xsl:template>
|
123
|
+
|
124
|
+
<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)]">
|
125
|
+
<xsl:comment>
|
126
|
+
In the following situation:
|
127
|
+
|
128
|
+
div
|
129
|
+
h2
|
130
|
+
textnode
|
131
|
+
p
|
132
|
+
|
133
|
+
The div template will not create a w:p because the div contains a h2. Therefore we need to wrap the textnode in a p here.
|
134
|
+
</xsl:comment>
|
135
|
+
<w:p>
|
136
|
+
<w:r>
|
137
|
+
<w:t xml:space="preserve"><xsl:value-of select="."/></w:t>
|
138
|
+
</w:r>
|
139
|
+
</w:p>
|
140
|
+
</xsl:template>
|
141
|
+
|
142
|
+
<xsl:template match="span[contains(concat(' ', @class, ' '), ' h ')]">
|
143
|
+
<xsl:comment>
|
144
|
+
This template adds MS Word highlighting ability.
|
145
|
+
</xsl:comment>
|
146
|
+
<xsl:variable name="color">
|
147
|
+
<xsl:choose>
|
148
|
+
<xsl:when test="./@data-style='pink'">magenta</xsl:when>
|
149
|
+
<xsl:when test="./@data-style='blue'">cyan</xsl:when>
|
150
|
+
<xsl:when test="./@data-style='orange'">darkYellow</xsl:when>
|
151
|
+
<xsl:otherwise><xsl:value-of select="./@data-style"/></xsl:otherwise>
|
152
|
+
</xsl:choose>
|
153
|
+
</xsl:variable>
|
154
|
+
<xsl:choose>
|
155
|
+
<xsl:when test="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">
|
156
|
+
<w:p>
|
157
|
+
<w:r>
|
158
|
+
<w:rPr>
|
159
|
+
<w:highlight w:val="{$color}"/>
|
160
|
+
</w:rPr>
|
161
|
+
<w:t xml:space="preserve"><xsl:value-of select="."/></w:t>
|
162
|
+
</w:r>
|
163
|
+
</w:p>
|
164
|
+
</xsl:when>
|
165
|
+
<xsl:otherwise>
|
166
|
+
<w:r>
|
167
|
+
<w:rPr>
|
168
|
+
<w:highlight w:val="{$color}"/>
|
169
|
+
</w:rPr>
|
170
|
+
<w:t xml:space="preserve"><xsl:value-of select="."/></w:t>
|
171
|
+
</w:r>
|
172
|
+
</xsl:otherwise>
|
173
|
+
</xsl:choose>
|
174
|
+
</xsl:template>
|
175
|
+
|
176
|
+
<xsl:template match="div[contains(concat(' ', @class, ' '), ' -page-break ')]">
|
177
|
+
<w:p>
|
178
|
+
<w:r>
|
179
|
+
<w:br w:type="page" />
|
180
|
+
</w:r>
|
181
|
+
</w:p>
|
182
|
+
<xsl:apply-templates />
|
183
|
+
</xsl:template>
|
184
|
+
|
185
|
+
<xsl:template match="details" />
|
186
|
+
|
187
|
+
<xsl:template name="tableborders">
|
188
|
+
<xsl:variable name="border">
|
189
|
+
<xsl:choose>
|
190
|
+
<xsl:when test="contains(concat(' ', @class, ' '), ' table-bordered ')">6</xsl:when>
|
191
|
+
<xsl:when test="not(@border)">0</xsl:when>
|
192
|
+
<xsl:otherwise><xsl:value-of select="./@border * 6"/></xsl:otherwise>
|
193
|
+
</xsl:choose>
|
194
|
+
</xsl:variable>
|
195
|
+
<xsl:variable name="bordertype">
|
196
|
+
<xsl:choose>
|
197
|
+
<xsl:when test="$border=0">none</xsl:when>
|
198
|
+
<xsl:otherwise>single</xsl:otherwise>
|
199
|
+
</xsl:choose>
|
200
|
+
</xsl:variable>
|
201
|
+
<w:tblBorders>
|
202
|
+
<w:top w:val="{$bordertype}" w:sz="{$border}" w:space="0" w:color="auto"/>
|
203
|
+
<w:left w:val="{$bordertype}" w:sz="{$border}" w:space="0" w:color="auto"/>
|
204
|
+
<w:bottom w:val="{$bordertype}" w:sz="{$border}" w:space="0" w:color="auto"/>
|
205
|
+
<w:right w:val="{$bordertype}" w:sz="{$border}" w:space="0" w:color="auto"/>
|
206
|
+
<w:insideH w:val="{$bordertype}" w:sz="{$border}" w:space="0" w:color="auto"/>
|
207
|
+
<w:insideV w:val="{$bordertype}" w:sz="{$border}" w:space="0" w:color="auto"/>
|
208
|
+
</w:tblBorders>
|
209
|
+
</xsl:template>
|
210
|
+
|
211
|
+
<xsl:template match="table">
|
212
|
+
<w:tbl>
|
213
|
+
<w:tblPr>
|
214
|
+
<w:tblStyle w:val="TableGrid"/>
|
215
|
+
<w:tblW w:w="0" w:type="auto"/>
|
216
|
+
<xsl:call-template name="tableborders"/>
|
217
|
+
<w:tblLook w:val="0600" w:firstRow="0" w:lastRow="0" w:firstColumn="0" w:lastColumn="0" w:noHBand="1" w:noVBand="1"/>
|
218
|
+
</w:tblPr>
|
219
|
+
<w:tblGrid>
|
220
|
+
<w:gridCol w:w="2310"/>
|
221
|
+
<w:gridCol w:w="2310"/>
|
222
|
+
</w:tblGrid>
|
223
|
+
<xsl:apply-templates />
|
224
|
+
</w:tbl>
|
225
|
+
</xsl:template>
|
226
|
+
|
227
|
+
<xsl:template match="tbody">
|
228
|
+
<xsl:apply-templates />
|
229
|
+
</xsl:template>
|
230
|
+
|
231
|
+
<xsl:template match="thead">
|
232
|
+
<xsl:choose>
|
233
|
+
<xsl:when test="count(./tr) = 0">
|
234
|
+
<w:tr><xsl:apply-templates /></w:tr>
|
235
|
+
</xsl:when>
|
236
|
+
<xsl:otherwise>
|
237
|
+
<xsl:apply-templates />
|
238
|
+
</xsl:otherwise>
|
239
|
+
</xsl:choose>
|
240
|
+
</xsl:template>
|
241
|
+
|
242
|
+
<xsl:template match="tr">
|
243
|
+
<xsl:if test="string-length(.) > 0">
|
244
|
+
<w:tr>
|
245
|
+
<xsl:apply-templates />
|
246
|
+
</w:tr>
|
247
|
+
</xsl:if>
|
248
|
+
</xsl:template>
|
249
|
+
|
250
|
+
<xsl:template match="th">
|
251
|
+
<w:tc>
|
252
|
+
<w:p>
|
253
|
+
<w:r>
|
254
|
+
<w:rPr>
|
255
|
+
<w:b />
|
256
|
+
</w:rPr>
|
257
|
+
<w:t xml:space="preserve"><xsl:value-of select="."/></w:t>
|
258
|
+
</w:r>
|
259
|
+
</w:p>
|
260
|
+
</w:tc>
|
261
|
+
</xsl:template>
|
262
|
+
|
263
|
+
<xsl:template match="td">
|
264
|
+
<w:tc>
|
265
|
+
<xsl:call-template name="block">
|
266
|
+
<xsl:with-param name="current" select="." />
|
267
|
+
<xsl:with-param name="class" select="@class" />
|
268
|
+
<xsl:with-param name="style" select="@style" />
|
269
|
+
</xsl:call-template>
|
270
|
+
</w:tc>
|
271
|
+
</xsl:template>
|
272
|
+
|
273
|
+
<xsl:template name="block">
|
274
|
+
<xsl:param name="current" />
|
275
|
+
<xsl:param name="class" />
|
276
|
+
<xsl:param name="style" />
|
277
|
+
<xsl:if test="count($current/*|$current/text()) = 0">
|
278
|
+
<w:p/>
|
279
|
+
</xsl:if>
|
280
|
+
<xsl:for-each select="$current/*|$current/text()">
|
281
|
+
<xsl:choose>
|
282
|
+
<xsl:when test="name(.) = 'table'">
|
283
|
+
<xsl:apply-templates select="." />
|
284
|
+
<w:p/>
|
285
|
+
</xsl:when>
|
286
|
+
<xsl:when test="contains('|p|h1|h2|h3|h4|h5|h6|ul|ol|', concat('|', name(.), '|'))">
|
287
|
+
<xsl:apply-templates select="." />
|
288
|
+
</xsl:when>
|
289
|
+
<xsl:when test="descendant::table|descendant::p|descendant::h1|descendant::h2|descendant::h3|descendant::h4|descendant::h5|descendant::h6|descendant::li">
|
290
|
+
<xsl:call-template name="block">
|
291
|
+
<xsl:with-param name="current" select="."/>
|
292
|
+
</xsl:call-template>
|
293
|
+
</xsl:when>
|
294
|
+
<xsl:otherwise>
|
295
|
+
<w:p>
|
296
|
+
<xsl:call-template name="text-alignment">
|
297
|
+
<xsl:with-param name="class" select="$class" />
|
298
|
+
<xsl:with-param name="style" select="$style" />
|
299
|
+
</xsl:call-template>
|
300
|
+
<xsl:apply-templates select="." />
|
301
|
+
</w:p>
|
302
|
+
</xsl:otherwise>
|
303
|
+
</xsl:choose>
|
304
|
+
</xsl:for-each>
|
305
|
+
</xsl:template>
|
306
|
+
|
307
|
+
<xsl:template match="text()">
|
308
|
+
<xsl:if test="string-length(.) > 0">
|
309
|
+
<w:r>
|
310
|
+
<xsl:if test="ancestor::i or ancestor::em">
|
311
|
+
<w:rPr>
|
312
|
+
<w:i />
|
313
|
+
</w:rPr>
|
314
|
+
</xsl:if>
|
315
|
+
<xsl:if test="ancestor::b or ancestor::strong">
|
316
|
+
<w:rPr>
|
317
|
+
<w:b />
|
318
|
+
</w:rPr>
|
319
|
+
</xsl:if>
|
320
|
+
<w:t xml:space="preserve"><xsl:value-of select="."/></w:t>
|
321
|
+
</w:r>
|
322
|
+
</xsl:if>
|
323
|
+
</xsl:template>
|
324
|
+
|
325
|
+
<xsl:template match="*">
|
326
|
+
<xsl:apply-templates/>
|
327
|
+
</xsl:template>
|
328
|
+
|
329
|
+
<xsl:template name="text-alignment">
|
330
|
+
<xsl:param name="class" select="@class" />
|
331
|
+
<xsl:param name="style" select="@style" />
|
332
|
+
<xsl:variable name="alignment">
|
333
|
+
<xsl:choose>
|
334
|
+
<xsl:when test="contains(concat(' ', $class, ' '), ' center ') or contains(translate(normalize-space($style),' ',''), 'text-align:center')">center</xsl:when>
|
335
|
+
<xsl:when test="contains(concat(' ', $class, ' '), ' right ') or contains(translate(normalize-space($style),' ',''), 'text-align:right')">right</xsl:when>
|
336
|
+
<xsl:when test="contains(concat(' ', $class, ' '), ' left ') or contains(translate(normalize-space($style),' ',''), 'text-align:left')">left</xsl:when>
|
337
|
+
<xsl:when test="contains(concat(' ', $class, ' '), ' justify ') or contains(translate(normalize-space($style),' ',''), 'text-align:justify')">both</xsl:when>
|
338
|
+
<xsl:otherwise></xsl:otherwise>
|
339
|
+
</xsl:choose>
|
340
|
+
</xsl:variable>
|
341
|
+
<xsl:if test="string-length(normalize-space($alignment)) > 0">
|
342
|
+
<w:pPr>
|
343
|
+
<w:jc w:val="{$alignment}"/>
|
344
|
+
</w:pPr>
|
345
|
+
</xsl:if>
|
346
|
+
</xsl:template>
|
347
|
+
</xsl:stylesheet>
|
metadata
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: htmltoword-1.8.7
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: -2720420102
|
5
|
+
prerelease: 6
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 8
|
10
|
+
- rc
|
11
|
+
- 1
|
12
|
+
version: 0.1.8.rc1
|
13
|
+
platform: ruby
|
14
|
+
authors:
|
15
|
+
- Nicholas Frandsen, Cristina Matonte
|
16
|
+
- Ayoub Khobaklatte
|
17
|
+
autorequire:
|
18
|
+
bindir: bin
|
19
|
+
cert_chain: []
|
20
|
+
|
21
|
+
date: 2018-01-09 00:00:00 Z
|
22
|
+
dependencies:
|
23
|
+
- !ruby/object:Gem::Dependency
|
24
|
+
name: actionpack
|
25
|
+
prerelease: false
|
26
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
27
|
+
none: false
|
28
|
+
requirements:
|
29
|
+
- - ~>
|
30
|
+
- !ruby/object:Gem::Version
|
31
|
+
hash: 5
|
32
|
+
segments:
|
33
|
+
- 2
|
34
|
+
- 3
|
35
|
+
version: "2.3"
|
36
|
+
type: :runtime
|
37
|
+
version_requirements: *id001
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: nokogiri
|
40
|
+
prerelease: false
|
41
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - "="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
hash: 9
|
47
|
+
segments:
|
48
|
+
- 1
|
49
|
+
- 5
|
50
|
+
- 5
|
51
|
+
version: 1.5.5
|
52
|
+
type: :runtime
|
53
|
+
version_requirements: *id002
|
54
|
+
- !ruby/object:Gem::Dependency
|
55
|
+
name: rubyzip
|
56
|
+
prerelease: false
|
57
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - "="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
hash: 41
|
63
|
+
segments:
|
64
|
+
- 0
|
65
|
+
- 9
|
66
|
+
- 9
|
67
|
+
version: 0.9.9
|
68
|
+
type: :runtime
|
69
|
+
version_requirements: *id003
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: rspec
|
72
|
+
prerelease: false
|
73
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
hash: 3
|
79
|
+
segments:
|
80
|
+
- 0
|
81
|
+
version: "0"
|
82
|
+
type: :development
|
83
|
+
version_requirements: *id004
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: bundler
|
86
|
+
prerelease: false
|
87
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
88
|
+
none: false
|
89
|
+
requirements:
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
hash: 3
|
93
|
+
segments:
|
94
|
+
- 0
|
95
|
+
version: "0"
|
96
|
+
type: :development
|
97
|
+
version_requirements: *id005
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
name: rake
|
100
|
+
prerelease: false
|
101
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
102
|
+
none: false
|
103
|
+
requirements:
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
hash: 3
|
107
|
+
segments:
|
108
|
+
- 0
|
109
|
+
version: "0"
|
110
|
+
type: :development
|
111
|
+
version_requirements: *id006
|
112
|
+
description: Convert html to word docx document.
|
113
|
+
email:
|
114
|
+
- nick.rowe.frandsen@gmail.com, anitsirc1@gmail.com
|
115
|
+
- ayoub.khobalatte@gmail.com
|
116
|
+
executables: []
|
117
|
+
|
118
|
+
extensions: []
|
119
|
+
|
120
|
+
extra_rdoc_files: []
|
121
|
+
|
122
|
+
files:
|
123
|
+
- lib/htmltoword/document.rb
|
124
|
+
- lib/htmltoword/htmltoword_helper.rb
|
125
|
+
- lib/htmltoword/version.rb
|
126
|
+
- lib/htmltoword.rb
|
127
|
+
- templates/default.docx
|
128
|
+
- xslt/html_to_wordml.xslt
|
129
|
+
- README.md
|
130
|
+
- Rakefile
|
131
|
+
homepage: http://github.com/unwire/htmltoword
|
132
|
+
licenses:
|
133
|
+
- MIT
|
134
|
+
post_install_message:
|
135
|
+
rdoc_options: []
|
136
|
+
|
137
|
+
require_paths:
|
138
|
+
- lib
|
139
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
140
|
+
none: false
|
141
|
+
requirements:
|
142
|
+
- - ">="
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
hash: 3
|
145
|
+
segments:
|
146
|
+
- 0
|
147
|
+
version: "0"
|
148
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
149
|
+
none: false
|
150
|
+
requirements:
|
151
|
+
- - ">"
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
hash: 25
|
154
|
+
segments:
|
155
|
+
- 1
|
156
|
+
- 3
|
157
|
+
- 1
|
158
|
+
version: 1.3.1
|
159
|
+
requirements: []
|
160
|
+
|
161
|
+
rubyforge_project:
|
162
|
+
rubygems_version: 1.8.30
|
163
|
+
signing_key:
|
164
|
+
specification_version: 3
|
165
|
+
summary: 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.
|
166
|
+
test_files: []
|
167
|
+
|