xsltgem 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ db/*.sqlite3*
6
+ log/*.log
7
+ *.log
8
+ /tmp/
9
+ doc/
10
+ *.swp
11
+ *~
12
+ .project
13
+ .DS_Store
14
+ .idea
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in xsltgem.gemspec
4
+ gemspec
5
+ gem 'xml_serialization'
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+
5
+
6
+ desc 'Default: run unit tests.'
7
+ task :default => :test
8
+
9
+ desc 'Test the xslt_render plugin.'
10
+ Rake::TestTask.new(:test) do |t|
11
+ t.libs << 'lib'
12
+ t.test_files = 'test/*_test.rb'
13
+ t.verbose = true
14
+ end
@@ -0,0 +1,68 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <xsl:stylesheet version="1.0"
3
+ xmlns="http://www.w3.org/1999/xhtml"
4
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
5
+
6
+ <xsl:template mode="json" match="*[@type='date']">
7
+ <xsl:value-of select="translate(name(), '-', '_')" />
8
+ <xsl:text>: new Date("</xsl:text>
9
+ <xsl:value-of select="translate(., '-', '/')" />
10
+ <xsl:text>")</xsl:text>
11
+ </xsl:template>
12
+
13
+ <xsl:template mode="json" match="*[@type='datetime']">
14
+ <xsl:variable name="date"
15
+ select="translate(substring-before(., 'T'), '-', '/')"
16
+ />
17
+ <xsl:variable name="full-time" select="substring-after(., 'T')" />
18
+ <xsl:variable name="time">
19
+ <xsl:choose>
20
+ <xsl:when test="contains($full-time, '-')">
21
+ <xsl:value-of select="substring-before($full-time, '-')" />
22
+ </xsl:when>
23
+ <xsl:otherwise>
24
+ <xsl:value-of select="substring-before($full-time, '+')" />
25
+ </xsl:otherwise>
26
+ </xsl:choose>
27
+ </xsl:variable>
28
+ <xsl:variable name="time-zone"
29
+ select="substring-after($full-time,$time)"
30
+ />
31
+ <xsl:value-of select="translate(name(), '-', '_')" />
32
+ <xsl:text>: new Date("</xsl:text>
33
+ <xsl:value-of select="$date" />
34
+ <xsl:text> </xsl:text>
35
+ <xsl:value-of select="$time" />
36
+ <xsl:text> </xsl:text>
37
+ <xsl:value-of select="$time-zone" />
38
+ <xsl:text>")</xsl:text>
39
+ </xsl:template>
40
+
41
+ <xsl:template mode="json"
42
+ match="*[@type='integer']|*[@type='float']|*[@type='boolean']">
43
+ <xsl:value-of select="translate(name(), '-', '_')" />
44
+ <xsl:text>: </xsl:text>
45
+ <xsl:value-of select="." />
46
+ </xsl:template>
47
+
48
+ <xsl:template mode="json" priority="-1"
49
+ match="*[count(./text()) = 1][count(./*) = 0]">
50
+ <xsl:value-of select="translate(name(), '-', '_')" />
51
+ <xsl:text>: "</xsl:text>
52
+ <xsl:value-of select="." />
53
+ <xsl:text>"</xsl:text>
54
+ </xsl:template>
55
+
56
+ <xsl:template priority="-2" mode="json" match="*">
57
+ <xsl:value-of select="translate(name(), '-', '_')" />
58
+ <xsl:text>: {</xsl:text>
59
+ <xsl:for-each select="*[position()&lt;last()]">
60
+ <xsl:apply-templates mode="json" select="." />
61
+ <xsl:text>,
62
+ </xsl:text>
63
+ </xsl:for-each>
64
+ <xsl:apply-templates mode="json" select="*[last()]" />
65
+ <xsl:text>}</xsl:text>
66
+ </xsl:template>
67
+
68
+ </xsl:stylesheet>
@@ -0,0 +1,187 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!-- RAILS view helpers -->
3
+ <xsl:stylesheet version="1.0"
4
+ xmlns="http://www.w3.org/1999/xhtml"
5
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
6
+
7
+ <xsl:template name="link-to">
8
+ <xsl:param name="text" />
9
+ <xsl:param name="base" />
10
+ <a>
11
+ <xsl:attribute name="href">
12
+ <xsl:value-of select="/*/url-root" />/<xsl:value-of select="$base" />
13
+ </xsl:attribute>
14
+ <xsl:if test="/*/frame-target">
15
+ <xsl:attribute name="target"><xsl:value-of select="/*/frame-target" /></xsl:attribute>
16
+ </xsl:if>
17
+ <xsl:value-of select="$text" />
18
+ </a>
19
+ </xsl:template>
20
+
21
+ <xsl:template name="form-attributes">
22
+ <xsl:param name="method">post</xsl:param>
23
+ <xsl:param name="base" />
24
+ <xsl:attribute name="method"><xsl:value-of select="$method" /></xsl:attribute>
25
+ <xsl:attribute name="action">
26
+ <xsl:value-of select="/*/url-root" />/<xsl:value-of select="$base" />
27
+ </xsl:attribute>
28
+ </xsl:template>
29
+
30
+ <xsl:template name="img-path">
31
+ <xsl:param name="file" />
32
+ <xsl:value-of select="/*/url-root" />/images/<xsl:value-of select="$file" />
33
+ </xsl:template>
34
+
35
+ <xsl:template name="img-src">
36
+ <xsl:param name="file" />
37
+ <xsl:attribute name="src">
38
+ <xsl:call-template name="img-path">
39
+ <xsl:with-param name="file" select="$file" />
40
+ </xsl:call-template>
41
+ </xsl:attribute>
42
+ </xsl:template>
43
+
44
+ <xsl:template name="url">
45
+ <xsl:param name="base" />
46
+ <xsl:value-of select="/*/url-root" />/<xsl:value-of select="$base" />
47
+ </xsl:template>
48
+
49
+ <xsl:template name="button-to">
50
+ <xsl:param name="text" />
51
+ <xsl:param name="base" />
52
+ <form method="post" class="button-to">
53
+ <xsl:call-template name="form-attributes">
54
+ <xsl:with-param name="base"><xsl:value-of select="$base" /></xsl:with-param>
55
+ </xsl:call-template>
56
+ <div>
57
+ <input type="submit">
58
+ <xsl:attribute name="value" >
59
+ <xsl:value-of select="$text" />
60
+ </xsl:attribute>
61
+ </input>
62
+ </div>
63
+ </form>
64
+ </xsl:template>
65
+
66
+ <xsl:template name="javascript-body">
67
+ <xsl:param name="body" />
68
+ <script type="text/javascript"><xsl:text disable-output-escaping="yes">
69
+ // &lt;![CDATA[
70
+ </xsl:text><xsl:value-of select="$body" /><xsl:text disable-output-escaping="yes">
71
+ // ]]&gt;
72
+ </xsl:text></script>
73
+ </xsl:template>
74
+
75
+ <!-- TODO: salt the stylesheet and javascript links -->
76
+ <xsl:template match="stylesheet">
77
+ <xsl:call-template name="stylesheet">
78
+ <xsl:with-param name="sheet" select="." />
79
+ </xsl:call-template>
80
+ </xsl:template>
81
+
82
+ <xsl:template match="javascript|default-javascript">
83
+ <xsl:call-template name="javascript">
84
+ <xsl:with-param name="script" select="." />
85
+ </xsl:call-template>
86
+ </xsl:template>
87
+
88
+ <xsl:template name="stylesheet">
89
+ <xsl:param name="sheet" />
90
+ <link media="screen" rel="stylesheet" type="text/css">
91
+ <xsl:choose>
92
+ <xsl:when test="starts-with($sheet,'http')">
93
+ <xsl:attribute name="href"><xsl:value-of select="$sheet" /></xsl:attribute>
94
+ </xsl:when>
95
+ <xsl:otherwise>
96
+ <xsl:attribute name="href">
97
+ <xsl:value-of select="/*/url-root" />/stylesheets/<xsl:value-of select="$sheet" />
98
+ <xsl:if test="not(contains($sheet,'.css'))">
99
+ <xsl:text>.css</xsl:text>
100
+ </xsl:if>
101
+ </xsl:attribute>
102
+ </xsl:otherwise>
103
+ </xsl:choose>
104
+ </link>
105
+ </xsl:template>
106
+
107
+ <xsl:template name="javascript-src">
108
+ <xsl:param name="script" />
109
+ <xsl:attribute name="src">
110
+ <xsl:value-of select="/*/url-root" />/javascripts/<xsl:value-of select="$script" />
111
+ <xsl:if test="not(contains($script,'.js'))">
112
+ <xsl:text>.js</xsl:text>
113
+ </xsl:if>
114
+ </xsl:attribute>
115
+ </xsl:template>
116
+
117
+ <xsl:template name="javascript">
118
+ <xsl:param name="script">defaults</xsl:param>
119
+ <xsl:choose>
120
+ <xsl:when test="$script='defaults'">
121
+ <xsl:apply-templates select="../../default-javascripts/*" />
122
+ </xsl:when>
123
+ <xsl:otherwise>
124
+ <script type="text/javascript">
125
+ <xsl:call-template name="javascript-src">
126
+ <xsl:with-param name="script" select="$script" />
127
+ </xsl:call-template>
128
+ </script>
129
+ </xsl:otherwise>
130
+ </xsl:choose>
131
+ </xsl:template>
132
+
133
+ <xsl:template name="uri-delete-param">
134
+ <xsl:param name="param" />
135
+ <xsl:param name="base-uri" select="/*/request-uri" />
136
+ <xsl:variable name="param-equate" select="concat($param, '=')" />
137
+ <xsl:variable name="rest" select="substring-after(substring-after($base-uri, $param-equate), '&amp;')" />
138
+ <xsl:variable name="before" select="substring-before($base-uri, $param-equate)" />
139
+ <xsl:variable name="result" select="concat($before, $rest)" />
140
+
141
+ <xsl:choose>
142
+ <xsl:when test="not(contains($base-uri, $param-equate))">
143
+ <xsl:value-of select="$base-uri" />
144
+ </xsl:when>
145
+ <xsl:when test="substring-after($result, '?') = ''">
146
+ <xsl:value-of select="substring-before($result, '?')" />
147
+ </xsl:when>
148
+ <xsl:when test="substring($result, string-length($result)) = '&amp;'">
149
+ <xsl:value-of select="substring($result, 1, string-length($result) - 1)" />
150
+ </xsl:when>
151
+ <xsl:otherwise><xsl:value-of select="$result" /></xsl:otherwise>
152
+ </xsl:choose>
153
+ </xsl:template>
154
+
155
+ <xsl:template name="uri-attribute-set-param">
156
+ <xsl:param name="param" />
157
+ <xsl:param name="value" />
158
+ <xsl:param name="attribute">href</xsl:param>
159
+ <xsl:param name="base-uri" select="/*/request-uri" />
160
+
161
+ <xsl:variable name="param-equate" select="concat($param, '=')" />
162
+ <xsl:attribute name="{$attribute}">
163
+ <xsl:choose>
164
+ <xsl:when test="contains($base-uri, $param-equate)">
165
+ <xsl:variable name="rest" select="substring-after(substring-after($base-uri, $param-equate), '&amp;')" />
166
+ <xsl:value-of select="concat(substring-before($base-uri, $param-equate), $param-equate, $value)" />
167
+ <xsl:if test="$rest">
168
+ <xsl:value-of select="concat('&amp;', $rest)" />
169
+ </xsl:if>
170
+ </xsl:when>
171
+ <xsl:otherwise>
172
+ <xsl:variable name="separator">
173
+ <xsl:choose>
174
+ <xsl:when test="contains($base-uri,'?')">
175
+ <xsl:text>&amp;</xsl:text>
176
+ </xsl:when>
177
+ <xsl:otherwise>
178
+ <xsl:text>?</xsl:text>
179
+ </xsl:otherwise>
180
+ </xsl:choose>
181
+ </xsl:variable>
182
+ <xsl:value-of select="concat($base-uri, $separator, $param-equate, $value)" />
183
+ </xsl:otherwise>
184
+ </xsl:choose>
185
+ </xsl:attribute>
186
+ </xsl:template>
187
+ </xsl:stylesheet>
data/lib/xsltgem.rb ADDED
@@ -0,0 +1,128 @@
1
+ require "xsltgem/version"
2
+
3
+ module Xsltgem
4
+ require 'open3'
5
+ require 'pathname'
6
+ require 'rubygems'
7
+ require 'xml_serialization'
8
+
9
+ class XsltprocError < StandardError; end
10
+
11
+ module XSLTRender
12
+ attr_writer :xslt_root_dir
13
+
14
+ def instance_hash
15
+ hash = instance_variables.inject({}) do |vars, var|
16
+ key = var[1..-1]
17
+
18
+ # don't include "hidden" vars
19
+ value = instance_variable_get(var)
20
+ vars[key] = value unless '_' == key[0..0] or value.nil?
21
+ vars
22
+ end
23
+ # don't allow param keys that are not valid as XML tag names
24
+ hash['params'] = params.dup.delete_if {|(k,v)| k.to_s !~ /^[a-zA-Z][\w]*$/}
25
+ hash['flash'] = flash
26
+ hash['url_root'] = request.relative_url_root unless request.relative_url_root.blank?
27
+ hash['environment'] = RAILS_ENV
28
+ hash['default_javascripts'] = ActionView::Helpers::AssetTagHelper::JAVASCRIPT_DEFAULT_SOURCES
29
+ hash['timestamp'] = "#{Time.now.to_i}#{Time.now.tv_usec}"
30
+ hash['host'] = request.host
31
+ hash['request_uri'] = request.request_uri
32
+ hash
33
+ end
34
+
35
+ def page_xml(options={})
36
+ start = Time.now
37
+ options = {:root => 'page'}.merge options
38
+ vars = instance_hash
39
+ xml = vars.to_xml(:language => options[:language], :root => options[:root])
40
+ logger.info "XSLTRender.page_xml: #{Time.now - start}sec"
41
+ xml
42
+ end
43
+
44
+ def default_xslt_template
45
+ (Pathname.new(self.class.controller_name)+action_name).to_s
46
+ end
47
+
48
+ def xslt_root_dir=(value)
49
+ Pathname.new(value.to_s) unless value.kind_of? Pathname
50
+ end
51
+
52
+ # We put the xslt stylesheets in public so we could experiment
53
+ # with having the browser perform the xsl transformations.
54
+ def xslt_root_dir
55
+ @xslt_root_dir ||= Pathname.new(RAILS_ROOT)+'public'+'xslts'
56
+ end
57
+
58
+ XSLTPROC_ERRORS = {
59
+ 1 => "No argument",
60
+ 2 => "Too many parameters",
61
+ 3 => "Unknown option",
62
+ 4 => "Failed to parse the stylesheet",
63
+ 5 => "Error in the stylesheet",
64
+ 6 => "Error in one of the documents",
65
+ 7 => "Unsupported xsl:output method",
66
+ 8 => "String parameter contains both quote and double-quotes",
67
+ 9 => "Internal processing error",
68
+ 10 => "Processing was stopped by a terminating message",
69
+ 11 => "Could not write the result to the output file",
70
+ }
71
+
72
+ def html_from_xml(xslt_file_name, xml, params = nil)
73
+ params ||= {}
74
+ cmd_params = params.map do |k,v|
75
+ "--stringparam '#{k}' '#{v}'"
76
+ end.join(' ')
77
+
78
+ xslt_cmd_string = %Q{xsltproc #{cmd_params} #{xslt_file_name} -; echo "::$?" 1>&2}
79
+ xslt_cmd = {}
80
+
81
+ # scope out variables that will be used outside the 'cd'
82
+ result = errors = error_code = nil
83
+
84
+ Open3.popen3(xslt_cmd_string) { |xslt_cmd|
85
+ begin
86
+ xslt_cmd[:in].write xml
87
+ rescue Errno::EPIPE
88
+ else
89
+ xslt_cmd[:in].close
90
+ result = xslt_cmd[:out].read
91
+ end
92
+
93
+ errors, error_code_string = xslt_cmd[:error].read.match(/\A(.*)\s*::(\d+)\s*\z/m).captures
94
+ error_code = error_code_string.to_i
95
+ }
96
+
97
+ unless 0 == error_code
98
+ raise XsltprocError, "xsltproc processing of '#{xslt_file_name}' failed: #{XSLTPROC_ERRORS[error_code]} (#{error_code})\n#{errors}"
99
+ end
100
+ result
101
+ end
102
+
103
+ def xslt_render(options = {})
104
+ options = {:root => 'page'}.merge(options)
105
+ template = options[:template] || default_xslt_template
106
+
107
+ full_template_path = nil
108
+ ["", ".xsl", ".html.xsl"].each do |ext|
109
+ if(full_path = (xslt_root_dir+(template + ext))).exist?
110
+ full_template_path = full_path
111
+ end
112
+ end
113
+
114
+ raise IOError, "XSLT template '#{template}' is missing" unless full_template_path
115
+
116
+ xml = options[:xml] || page_xml(options)
117
+ html = html_from_xml(full_template_path, xml, options[:params])
118
+
119
+ if options[:language]
120
+ plugin_root = (Pathname.new(__FILE__).dirname + '..').expand_path
121
+ term_path = TermLanguage.new(options[:language]).translation_file
122
+ i18n_path = plugin_root+'lib'+'xslts'+'i18n.xsl'
123
+ html = html_from_xml(i18n_path, html, 'termfile' => term_path)
124
+ end
125
+ render :text => html
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,3 @@
1
+ module Xsltgem
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,124 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!--This stylesheet is used internally by the xslt plugin to do internationalization.-->
3
+ <xsl:stylesheet version="1.0"
4
+ xmlns="http://www.w3.org/1999/xhtml"
5
+ xmlns:xhtml="http://www.w3.org/1999/xhtml"
6
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
7
+ xmlns:tr="http://www.hotelsearch.com/XMLSchema/2007/translation"
8
+ exclude-result-prefixes="tr">
9
+
10
+ <xsl:output indent="yes" method="xml" encoding="UTF-8"
11
+ doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"
12
+ doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
13
+ />
14
+
15
+ <xsl:param name="termfile" />
16
+
17
+ <xsl:variable name="termdoc" select="document($termfile)" />
18
+
19
+ <xsl:key name="terms" match="term" use="@name" />
20
+
21
+ <xsl:variable name="language">
22
+ <xsl:for-each select="$termdoc">
23
+ <xsl:value-of select="/terms/@lang" />
24
+ </xsl:for-each>
25
+ </xsl:variable>
26
+
27
+ <xsl:template match="/">
28
+ <xsl:apply-templates select="*" />
29
+ </xsl:template>
30
+
31
+ <xsl:template match="tr:term">
32
+ <xsl:choose>
33
+ <xsl:when test="count(*)=0 and count(text())=1">
34
+ <xsl:variable name="term"><xsl:value-of select="text()" /></xsl:variable>
35
+ <xsl:variable name="pass-thru"><xsl:value-of select="@pass-thru" /></xsl:variable>
36
+ <xsl:for-each select="$termdoc">
37
+ <xsl:variable name="translation" select="key('terms', $term)" />
38
+ <xsl:choose>
39
+ <xsl:when test="$translation">
40
+ <xsl:value-of select="$translation" />
41
+ </xsl:when>
42
+ <xsl:when test="$pass-thru = 'true'">
43
+ <xsl:value-of select="$term" />
44
+ </xsl:when>
45
+ </xsl:choose>
46
+ </xsl:for-each>
47
+ </xsl:when>
48
+ <xsl:otherwise>
49
+ <xsl:copy>
50
+ <xsl:apply-templates select="*|@*|text()" />
51
+ </xsl:copy>
52
+ </xsl:otherwise>
53
+ </xsl:choose>
54
+ </xsl:template>
55
+
56
+ <xsl:template match="@*[starts-with(.,'tr:')]">
57
+ <xsl:variable name="term"><xsl:value-of select="substring(.,4)" /></xsl:variable>
58
+ <xsl:variable name="attrName"><xsl:value-of select="name()" /></xsl:variable>
59
+ <xsl:for-each select="$termdoc">
60
+ <xsl:attribute name="{$attrName}">
61
+ <xsl:value-of select="key('terms', $term)" />
62
+ </xsl:attribute>
63
+ </xsl:for-each>
64
+ </xsl:template>
65
+
66
+ <xsl:template match="tr:ordered">
67
+ <xsl:variable name="before"><xsl:value-of select="@before" /></xsl:variable>
68
+ <xsl:variable name="text"><xsl:value-of select="text()" /></xsl:variable>
69
+ <xsl:variable name="after"><xsl:value-of select="@after" /></xsl:variable>
70
+ <xsl:variable name="before-translation">
71
+ <xsl:for-each select="$termdoc">
72
+ <xsl:value-of select="key('terms', $before)" />
73
+ </xsl:for-each>
74
+ </xsl:variable>
75
+ <xsl:variable name="after-translation">
76
+ <xsl:for-each select="$termdoc">
77
+ <xsl:value-of select="key('terms', $after)" />
78
+ </xsl:for-each>
79
+ </xsl:variable>
80
+ <xsl:choose>
81
+ <xsl:when test="$language = 'ja'">
82
+ <xsl:value-of select="$after-translation" />
83
+ <xsl:value-of select="$text" />
84
+ <xsl:value-of select="$before-translation" />
85
+ </xsl:when>
86
+ <xsl:otherwise>
87
+ <xsl:if test="$before-translation != ''">
88
+ <xsl:value-of select="$before-translation" />
89
+ <xsl:text> </xsl:text>
90
+ </xsl:if>
91
+ <xsl:value-of select="$text" />
92
+ <xsl:if test="$after-translation != ''">
93
+ <xsl:text> </xsl:text>
94
+ <xsl:value-of select="$after-translation" />
95
+ </xsl:if>
96
+ </xsl:otherwise>
97
+ </xsl:choose>
98
+ </xsl:template>
99
+
100
+ <xsl:template match="xhtml:div|xhtml:script|xhtml:span">
101
+ <xsl:copy>
102
+ <xsl:apply-templates select="@*" />
103
+ <xsl:choose>
104
+ <xsl:when test="count(*)=0 and count(text())=0">
105
+ <xsl:text> </xsl:text>
106
+ </xsl:when>
107
+ <xsl:otherwise>
108
+ <xsl:apply-templates select="*|text()" />
109
+ </xsl:otherwise>
110
+ </xsl:choose>
111
+ </xsl:copy>
112
+ </xsl:template>
113
+
114
+ <xsl:template match="*">
115
+ <xsl:copy>
116
+ <xsl:apply-templates select="*|@*|text()" />
117
+ </xsl:copy>
118
+ </xsl:template>
119
+
120
+ <xsl:template match="@*">
121
+ <xsl:copy />
122
+ </xsl:template>
123
+ </xsl:stylesheet>
124
+