htmltoword 0.5.1 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/htmltoword.rb +9 -6
- data/lib/htmltoword/document.rb +82 -29
- data/lib/htmltoword/helpers/templates_helper.rb +9 -0
- data/lib/htmltoword/helpers/xslt_helper.rb +17 -0
- data/lib/htmltoword/railtie.rb +25 -0
- data/lib/htmltoword/renderer.rb +43 -0
- data/lib/htmltoword/version.rb +1 -1
- data/lib/htmltoword/xslt/base.xslt +24 -3
- data/lib/htmltoword/xslt/cleanup.xslt +70 -0
- data/lib/htmltoword/xslt/functions.xslt +3 -0
- data/lib/htmltoword/xslt/image_functions.xslt +148 -0
- data/lib/htmltoword/xslt/images.xslt +129 -0
- data/lib/htmltoword/xslt/inline_elements.xslt +13 -12
- data/lib/htmltoword/xslt/links.xslt +2 -1
- data/lib/htmltoword/xslt/relations.xslt +33 -1
- data/lib/htmltoword/xslt/tables.xslt +3 -0
- metadata +10 -5
- data/lib/htmltoword/action_controller.rb +0 -54
- data/lib/htmltoword/htmltoword_helper.rb +0 -35
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7034d51bc5f9b9251aec22334f9ee4427bc3d520
|
4
|
+
data.tar.gz: b5925e2169eca6f9de534788a2f62850da43ac4d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c5ac9f6e7c6f26acbb06ee4c85a042cce12318802aabb08a836df3db136b408f6622b34366e0993ec4b8de7b2183b7f4e83c639c858342b5aa2586b264c2ed89
|
7
|
+
data.tar.gz: 6747b7abea40e7b43d52322ebe4283e4edc5f97c95487cb3de57e0f66bcfd209f379012572a88a96b4f95fe95651984eaeaf2b4cfb7b9410e648a80a0b7a3426
|
data/lib/htmltoword.rb
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
# encoding: UTF-8
|
2
|
-
# require 'action_controller'
|
3
|
-
# require 'action_view'
|
4
2
|
require 'nokogiri'
|
5
3
|
require 'zip'
|
4
|
+
require 'open-uri'
|
6
5
|
require_relative 'htmltoword/configuration'
|
7
6
|
|
8
7
|
module Htmltoword
|
@@ -15,12 +14,16 @@ module Htmltoword
|
|
15
14
|
@configuration ||= Configuration.new
|
16
15
|
end
|
17
16
|
|
18
|
-
|
17
|
+
alias_method :config, :configuration
|
19
18
|
end
|
20
19
|
end
|
21
20
|
|
22
|
-
|
23
21
|
require_relative 'htmltoword/version'
|
24
|
-
require_relative 'htmltoword/
|
22
|
+
require_relative 'htmltoword/helpers/templates_helper'
|
23
|
+
require_relative 'htmltoword/helpers/xslt_helper'
|
25
24
|
require_relative 'htmltoword/document'
|
26
|
-
|
25
|
+
|
26
|
+
if defined?(Rails)
|
27
|
+
require_relative 'htmltoword/renderer'
|
28
|
+
require_relative 'htmltoword/railtie'
|
29
|
+
end
|
data/lib/htmltoword/document.rb
CHANGED
@@ -1,26 +1,26 @@
|
|
1
1
|
module Htmltoword
|
2
2
|
class Document
|
3
|
-
|
4
|
-
include HtmltowordHelper
|
3
|
+
include XSLTHelper
|
5
4
|
|
5
|
+
class << self
|
6
|
+
include TemplatesHelper
|
6
7
|
def create(content, template_name = nil, extras = false)
|
7
8
|
template_name += extension if template_name && !template_name.end_with?(extension)
|
8
9
|
document = new(template_file(template_name))
|
9
|
-
document.
|
10
|
+
document.replace_files(content, extras)
|
10
11
|
document.generate
|
11
12
|
end
|
12
13
|
|
13
14
|
def create_and_save(content, file_path, template_name = nil, extras = false)
|
14
|
-
File.open(file_path,
|
15
|
+
File.open(file_path, 'wb') do |out|
|
15
16
|
out << create(content, template_name, extras)
|
16
17
|
end
|
17
18
|
end
|
18
19
|
|
19
|
-
def create_with_content(template, content,
|
20
|
+
def create_with_content(template, content, extras = false)
|
20
21
|
template += extension unless template.end_with?(extension)
|
21
|
-
content = replace_values(content, set) if set
|
22
22
|
document = new(template_file(template))
|
23
|
-
document.
|
23
|
+
document.replace_files(content, extras)
|
24
24
|
document.generate
|
25
25
|
end
|
26
26
|
|
@@ -40,22 +40,15 @@ module Htmltoword
|
|
40
40
|
'word/_rels/document.xml.rels'
|
41
41
|
end
|
42
42
|
|
43
|
-
def
|
44
|
-
|
45
|
-
end
|
46
|
-
|
47
|
-
def relations_xslt
|
48
|
-
File.join(Htmltoword.config.default_xslt_path, 'relations.xslt')
|
49
|
-
end
|
50
|
-
|
51
|
-
def xslt_template(extras = false)
|
52
|
-
File.join(Htmltoword.config.default_xslt_path, (extras ? 'htmltoword.xslt' : 'base.xslt'))
|
43
|
+
def content_types_xml_file
|
44
|
+
'[Content_Types].xml'
|
53
45
|
end
|
54
46
|
end
|
55
47
|
|
56
48
|
def initialize(template_path)
|
57
49
|
@replaceable_files = {}
|
58
50
|
@template_path = template_path
|
51
|
+
@image_files = []
|
59
52
|
end
|
60
53
|
|
61
54
|
#
|
@@ -67,35 +60,95 @@ module Htmltoword
|
|
67
60
|
template_zip.each do |entry|
|
68
61
|
out.put_next_entry entry.name
|
69
62
|
if @replaceable_files[entry.name] && entry.name == Document.doc_xml_file
|
70
|
-
source = entry.get_input_stream.read
|
63
|
+
source = entry.get_input_stream.read
|
64
|
+
# Change only the body of document. TODO: Improve this...
|
65
|
+
source = source.sub(/(<w:body>)((.|\n)*?)(<w:sectPr)/, "\\1#{@replaceable_files[entry.name]}\\4")
|
71
66
|
out.write(source)
|
72
67
|
elsif @replaceable_files[entry.name]
|
73
68
|
out.write(@replaceable_files[entry.name])
|
69
|
+
elsif entry.name == Document.content_types_xml_file
|
70
|
+
raw_file = entry.get_input_stream.read
|
71
|
+
content_types = @image_files.empty? ? raw_file : inject_image_content_types(raw_file)
|
72
|
+
|
73
|
+
out.write(content_types)
|
74
74
|
else
|
75
75
|
out.write(template_zip.read(entry.name))
|
76
76
|
end
|
77
77
|
end
|
78
|
+
unless @image_files.empty?
|
79
|
+
#stream the image files into the media folder using open-uri
|
80
|
+
@image_files.each do |hash|
|
81
|
+
out.put_next_entry("word/media/#{hash[:filename]}")
|
82
|
+
open(hash[:url], 'rb') do |f|
|
83
|
+
out.write(f.read)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
78
87
|
end
|
79
88
|
buffer.string
|
80
89
|
end
|
81
90
|
end
|
82
91
|
|
83
|
-
def
|
84
|
-
html =
|
92
|
+
def replace_files(html, extras = false)
|
93
|
+
html = '<body></body>' if html.nil? || html.empty?
|
85
94
|
source = Nokogiri::HTML(html.gsub(/>\s+</, '><'))
|
86
|
-
transform_and_replace(source,
|
87
|
-
transform_and_replace(source,
|
88
|
-
|
89
|
-
|
95
|
+
transform_and_replace(source, xslt_path('numbering'), Document.numbering_xml_file)
|
96
|
+
transform_and_replace(source, xslt_path('relations'), Document.relations_xml_file)
|
97
|
+
transform_doc_xml(source, extras)
|
98
|
+
local_images(source)
|
99
|
+
end
|
100
|
+
|
101
|
+
def transform_doc_xml(source, extras = false)
|
102
|
+
transformed_source = xslt(stylesheet_name: 'cleanup').transform(source)
|
103
|
+
transformed_source = xslt(stylesheet_name: 'inline_elements').transform(transformed_source)
|
104
|
+
transform_and_replace(transformed_source, document_xslt(extras), Document.doc_xml_file, extras)
|
90
105
|
end
|
91
106
|
|
92
107
|
private
|
93
108
|
|
94
|
-
def transform_and_replace
|
95
|
-
|
96
|
-
content =
|
97
|
-
content.gsub!(/\s*xmlns:(\w+)="(.*?)\s*"/,'') if remove_ns
|
98
|
-
@replaceable_files[file] =
|
109
|
+
def transform_and_replace(source, stylesheet_path, file, remove_ns = false)
|
110
|
+
stylesheet = xslt(stylesheet_path: stylesheet_path)
|
111
|
+
content = stylesheet.apply_to(source)
|
112
|
+
content.gsub!(/\s*xmlns:(\w+)="(.*?)\s*"/, '') if remove_ns
|
113
|
+
@replaceable_files[file] = content
|
114
|
+
end
|
115
|
+
|
116
|
+
#generates an array of hashes with filename and full url
|
117
|
+
#for all images to be embeded in the word document
|
118
|
+
def local_images(source)
|
119
|
+
source.css('img').each_with_index do |image,i|
|
120
|
+
filename = image['data-filename'] ? image['data-filename'] : image['src'].split("/").last
|
121
|
+
ext = File.extname(filename).delete(".").downcase
|
122
|
+
|
123
|
+
@image_files << { filename: "image#{i+1}.#{ext}", url: image['src'], ext: ext }
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
#get extension from filename and clean to match content_types
|
128
|
+
def content_type_from_extension(ext)
|
129
|
+
ext == "jpg" ? "jpeg" : ext
|
130
|
+
end
|
131
|
+
|
132
|
+
#inject the required content_types into the [content_types].xml file...
|
133
|
+
def inject_image_content_types(source)
|
134
|
+
doc = Nokogiri::XML(source)
|
135
|
+
|
136
|
+
#get a list of all extensions currently in content_types file
|
137
|
+
existing_exts = doc.css("Default").map { |node| node.attribute("Extension").value }.compact
|
138
|
+
|
139
|
+
#get a list of extensions we need for our images
|
140
|
+
required_exts = @image_files.map{ |i| i[:ext] }
|
141
|
+
|
142
|
+
#workout which required extensions are missing from the content_types file
|
143
|
+
missing_exts = (required_exts - existing_exts).uniq
|
144
|
+
|
145
|
+
#inject missing extensions into document
|
146
|
+
missing_exts.each do |ext|
|
147
|
+
doc.at_css("Types").add_child( "<Default Extension='#{ext}' ContentType='image/#{content_type_from_extension(ext)}'/>")
|
148
|
+
end
|
149
|
+
|
150
|
+
#return the amended source to be saved into the zip
|
151
|
+
doc.to_s
|
99
152
|
end
|
100
153
|
end
|
101
154
|
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module Htmltoword
|
2
|
+
module TemplatesHelper
|
3
|
+
def template_file(template_file_name = nil)
|
4
|
+
default_path = File.join(::Htmltoword.config.default_templates_path, 'default.docx')
|
5
|
+
template_path = template_file_name.nil? ? '' : File.join(::Htmltoword.config.custom_templates_path, template_file_name)
|
6
|
+
File.exist?(template_path) ? template_path : default_path
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Htmltoword
|
2
|
+
module XSLTHelper
|
3
|
+
def document_xslt(extras = false)
|
4
|
+
file_name = extras ? 'htmltoword' : 'base'
|
5
|
+
xslt_path(file_name)
|
6
|
+
end
|
7
|
+
|
8
|
+
def xslt_path(template_name)
|
9
|
+
File.join(Htmltoword.config.default_xslt_path, "#{template_name}.xslt")
|
10
|
+
end
|
11
|
+
|
12
|
+
def xslt(stylesheet_name: nil, stylesheet_path: nil)
|
13
|
+
return Nokogiri::XSLT(File.open(stylesheet_path)) if stylesheet_path
|
14
|
+
Nokogiri::XSLT(File.open(xslt_path(stylesheet_name)))
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Htmltoword
|
2
|
+
class Railtie < ::Rails::Railtie
|
3
|
+
initializer 'htmltoword.setup' do
|
4
|
+
if defined?(Mime) and Mime[:docx].nil?
|
5
|
+
Mime::Type.register 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', :docx
|
6
|
+
end
|
7
|
+
|
8
|
+
ActionController::Renderers.add :docx do |file_name, options|
|
9
|
+
Htmltoword::Renderer.send_file(self, file_name, options)
|
10
|
+
end
|
11
|
+
|
12
|
+
if defined? ActionController::Responder
|
13
|
+
ActionController::Responder.class_eval do
|
14
|
+
def to_docx
|
15
|
+
if @default_response
|
16
|
+
@default_response.call(options)
|
17
|
+
else
|
18
|
+
controller.render({ docx: controller.action_name }.merge(options))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Htmltoword
|
2
|
+
class Renderer
|
3
|
+
class << self
|
4
|
+
def send_file(context, filename, options = {})
|
5
|
+
new(context, filename, options).send_file
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(context, filename, options)
|
10
|
+
@word_template = options[:word_template].presence
|
11
|
+
@disposition = options.fetch(:disposition, 'attachment')
|
12
|
+
@use_extras = options.fetch(:extras, false)
|
13
|
+
@file_name = file_name(filename, options)
|
14
|
+
@context = context
|
15
|
+
define_template(filename, options)
|
16
|
+
@content = options[:content] || @context.render_to_string(options)
|
17
|
+
end
|
18
|
+
|
19
|
+
def send_file
|
20
|
+
document = Htmltoword::Document.create(@content, @word_template, @use_extras)
|
21
|
+
@context.send_data(document, filename: @file_name, type: Mime[:docx], disposition: @disposition)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def define_template(filename, options)
|
27
|
+
if options[:template] == @context.action_name
|
28
|
+
if filename =~ %r{^([^\/]+)/(.+)$}
|
29
|
+
options[:prefixes] ||= []
|
30
|
+
options[:prefixes].unshift $1
|
31
|
+
options[:template] = $2
|
32
|
+
else
|
33
|
+
options[:template] = filename
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def file_name(filename, options)
|
39
|
+
name = options[:filename].presence || filename
|
40
|
+
name =~ /\.docx$/ ? name : "#{name}.docx"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/htmltoword/version.rb
CHANGED
@@ -19,7 +19,7 @@
|
|
19
19
|
<xsl:include href="./functions.xslt"/>
|
20
20
|
<xsl:include href="./tables.xslt"/>
|
21
21
|
<xsl:include href="./links.xslt"/>
|
22
|
-
|
22
|
+
<xsl:include href="./images.xslt"/>
|
23
23
|
<xsl:template match="/">
|
24
24
|
<xsl:apply-templates />
|
25
25
|
</xsl:template>
|
@@ -204,6 +204,12 @@
|
|
204
204
|
<xsl:when test="self::a[starts-with(@href, 'http://') or starts-with(@href, 'https://')]">
|
205
205
|
<xsl:call-template name="link" />
|
206
206
|
</xsl:when>
|
207
|
+
<xsl:when test="self::img">
|
208
|
+
<xsl:comment>
|
209
|
+
This template adds images.
|
210
|
+
</xsl:comment>
|
211
|
+
<xsl:call-template name="image"/>
|
212
|
+
</xsl:when>
|
207
213
|
<xsl:otherwise>
|
208
214
|
<xsl:apply-templates />
|
209
215
|
</xsl:otherwise>
|
@@ -277,12 +283,12 @@
|
|
277
283
|
<xsl:template match="text()">
|
278
284
|
<xsl:if test="string-length(.) > 0">
|
279
285
|
<w:r>
|
280
|
-
<xsl:if test="ancestor::i
|
286
|
+
<xsl:if test="ancestor::i">
|
281
287
|
<w:rPr>
|
282
288
|
<w:i />
|
283
289
|
</w:rPr>
|
284
290
|
</xsl:if>
|
285
|
-
<xsl:if test="ancestor::b
|
291
|
+
<xsl:if test="ancestor::b">
|
286
292
|
<w:rPr>
|
287
293
|
<w:b />
|
288
294
|
</w:rPr>
|
@@ -292,6 +298,21 @@
|
|
292
298
|
<w:u w:val="single"/>
|
293
299
|
</w:rPr>
|
294
300
|
</xsl:if>
|
301
|
+
<xsl:if test="ancestor::s">
|
302
|
+
<w:rPr>
|
303
|
+
<w:strike w:val="true"/>
|
304
|
+
</w:rPr>
|
305
|
+
</xsl:if>
|
306
|
+
<xsl:if test="ancestor::sub">
|
307
|
+
<w:rPr>
|
308
|
+
<w:vertAlign w:val="subscript"/>
|
309
|
+
</w:rPr>
|
310
|
+
</xsl:if>
|
311
|
+
<xsl:if test="ancestor::sup">
|
312
|
+
<w:rPr>
|
313
|
+
<w:vertAlign w:val="superscript"/>
|
314
|
+
</w:rPr>
|
315
|
+
</xsl:if>
|
295
316
|
<w:t xml:space="preserve"><xsl:value-of select="."/></w:t>
|
296
317
|
</w:r>
|
297
318
|
</xsl:if>
|
@@ -0,0 +1,70 @@
|
|
1
|
+
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
2
|
+
xmlns:str="http://exslt.org/strings"
|
3
|
+
xmlns:func="http://exslt.org/functions"
|
4
|
+
xmlns:fn="http://www.w3.org/2005/xpath-functions"
|
5
|
+
version="1.0"
|
6
|
+
exclude-result-prefixes="java msxsl ext w o v WX aml w10"
|
7
|
+
extension-element-prefixes="func">
|
8
|
+
<xsl:output method="html" encoding="utf-8" omit-xml-declaration="yes" indent="yes"/>
|
9
|
+
|
10
|
+
<xsl:template match="/">
|
11
|
+
<xsl:apply-templates/>
|
12
|
+
</xsl:template>
|
13
|
+
|
14
|
+
<xsl:template match="head"/>
|
15
|
+
|
16
|
+
<!-- Elements not supported -->
|
17
|
+
<xsl:template match="applet"/>
|
18
|
+
<xsl:template match="area"/>
|
19
|
+
<xsl:template match="audio"/>
|
20
|
+
<xsl:template match="base"/>
|
21
|
+
<xsl:template match="basefont"/>
|
22
|
+
<xsl:template match="canvas"/>
|
23
|
+
<xsl:template match="command"/>
|
24
|
+
<xsl:template match="font"/>
|
25
|
+
<xsl:template match="iframe"/>
|
26
|
+
<xsl:template match="isindex"/>
|
27
|
+
<xsl:template match="map"/>
|
28
|
+
<xsl:template match="noframes"/>
|
29
|
+
<xsl:template match="noscript"/>
|
30
|
+
<xsl:template match="object"/>
|
31
|
+
<xsl:template match="param"/>
|
32
|
+
<xsl:template match="script"/>
|
33
|
+
<xsl:template match="source"/>
|
34
|
+
<xsl:template match="style"/>
|
35
|
+
<xsl:template match="video"/>
|
36
|
+
|
37
|
+
<!-- Elements currently being handled as normal text. Remove tags only -->
|
38
|
+
<xsl:template match="abbr"><xsl:apply-templates/></xsl:template>
|
39
|
+
<xsl:template match="acronym"><xsl:apply-templates/></xsl:template>
|
40
|
+
<xsl:template match="bdi"><xsl:apply-templates/></xsl:template>
|
41
|
+
<xsl:template match="bdo"><xsl:apply-templates/></xsl:template>
|
42
|
+
<xsl:template match="big"><xsl:apply-templates/></xsl:template>
|
43
|
+
<xsl:template match="code"><xsl:apply-templates/></xsl:template>
|
44
|
+
<xsl:template match="kbd"><xsl:apply-templates/></xsl:template>
|
45
|
+
<xsl:template match="samp"><xsl:apply-templates/></xsl:template>
|
46
|
+
<xsl:template match="small"><xsl:apply-templates/></xsl:template>
|
47
|
+
<xsl:template match="tt"><xsl:apply-templates/></xsl:template>
|
48
|
+
<xsl:template match="var"><xsl:apply-templates/></xsl:template>
|
49
|
+
|
50
|
+
<!-- Inline elements transformations -->
|
51
|
+
<xsl:template match="cite"><i><xsl:apply-templates/></i></xsl:template>
|
52
|
+
<xsl:template match="del"><s><xsl:apply-templates/></s></xsl:template>
|
53
|
+
<xsl:template match="dfn"><i><xsl:apply-templates/></i></xsl:template>
|
54
|
+
<xsl:template match="em"><i><xsl:apply-templates/></i></xsl:template>
|
55
|
+
<xsl:template match="ins"><u><xsl:apply-templates/></u></xsl:template>
|
56
|
+
<xsl:template match="mark"><span class="h" data-style="yellow"><xsl:apply-templates/></span></xsl:template>
|
57
|
+
<xsl:template match="q">"<xsl:apply-templates/>"</xsl:template>
|
58
|
+
<xsl:template match="strike"><s><xsl:apply-templates/></s></xsl:template>
|
59
|
+
<xsl:template match="strong"><b><xsl:apply-templates/></b></xsl:template>
|
60
|
+
|
61
|
+
<!-- Block elements transformations -->
|
62
|
+
<xsl:template match="section"><div class="{@class}" style="{@style}"><xsl:apply-templates/></div></xsl:template>
|
63
|
+
<xsl:template match="article"><div class="{@class}" style="{@style}"><xsl:apply-templates/></div></xsl:template>
|
64
|
+
|
65
|
+
<xsl:template match="@*|node()">
|
66
|
+
<xsl:copy>
|
67
|
+
<xsl:apply-templates select="@*|node()"/>
|
68
|
+
</xsl:copy>
|
69
|
+
</xsl:template>
|
70
|
+
</xsl:stylesheet>
|
@@ -31,4 +31,7 @@
|
|
31
31
|
</xsl:choose>
|
32
32
|
</func:result>
|
33
33
|
</func:function>
|
34
|
+
|
35
|
+
<!-- template as function used to return the relationship id of the element (currently links or images) -->
|
36
|
+
<xsl:template name="relationship-id">rId<xsl:value-of select="count(preceding::a[starts-with(@href, 'http://') or starts-with(@href, 'https://')])+count(preceding::img)+8"/></xsl:template>
|
34
37
|
</xsl:stylesheet>
|
@@ -0,0 +1,148 @@
|
|
1
|
+
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
2
|
+
xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
|
3
|
+
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
4
|
+
xmlns:o="urn:schemas-microsoft-com:office:office"
|
5
|
+
xmlns:v="urn:schemas-microsoft-com:vml"
|
6
|
+
xmlns:WX="http://schemas.microsoft.com/office/word/2003/auxHint"
|
7
|
+
xmlns:aml="http://schemas.microsoft.com/aml/2001/core"
|
8
|
+
xmlns:w10="urn:schemas-microsoft-com:office:word"
|
9
|
+
xmlns:pkg="http://schemas.microsoft.com/office/2006/xmlPackage"
|
10
|
+
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
|
11
|
+
xmlns:ext="http://www.xmllab.net/wordml2html/ext"
|
12
|
+
xmlns:java="http://xml.apache.org/xalan/java"
|
13
|
+
xmlns:str="http://exslt.org/strings"
|
14
|
+
xmlns:func="http://exslt.org/functions"
|
15
|
+
xmlns:fn="http://www.w3.org/2005/xpath-functions"
|
16
|
+
version="1.0"
|
17
|
+
exclude-result-prefixes="java msxsl ext w o v WX aml w10"
|
18
|
+
extension-element-prefixes="func">
|
19
|
+
|
20
|
+
<!-- template as function used to return the file extension of an image. -->
|
21
|
+
<xsl:template name="image-extension">
|
22
|
+
<xsl:param name="data-filename" select="." />
|
23
|
+
<xsl:param name="source" select="." />
|
24
|
+
<xsl:variable name="filename">
|
25
|
+
<xsl:call-template name="image-name">
|
26
|
+
<xsl:with-param name="source" select="$source"/>
|
27
|
+
<xsl:with-param name="data-filename" select="$data-filename"/>
|
28
|
+
</xsl:call-template>
|
29
|
+
</xsl:variable>
|
30
|
+
<xsl:value-of select="substring-after($filename,'.')"/>
|
31
|
+
</xsl:template>
|
32
|
+
|
33
|
+
<!-- template as function used to return the name of an image. -->
|
34
|
+
<xsl:template name="image-name">
|
35
|
+
<xsl:param name="data-filename" select="." />
|
36
|
+
<xsl:param name="source" select="." />
|
37
|
+
<xsl:choose>
|
38
|
+
<xsl:when test="string-length($data-filename) > 0">
|
39
|
+
<xsl:value-of select="$data-filename"/>
|
40
|
+
</xsl:when>
|
41
|
+
<xsl:otherwise>
|
42
|
+
<xsl:call-template name="extract-filename-from-path">
|
43
|
+
<xsl:with-param name="path" select="$source"/>
|
44
|
+
</xsl:call-template>
|
45
|
+
</xsl:otherwise>
|
46
|
+
</xsl:choose>
|
47
|
+
</xsl:template>
|
48
|
+
|
49
|
+
<!-- template as function used to extract the filename from the image source. Can't use tokenize or other functions which return a fragment tree as xpath can't process them. -->
|
50
|
+
<xsl:template name="extract-filename-from-path">
|
51
|
+
<xsl:param name="path" select="." />
|
52
|
+
<xsl:choose>
|
53
|
+
<xsl:when test="not(contains($path, '/'))">
|
54
|
+
<xsl:value-of select="$path" />
|
55
|
+
</xsl:when>
|
56
|
+
<xsl:otherwise>
|
57
|
+
<xsl:call-template name="extract-filename-from-path">
|
58
|
+
<xsl:with-param name="path" select="substring-after($path, '/')" />
|
59
|
+
</xsl:call-template>
|
60
|
+
</xsl:otherwise>
|
61
|
+
</xsl:choose>
|
62
|
+
</xsl:template>
|
63
|
+
|
64
|
+
<!--
|
65
|
+
Returns the unqualified dimension from a length specification copied from:
|
66
|
+
http://docbook.sourceforge.net/release/xsl/1.76.1/doc/lib/length-magnitude.html
|
67
|
+
-->
|
68
|
+
|
69
|
+
<xsl:template name="length-magnitude">
|
70
|
+
<xsl:param name="length" select="'0pt'"></xsl:param>
|
71
|
+
|
72
|
+
<xsl:choose>
|
73
|
+
<xsl:when test="string-length($length) = 0"></xsl:when>
|
74
|
+
<xsl:when test="substring($length,1,1) = '0' or substring($length,1,1) = '1' or substring($length,1,1) = '2' or substring($length,1,1) = '3' or substring($length,1,1) = '4' or substring($length,1,1) = '5' or substring($length,1,1) = '6' or substring($length,1,1) = '7' or substring($length,1,1) = '8' or substring($length,1,1) = '9' or substring($length,1,1) = '.'">
|
75
|
+
<xsl:value-of select="substring($length,1,1)"></xsl:value-of>
|
76
|
+
<xsl:call-template name="length-magnitude">
|
77
|
+
<xsl:with-param name="length" select="substring($length,2)"></xsl:with-param>
|
78
|
+
</xsl:call-template>
|
79
|
+
</xsl:when>
|
80
|
+
</xsl:choose>
|
81
|
+
</xsl:template>
|
82
|
+
|
83
|
+
|
84
|
+
|
85
|
+
|
86
|
+
<!-- Convert em and pixel sizes to inches. Inspired by from:
|
87
|
+
http://docbook.sourceforge.net/release/xsl/1.76.1/doc/lib/length-in-points.html
|
88
|
+
EMU info from: https://startbigthinksmall.wordpress.com/2010/01/04/points-inches-and-emus-measuring-units-in-office-open-xml/
|
89
|
+
-->
|
90
|
+
<xsl:template name="length-in-emus">
|
91
|
+
<xsl:param name="length" select="'0px'"/>
|
92
|
+
<xsl:param name="em.size" select="6.02250006023"/>
|
93
|
+
<xsl:param name="pixels.per.inch" select="90"/>
|
94
|
+
<xsl:variable name="emus.per.inch" select="914400"/>
|
95
|
+
|
96
|
+
<xsl:variable name="magnitude">
|
97
|
+
<xsl:call-template name="length-magnitude">
|
98
|
+
<xsl:with-param name="length" select="$length"/>
|
99
|
+
</xsl:call-template>
|
100
|
+
</xsl:variable>
|
101
|
+
|
102
|
+
<xsl:variable name="units">
|
103
|
+
<xsl:value-of select="substring($length, string-length($magnitude)+1)"/>
|
104
|
+
</xsl:variable>
|
105
|
+
|
106
|
+
<xsl:variable name="inches">
|
107
|
+
<xsl:choose>
|
108
|
+
<xsl:when test="$units = 'px'">
|
109
|
+
<xsl:value-of select="$magnitude div $pixels.per.inch"/>
|
110
|
+
</xsl:when>
|
111
|
+
<xsl:when test="$units = 'em'">
|
112
|
+
<xsl:value-of select="$magnitude div $em.size"/>
|
113
|
+
</xsl:when>
|
114
|
+
<xsl:otherwise>
|
115
|
+
<xsl:message>
|
116
|
+
<xsl:text>Unrecognized unit of measure: </xsl:text>
|
117
|
+
<xsl:value-of select="$units"></xsl:value-of>
|
118
|
+
<xsl:text>.</xsl:text>
|
119
|
+
</xsl:message>
|
120
|
+
</xsl:otherwise>
|
121
|
+
</xsl:choose>
|
122
|
+
</xsl:variable>
|
123
|
+
|
124
|
+
<xsl:value-of select="$inches * $emus.per.inch"/>
|
125
|
+
</xsl:template>
|
126
|
+
|
127
|
+
<!-- template as function used to get the width or height of an image in points. -->
|
128
|
+
<xsl:template name="image-dimention">
|
129
|
+
<xsl:param name="style" />
|
130
|
+
<xsl:param name="data-value" />
|
131
|
+
<xsl:param name="type" />
|
132
|
+
|
133
|
+
<xsl:variable name="size">
|
134
|
+
<xsl:choose>
|
135
|
+
<xsl:when test="string-length($data-value) > 0">
|
136
|
+
<xsl:value-of select="$data-value" />
|
137
|
+
</xsl:when>
|
138
|
+
<xsl:when test="contains($style, concat($type,':'))">
|
139
|
+
<xsl:value-of select="translate(str:tokenize(substring-after($style, concat($type,':')), ';')[1],' 	
','')" />
|
140
|
+
</xsl:when>
|
141
|
+
<xsl:otherwise>1</xsl:otherwise>
|
142
|
+
</xsl:choose>
|
143
|
+
</xsl:variable>
|
144
|
+
<xsl:call-template name="length-in-emus">
|
145
|
+
<xsl:with-param name="length" select="$size"/>
|
146
|
+
</xsl:call-template>
|
147
|
+
</xsl:template>
|
148
|
+
</xsl:stylesheet>
|
@@ -0,0 +1,129 @@
|
|
1
|
+
<xsl:stylesheet xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas"
|
2
|
+
xmlns:mo="http://schemas.microsoft.com/office/mac/office/2008/main"
|
3
|
+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
4
|
+
xmlns:mv="urn:schemas-microsoft-com:mac:vml"
|
5
|
+
xmlns:o="urn:schemas-microsoft-com:office:office"
|
6
|
+
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
7
|
+
xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math"
|
8
|
+
xmlns:v="urn:schemas-microsoft-com:vml"
|
9
|
+
xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing"
|
10
|
+
xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"
|
11
|
+
xmlns:w10="urn:schemas-microsoft-com:office:word"
|
12
|
+
xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
|
13
|
+
xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml"
|
14
|
+
xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml"
|
15
|
+
xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup"
|
16
|
+
xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk"
|
17
|
+
xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml"
|
18
|
+
xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape"
|
19
|
+
xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
|
20
|
+
xmlns:a14="http://schemas.microsoft.com/office/drawing/2010/main"
|
21
|
+
xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture"
|
22
|
+
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
23
|
+
xmlns:WX="http://schemas.microsoft.com/office/word/2003/auxHint"
|
24
|
+
xmlns:aml="http://schemas.microsoft.com/aml/2001/core"
|
25
|
+
xmlns:pkg="http://schemas.microsoft.com/office/2006/xmlPackage"
|
26
|
+
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
|
27
|
+
xmlns:ext="http://www.xmllab.net/wordml2html/ext"
|
28
|
+
xmlns:java="http://xml.apache.org/xalan/java"
|
29
|
+
xmlns:str="http://exslt.org/strings"
|
30
|
+
xmlns:func="http://exslt.org/functions"
|
31
|
+
xmlns:fn="http://www.w3.org/2005/xpath-functions"
|
32
|
+
mc:Ignorable="w14 w15 wp14 a14"
|
33
|
+
version="1.0"
|
34
|
+
exclude-result-prefixes="java msxsl ext w o v WX aml w10"
|
35
|
+
extension-element-prefixes="func">
|
36
|
+
|
37
|
+
<xsl:include href="./image_functions.xslt"/>
|
38
|
+
|
39
|
+
<xsl:template match="img|body/img" name="image">
|
40
|
+
<w:drawing>
|
41
|
+
<wp:inline distT="0" distB="0" distL="0" distR="0">
|
42
|
+
<wp:extent>
|
43
|
+
<xsl:call-template name="image-dimention-attributes"/>
|
44
|
+
</wp:extent>
|
45
|
+
<wp:effectExtent l="0" t="0" r="0" b="0"/>
|
46
|
+
<wp:docPr>
|
47
|
+
<xsl:attribute name="id"><xsl:value-of select="count(preceding::img)+1" /></xsl:attribute>
|
48
|
+
<xsl:attribute name="name">Picture <xsl:value-of select="count(preceding::img)+1" /></xsl:attribute>
|
49
|
+
</wp:docPr>
|
50
|
+
<wp:cNvGraphicFramePr>
|
51
|
+
<a:graphicFrameLocks noChangeAspect="1"/>
|
52
|
+
</wp:cNvGraphicFramePr>
|
53
|
+
<a:graphic>
|
54
|
+
<a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
|
55
|
+
<pic:pic>
|
56
|
+
<pic:nvPicPr>
|
57
|
+
<pic:cNvPr>
|
58
|
+
<xsl:attribute name="id"><xsl:value-of select="count(preceding::img)+1" /></xsl:attribute>
|
59
|
+
<xsl:attribute name="title"><xsl:value-of select="@alt" /></xsl:attribute>
|
60
|
+
<xsl:attribute name="name"><xsl:call-template name="image-name">
|
61
|
+
<xsl:with-param name="source" select="@src"/>
|
62
|
+
<xsl:with-param name="data-filename" select="@data-filename"/>
|
63
|
+
</xsl:call-template></xsl:attribute>
|
64
|
+
</pic:cNvPr>
|
65
|
+
<pic:cNvPicPr/>
|
66
|
+
</pic:nvPicPr>
|
67
|
+
<pic:blipFill>
|
68
|
+
<a:blip>
|
69
|
+
<xsl:attribute name="r:embed"><xsl:call-template name="relationship-id"/></xsl:attribute>
|
70
|
+
<a:extLst>
|
71
|
+
<a:ext uri="{{28A0092B-C50C-407E-A947-70E740481C1C}}">
|
72
|
+
<a14:useLocalDpi val="0"/>
|
73
|
+
</a:ext>
|
74
|
+
</a:extLst>
|
75
|
+
</a:blip>
|
76
|
+
<a:stretch>
|
77
|
+
<a:fillRect/>
|
78
|
+
</a:stretch>
|
79
|
+
</pic:blipFill>
|
80
|
+
<pic:spPr>
|
81
|
+
<a:xfrm>
|
82
|
+
<a:off x="0" y="0"/>
|
83
|
+
<a:ext>
|
84
|
+
<xsl:call-template name="image-dimention-attributes"/>
|
85
|
+
</a:ext>
|
86
|
+
</a:xfrm>
|
87
|
+
<a:prstGeom prst="rect">
|
88
|
+
<a:avLst/>
|
89
|
+
</a:prstGeom>
|
90
|
+
</pic:spPr>
|
91
|
+
</pic:pic>
|
92
|
+
</a:graphicData>
|
93
|
+
</a:graphic>
|
94
|
+
</wp:inline>
|
95
|
+
</w:drawing>
|
96
|
+
</xsl:template>
|
97
|
+
|
98
|
+
<!--
|
99
|
+
A style specifiying the width and height is required to render an image correctly in word.
|
100
|
+
Styles can be provided either via data attributes:
|
101
|
+
img src="pathtosomeimage" data-width="200px" data-height="250px"
|
102
|
+
|
103
|
+
or via the html style attribute
|
104
|
+
img src="pathtosomeimage" style="width:150px;height:200px"
|
105
|
+
|
106
|
+
If both a style and data attributes are provided then data attributes take president.
|
107
|
+
e.g.
|
108
|
+
img src="pathtosomeimage" data-width="200em" style="width:150px;height:200px"
|
109
|
+
becomes: width:200em;height:200px
|
110
|
+
|
111
|
+
Note: All sizes must be in pixles or em
|
112
|
+
-->
|
113
|
+
<xsl:template name="image-dimention-attributes">
|
114
|
+
<xsl:attribute name="cx">
|
115
|
+
<xsl:call-template name="image-dimention">
|
116
|
+
<xsl:with-param name="style" select="@style" />
|
117
|
+
<xsl:with-param name="data-value" select="@data-width" />
|
118
|
+
<xsl:with-param name="type" select="'width'" />
|
119
|
+
</xsl:call-template>
|
120
|
+
</xsl:attribute>
|
121
|
+
<xsl:attribute name="cy">
|
122
|
+
<xsl:call-template name="image-dimention">
|
123
|
+
<xsl:with-param name="style" select="@style" />
|
124
|
+
<xsl:with-param name="data-value" select="@data-height" />
|
125
|
+
<xsl:with-param name="type" select="'height'" />
|
126
|
+
</xsl:call-template>
|
127
|
+
</xsl:attribute>
|
128
|
+
</xsl:template>
|
129
|
+
</xsl:stylesheet>
|
@@ -11,29 +11,30 @@
|
|
11
11
|
</xsl:template>
|
12
12
|
|
13
13
|
<!-- get first inline element of a sequence or text having block element siblings... -->
|
14
|
-
<xsl:template match="node()[self::a|self::b|self::
|
14
|
+
<xsl:template match="node()[self::a|self::b|self::i|self::s|self::span|self::sub|self::sup|self::u|self::text()][parent::div|parent::li|parent::td]">
|
15
15
|
<div>
|
16
16
|
<xsl:attribute name="class"><xsl:value-of select="../@class"/></xsl:attribute>
|
17
17
|
<xsl:attribute name="style"><xsl:value-of select="../@style"/></xsl:attribute>
|
18
18
|
<xsl:call-template name="inlineElement"/>
|
19
19
|
</div>
|
20
|
-
<xsl:apply-templates select="following-sibling::node()[not((self::a|self::b|self::
|
20
|
+
<xsl:apply-templates select="following-sibling::node()[not((self::a|self::b|self::i|self::s|self::span|self::sub|self::sup|self::u|self::text())[parent::div|parent::li|parent::td])][1]"/>
|
21
21
|
</xsl:template>
|
22
22
|
|
23
23
|
<!-- get following inline elements... -->
|
24
|
-
<xsl:template match="
|
25
|
-
|
26
|
-
|
|
27
|
-
|i[preceding-sibling::node()[1][self::a|self::b|self::
|
28
|
-
|
|
29
|
-
|span[preceding-sibling::node()[1][self::a|self::b|self::
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
24
|
+
<xsl:template match="
|
25
|
+
a[preceding-sibling::node()[1][self::a|self::b|self::i|self::s|self::span|self::sub|self::sup|self::u|self::text()]]
|
26
|
+
|b[preceding-sibling::node()[1][self::a|self::b|self::i|self::s|self::span|self::sub|self::sup|self::u|self::text()]]
|
27
|
+
|i[preceding-sibling::node()[1][self::a|self::b|self::i|self::s|self::span|self::sub|self::sup|self::u|self::text()]]
|
28
|
+
|s[preceding-sibling::node()[1][self::a|self::b|self::i|self::s|self::span|self::sub|self::sup|self::u|self::text()]]
|
29
|
+
|span[preceding-sibling::node()[1][self::a|self::b|self::i|self::s|self::span|self::sub|self::sup|self::u|self::text()]]
|
30
|
+
|sub[preceding-sibling::node()[1][self::a|self::b|self::i|self::s|self::span|self::sub|self::sup|self::u|self::text()]]
|
31
|
+
|sup[preceding-sibling::node()[1][self::a|self::b|self::i|self::s|self::span|self::sub|self::sup|self::u|self::text()]]
|
32
|
+
|u[preceding-sibling::node()[1][self::a|self::b|self::i|self::s|self::span|self::sub|self::sup|self::u|self::text()]]
|
33
|
+
|text()[preceding-sibling::node()[1][self::a|self::b|self::i|self::s|self::span|self::sub|self::sup|self::u|self::text()]]"
|
33
34
|
name="inlineElement">
|
34
35
|
<xsl:copy>
|
35
36
|
<xsl:apply-templates select="@*|node()[1]"/>
|
36
37
|
</xsl:copy>
|
37
|
-
<xsl:apply-templates select="following-sibling::node()[1][self::a|self::b|self::
|
38
|
+
<xsl:apply-templates select="following-sibling::node()[1][self::a|self::b|self::i|self::s|self::span|self::sub|self::sup|self::u|self::text()]"/>
|
38
39
|
</xsl:template>
|
39
40
|
</xsl:stylesheet>
|
@@ -17,9 +17,10 @@
|
|
17
17
|
exclude-result-prefixes="java msxsl ext w o v WX aml w10"
|
18
18
|
extension-element-prefixes="func">
|
19
19
|
|
20
|
+
|
20
21
|
<xsl:template match="a[starts-with(@href, 'http://') or starts-with(@href, 'https://')]" name="link">
|
21
22
|
<w:hyperlink>
|
22
|
-
<xsl:attribute name="r:id"
|
23
|
+
<xsl:attribute name="r:id"><xsl:call-template name="relationship-id"/></xsl:attribute>
|
23
24
|
<w:r>
|
24
25
|
<w:rPr>
|
25
26
|
<w:rStyle w:val="Hyperlink"/>
|
@@ -3,13 +3,45 @@
|
|
3
3
|
version="1.0">
|
4
4
|
<xsl:output method="xml" encoding="utf-8" omit-xml-declaration="yes" indent="yes" />
|
5
5
|
|
6
|
+
<xsl:include href="./image_functions.xslt"/>
|
7
|
+
<xsl:include href="./functions.xslt"/>
|
8
|
+
|
6
9
|
<xsl:template match="a[starts-with(@href, 'http://') or starts-with(@href, 'https://')]" priority="1">
|
7
10
|
<Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink" Target="{@href}" TargetMode="External">
|
8
|
-
<xsl:attribute name="Id"
|
11
|
+
<xsl:attribute name="Id"><xsl:call-template name="relationship-id"/></xsl:attribute>
|
12
|
+
</Relationship>
|
13
|
+
</xsl:template>
|
14
|
+
|
15
|
+
<!--
|
16
|
+
Images can either be embedded in the document or referenced via the external url.
|
17
|
+
By default images are embedded and a copy will be stored in the final zip folder.
|
18
|
+
If you want your images to be referenced externally (don't store the image files) then add data-external="true" to your image tag(s).
|
19
|
+
If you are embedding them images need a filename. You can either define one by passing the name and extension to data-filename or rely on the defaul which is the last part of the source url.
|
20
|
+
**Word files can be corrupted if an extension isn't present so if you are relying on the source url ensure that is has an extension.**
|
21
|
+
-->
|
22
|
+
<xsl:template match="img" priority="0">
|
23
|
+
<Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image">
|
24
|
+
<xsl:choose>
|
25
|
+
<xsl:when test="@data-external = 'true'">
|
26
|
+
<xsl:attribute name="Target"><xsl:value-of select="@src"/></xsl:attribute>
|
27
|
+
<xsl:attribute name="TargetMode">External</xsl:attribute>
|
28
|
+
</xsl:when>
|
29
|
+
|
30
|
+
<xsl:otherwise>
|
31
|
+
<xsl:attribute name="Target">media/image<xsl:value-of select="count(preceding::img)+1"/>.<xsl:call-template name="image-extension">
|
32
|
+
<xsl:with-param name="source" select="@src"/>
|
33
|
+
<xsl:with-param name="data-filename" select="@data-filename"/>
|
34
|
+
</xsl:call-template>
|
35
|
+
</xsl:attribute>
|
36
|
+
</xsl:otherwise>
|
37
|
+
</xsl:choose>
|
38
|
+
|
39
|
+
<xsl:attribute name="Id"><xsl:call-template name="relationship-id"/></xsl:attribute>
|
9
40
|
</Relationship>
|
10
41
|
</xsl:template>
|
11
42
|
|
12
43
|
<xsl:template match="/">
|
44
|
+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
13
45
|
<Relationships>
|
14
46
|
<Relationship Id="rId3" Type="http://schemas.microsoft.com/office/2007/relationships/stylesWithEffects" Target="stylesWithEffects.xml"/>
|
15
47
|
<Relationship Id="rId4" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings" Target="settings.xml"/>
|
@@ -152,6 +152,9 @@
|
|
152
152
|
<xsl:variable name="cell-bg" select="str:tokenize(substring-after(@class, 'ms-fill-'), ' ')[1]"/>
|
153
153
|
<w:shd w:val="clear" w:color="auto" w:fill="{$cell-bg}" />
|
154
154
|
</xsl:if>
|
155
|
+
<xsl:if test="@colspan > 1">
|
156
|
+
<w:gridSpan w:val="{@colspan}"/>
|
157
|
+
</xsl:if>
|
155
158
|
</w:tcPr>
|
156
159
|
</xsl:template>
|
157
160
|
|
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
|
+
version: 0.7.0
|
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:
|
11
|
+
date: 2017-11-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: actionpack
|
@@ -134,16 +134,21 @@ files:
|
|
134
134
|
- Rakefile
|
135
135
|
- bin/htmltoword
|
136
136
|
- lib/htmltoword.rb
|
137
|
-
- lib/htmltoword/action_controller.rb
|
138
137
|
- lib/htmltoword/configuration.rb
|
139
138
|
- lib/htmltoword/document.rb
|
140
|
-
- lib/htmltoword/
|
139
|
+
- lib/htmltoword/helpers/templates_helper.rb
|
140
|
+
- lib/htmltoword/helpers/xslt_helper.rb
|
141
|
+
- lib/htmltoword/railtie.rb
|
142
|
+
- lib/htmltoword/renderer.rb
|
141
143
|
- lib/htmltoword/templates/default.docx
|
142
144
|
- lib/htmltoword/version.rb
|
143
145
|
- lib/htmltoword/xslt/base.xslt
|
146
|
+
- lib/htmltoword/xslt/cleanup.xslt
|
144
147
|
- lib/htmltoword/xslt/extras.xslt
|
145
148
|
- lib/htmltoword/xslt/functions.xslt
|
146
149
|
- lib/htmltoword/xslt/htmltoword.xslt
|
150
|
+
- lib/htmltoword/xslt/image_functions.xslt
|
151
|
+
- lib/htmltoword/xslt/images.xslt
|
147
152
|
- lib/htmltoword/xslt/inline_elements.xslt
|
148
153
|
- lib/htmltoword/xslt/links.xslt
|
149
154
|
- lib/htmltoword/xslt/numbering.xslt
|
@@ -170,7 +175,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
170
175
|
version: '0'
|
171
176
|
requirements: []
|
172
177
|
rubyforge_project:
|
173
|
-
rubygems_version: 2.
|
178
|
+
rubygems_version: 2.6.14
|
174
179
|
signing_key:
|
175
180
|
specification_version: 4
|
176
181
|
summary: This simple gem allows you to create MS Word docx documents from simple html
|
@@ -1,54 +0,0 @@
|
|
1
|
-
require 'rack/test'
|
2
|
-
require 'action_controller'
|
3
|
-
|
4
|
-
unless defined? Mime::DOCX
|
5
|
-
Mime::Type.register 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', :docx
|
6
|
-
end
|
7
|
-
|
8
|
-
ActionController::Renderers.add :docx do |filename, options|
|
9
|
-
formats << :docx unless formats.include?(:docx) || Rails.version < '3.2'
|
10
|
-
|
11
|
-
# This is ugly and should be solved with regular file utils
|
12
|
-
if options[:template] == action_name
|
13
|
-
if filename =~ %r{^([^\/]+)/(.+)$}
|
14
|
-
options[:prefixes] ||= []
|
15
|
-
options[:prefixes].unshift $1
|
16
|
-
options[:template] = $2
|
17
|
-
else
|
18
|
-
options[:template] = filename
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
# disposition / filename
|
23
|
-
disposition = options.delete(:disposition) || 'attachment'
|
24
|
-
if file_name = options.delete(:filename)
|
25
|
-
file_name += '.docx' unless file_name =~ /\.docx$/
|
26
|
-
else
|
27
|
-
file_name = "#{filename.gsub(/^.*\//, '')}.docx"
|
28
|
-
end
|
29
|
-
|
30
|
-
# other properties
|
31
|
-
word_template = options.delete(:word_template) || nil
|
32
|
-
extras = options.delete(:extras) || false
|
33
|
-
# content will come from property content unless not specified
|
34
|
-
# then it will look for a template.
|
35
|
-
content = options.delete(:content) || render_to_string(options)
|
36
|
-
|
37
|
-
document = Htmltoword::Document.create(content, word_template, extras)
|
38
|
-
send_data document, filename: file_name, type: Mime::DOCX, disposition: disposition
|
39
|
-
end
|
40
|
-
|
41
|
-
if defined? ActionController::Responder
|
42
|
-
module ActionController
|
43
|
-
# For respond_with default
|
44
|
-
class Responder
|
45
|
-
def to_docx
|
46
|
-
if @default_response
|
47
|
-
@default_response.call(options)
|
48
|
-
else
|
49
|
-
controller.render({ docx: controller.action_name }.merge(options))
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
@@ -1,35 +0,0 @@
|
|
1
|
-
module Htmltoword
|
2
|
-
module HtmltowordHelper
|
3
|
-
|
4
|
-
def template_file template_file_name=nil
|
5
|
-
default_path = File.join(::Htmltoword.config.default_templates_path, 'default.docx')
|
6
|
-
template_path = template_file_name.present? ? File.join(::Htmltoword.config.custom_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
|