xsltgem 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+