saxon-rb 0.4.0-java → 0.7.2-java
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.
- checksums.yaml +4 -4
- data/.circleci/config.yml +429 -42
- data/.ruby-version +1 -1
- data/.yardopts +1 -0
- data/Gemfile +2 -2
- data/README.md +358 -10
- data/Rakefile +237 -7
- data/docs/templates/plugin.rb +73 -0
- data/lib/net/sf/saxon/Saxon-HE/{9.9.1-5/Saxon-HE-9.9.1-5.jar → 9.9.1-6/Saxon-HE-9.9.1-6.jar} +0 -0
- data/lib/saxon-rb.rb +0 -0
- data/lib/{saxon_jars.rb → saxon-rb_jars.rb} +2 -2
- data/lib/saxon.rb +13 -0
- data/lib/saxon/axis_iterator.rb +8 -1
- data/lib/saxon/configuration.rb +16 -13
- data/lib/saxon/document_builder.rb +216 -5
- data/lib/saxon/feature_flags.rb +11 -0
- data/lib/saxon/feature_flags/errors.rb +8 -0
- data/lib/saxon/feature_flags/helpers.rb +15 -0
- data/lib/saxon/feature_flags/version.rb +100 -0
- data/lib/saxon/item_type.rb +129 -89
- data/lib/saxon/item_type/lexical_string_conversion.rb +214 -59
- data/lib/saxon/item_type/value_to_ruby.rb +25 -0
- data/lib/saxon/loader.rb +6 -1
- data/lib/saxon/nokogiri.rb +78 -0
- data/lib/saxon/occurrence_indicator.rb +32 -3
- data/lib/saxon/processor.rb +50 -5
- data/lib/saxon/qname.rb +37 -2
- data/lib/saxon/s9api.rb +5 -0
- data/lib/saxon/sequence_type.rb +131 -0
- data/lib/saxon/serializer.rb +3 -137
- data/lib/saxon/serializer/destination.rb +80 -0
- data/lib/saxon/serializer/object.rb +93 -0
- data/lib/saxon/serializer/output_properties.rb +83 -0
- data/lib/saxon/source.rb +207 -71
- data/lib/saxon/version.rb +7 -1
- data/lib/saxon/version/library.rb +89 -0
- data/lib/saxon/xdm.rb +7 -0
- data/lib/saxon/xdm/array.rb +16 -0
- data/lib/saxon/xdm/atomic_value.rb +10 -2
- data/lib/saxon/xdm/empty_sequence.rb +13 -0
- data/lib/saxon/xdm/external_object.rb +1 -0
- data/lib/saxon/xdm/function_item.rb +1 -0
- data/lib/saxon/xdm/item.rb +7 -0
- data/lib/saxon/xdm/map.rb +38 -0
- data/lib/saxon/xdm/node.rb +50 -1
- data/lib/saxon/xdm/sequence_like.rb +15 -0
- data/lib/saxon/xdm/value.rb +21 -5
- data/lib/saxon/xpath.rb +9 -0
- data/lib/saxon/xpath/compiler.rb +37 -2
- data/lib/saxon/xpath/executable.rb +53 -28
- data/lib/saxon/xpath/static_context.rb +25 -40
- data/lib/saxon/xpath/variable_declaration.rb +16 -49
- data/lib/saxon/xslt.rb +12 -0
- data/lib/saxon/xslt/compiler.rb +75 -6
- data/lib/saxon/xslt/evaluation_context.rb +30 -4
- data/lib/saxon/xslt/executable.rb +206 -29
- data/lib/saxon/xslt/invocation.rb +97 -0
- data/saxon-rb.gemspec +3 -3
- metadata +22 -10
- data/saxon.gemspec +0 -30
@@ -3,6 +3,7 @@ require_relative '../qname'
|
|
3
3
|
|
4
4
|
module Saxon
|
5
5
|
module XSLT
|
6
|
+
# @api private
|
6
7
|
# Represents the evaluation context for an XSLT compiler, and stylesheets
|
7
8
|
# compiled using one. {EvaluationContext}s are immutable.
|
8
9
|
class EvaluationContext
|
@@ -47,11 +48,12 @@ module Saxon
|
|
47
48
|
end
|
48
49
|
end
|
49
50
|
|
51
|
+
# @api public
|
50
52
|
# Provides the hooks for constructing a {EvaluationContext} with a DSL.
|
51
|
-
# @api private
|
52
53
|
class DSL
|
53
54
|
include Common
|
54
55
|
|
56
|
+
# @api private
|
55
57
|
# Create an instance based on the args hash, and execute the passed in Proc/lambda against it using <tt>#instance_exec</tt> and return a
|
56
58
|
# new {EvaluationContext} with the results
|
57
59
|
# @param block [Proc] a Proc/lambda (or <tt>to_proc</tt>'d containing DSL calls
|
@@ -130,6 +132,7 @@ module Saxon
|
|
130
132
|
|
131
133
|
include Common
|
132
134
|
|
135
|
+
# @api private
|
133
136
|
# Executes the Proc/lambda passed in with a new instance of
|
134
137
|
# {EvaluationContext} as <tt>self</tt>, allowing the DSL methods to be
|
135
138
|
# called in a DSL-ish way
|
@@ -140,23 +143,46 @@ module Saxon
|
|
140
143
|
DSL.define(block)
|
141
144
|
end
|
142
145
|
|
143
|
-
attr_reader :default_collation, :static_parameters, :global_parameters, :initial_template_parameters, :initial_template_tunnel_parameters
|
144
146
|
|
147
|
+
# @return [String] The default collation URI as a String
|
148
|
+
attr_reader :default_collation
|
149
|
+
# @return [Hash<Saxon::QName => Saxon::XDM::Value>] All the static parameters
|
150
|
+
attr_reader :static_parameters
|
151
|
+
# @return [Hash<Saxon::QName => Saxon::XDM::Value>] All the global parameters
|
152
|
+
attr_reader :global_parameters
|
153
|
+
# @return [Hash<Saxon::QName => Saxon::XDM::Value>] All the initial template parameters
|
154
|
+
attr_reader :initial_template_parameters
|
155
|
+
# @return [Hash<Saxon::QName => Saxon::XDM::Value>] All the initial template parameters with tunnelling = "yes"
|
156
|
+
attr_reader :initial_template_tunnel_parameters
|
157
|
+
|
158
|
+
# @api private
|
159
|
+
# When passed a Proc, create a new EvaluationContext based on this one, with the same DSL available as in {.define}.
|
160
|
+
#
|
161
|
+
# When passed {nil}, simply return the EvaluationContext unaltered.
|
145
162
|
def define(block)
|
146
163
|
block.nil? ? self : DSL.define(block, args_hash)
|
147
164
|
end
|
148
165
|
end
|
149
166
|
|
167
|
+
# Error raised when a global and static parameter of the same name are
|
168
|
+
# declared
|
150
169
|
class GlobalAndStaticParameterClashError < StandardError
|
151
170
|
end
|
152
171
|
|
172
|
+
# parameter shorthand name/value-to-full QName/XDM::Value helper module
|
153
173
|
module ParameterHelper
|
174
|
+
# process shorthand parameter hash into fully-qualified QName / Value hash
|
175
|
+
# @param parameters [Hash<String, Saxon::QName => Object>]
|
176
|
+
# @return [Hash<Saxon::QName => Saxon::XDM::Value>]
|
177
|
+
# @see Saxon::QName.resolve() for more about the QName resolution process
|
178
|
+
# @see Saxon::XDM.Value() for more about the conversion of Object into XDM Values
|
154
179
|
def self.process_parameters(parameters)
|
155
|
-
|
180
|
+
parameters.map { |qname, value|
|
156
181
|
[Saxon::QName.resolve(qname), Saxon::XDM.Value(value)]
|
157
|
-
}
|
182
|
+
}.to_h
|
158
183
|
end
|
159
184
|
|
185
|
+
# generate Java Map from fully qualified parameter hash
|
160
186
|
def self.to_java(parameters)
|
161
187
|
Hash[parameters.map { |k,v| [k.to_java, v.to_java] }].to_java
|
162
188
|
end
|
@@ -1,14 +1,60 @@
|
|
1
1
|
require 'forwardable'
|
2
2
|
require_relative 'evaluation_context'
|
3
|
+
require_relative 'invocation'
|
3
4
|
require_relative '../serializer'
|
4
5
|
require_relative '../xdm'
|
5
6
|
require_relative '../qname'
|
7
|
+
require_relative '../feature_flags'
|
6
8
|
|
7
9
|
module Saxon
|
8
10
|
module XSLT
|
9
11
|
# Represents a compiled XSLT stylesheet ready to be executed
|
12
|
+
#
|
13
|
+
# Once you have a compiled stylesheet, then it can be executed against a
|
14
|
+
# source document in a variety of ways.
|
15
|
+
#
|
16
|
+
# First, you can use the traditional *apply templates* ,method, which was
|
17
|
+
# the only way in XSLT 1.
|
18
|
+
#
|
19
|
+
# input = Saxon::Source.create('input.xml')
|
20
|
+
# result = xslt.apply_templates(input)
|
21
|
+
#
|
22
|
+
# Next, you can call a specific named template (new in XSLT 2).
|
23
|
+
#
|
24
|
+
# result = xslt.call_template('template-name')
|
25
|
+
#
|
26
|
+
# Note that there's no input document here. If your XSLT needs a global
|
27
|
+
# context item set when you invoke it via a named template, then you can do
|
28
|
+
# that, too:
|
29
|
+
#
|
30
|
+
# input = processor.XML('input.xml')
|
31
|
+
# result = xslt.call_template('template-name', {
|
32
|
+
# global_context_item: input
|
33
|
+
# })
|
34
|
+
#
|
35
|
+
# Global and initial template parameters can be set at compiler creation
|
36
|
+
# time, compile time, or execution time.
|
37
|
+
#
|
38
|
+
# Initial template parameters relate to parameters passed to the *first*
|
39
|
+
# template run (either the first template matched when called with
|
40
|
+
# {Executable#apply_templates}, or the named template called with
|
41
|
+
# {Executable#call_template}).
|
42
|
+
#
|
43
|
+
# <b>Initial template parameters</b> are essentially implied +<xsl:with-parameter
|
44
|
+
# tunnel="no">+ elements. <b>Initial template tunnel parameters</b> are implied
|
45
|
+
# +<xsl:with-parameter tunnel="yes">+ elements.
|
46
|
+
#
|
47
|
+
# xslt.apply_templates(input, {
|
48
|
+
# global_parameters: {'param' => 'global value'},
|
49
|
+
# initial_template_parameters: {'param' => 'other value'},
|
50
|
+
# initial_template_tunnel_parameters: {'param' => 'tunnel value'}
|
51
|
+
# })
|
52
|
+
#
|
53
|
+
# Remember that if you need to use a parameter name which uses a namespace
|
54
|
+
# prefix, you must use an explicit {Saxon::QName} to refer to it.
|
10
55
|
class Executable
|
11
56
|
extend Forwardable
|
57
|
+
extend Saxon::FeatureFlags::Helpers
|
12
58
|
|
13
59
|
attr_reader :evaluation_context
|
14
60
|
private :evaluation_context
|
@@ -24,16 +70,111 @@ module Saxon
|
|
24
70
|
|
25
71
|
def_delegators :evaluation_context, :global_parameters, :initial_template_parameters, :initial_template_tunnel_parameters
|
26
72
|
|
73
|
+
# Run the XSLT by applying templates against the provided {Saxon::Source}
|
74
|
+
# or {Saxon::XDM::Node}.
|
75
|
+
#
|
76
|
+
# @note Any {QName}s supplied as strings MUST be resolvable as a QName
|
77
|
+
# without extra information, so they must be prefix-less (so, 'name', and
|
78
|
+
# never 'ns:name')
|
79
|
+
#
|
80
|
+
# @param source [Saxon::Source, Saxon::XDM::Node] the Source or Node that
|
81
|
+
# will be used as the global context item
|
82
|
+
# @param opts [Hash] a hash of options for invoking the transformation
|
83
|
+
# @option opts [Boolean] :raw (false) Whether the transformation should be
|
84
|
+
# executed 'raw', because it is expected to return a simple XDM Value
|
85
|
+
# (like a number, or plain text) and not an XML document.
|
86
|
+
# @option opts [String, Saxon::QName] :mode The initial mode to use when
|
87
|
+
# processing starts.
|
88
|
+
# @option opts [Hash<String, Saxon::QName => Object>] :global_parameters
|
89
|
+
# Additional global parameters to set. Setting already-defined
|
90
|
+
# parameters will replace their value for this invocation of the XSLT
|
91
|
+
# only, it won't affect the {XSLT::Compiler}'s context.
|
92
|
+
# @option opts [Hash<String, Saxon::QName => Object>]
|
93
|
+
# :initial_template_parameters Additional parameters to pass to the
|
94
|
+
# first template matched. Setting already-defined parameters will
|
95
|
+
# replace their value for this invocation of the XSLT only, it won't
|
96
|
+
# affect the {XSLT::Compiler}'s context.
|
97
|
+
# @option opts [Hash<String, Saxon::QName => Object>]
|
98
|
+
# :initial_template_tunnel_parameters Additional tunnelling parameters
|
99
|
+
# to pass to the first template matched. Setting already-defined
|
100
|
+
# parameters will replace their value for this invocation of the XSLT
|
101
|
+
# only, it won't affect the {XSLT::Compiler}'s context.
|
102
|
+
# @return [Saxon::XSLT::Invocation] the transformation result
|
27
103
|
def apply_templates(source, opts = {})
|
28
104
|
transformation(opts).apply_templates(source)
|
29
105
|
end
|
30
106
|
|
31
|
-
|
107
|
+
# Run the XSLT by calling the named template.
|
108
|
+
#
|
109
|
+
# @note Any {QName}s supplied as Strings (e.g. for the template name)
|
110
|
+
# MUST be resolvable as a QName without extra information, so they must be
|
111
|
+
# prefix-less (so, 'name', and never 'ns:name')
|
112
|
+
#
|
113
|
+
# @param template_name [String, Saxon::QName, nil] the name of the
|
114
|
+
# template to be invoked. Passing +nil+ will invoke the default named
|
115
|
+
# template (+xsl:default-template+)
|
116
|
+
# @param opts [Hash] a hash of options for invoking the transformation
|
117
|
+
# @option opts [Boolean] :raw (false) Whether the transformation should be
|
118
|
+
# executed 'raw', because it is expected to return a simple XDM Value
|
119
|
+
# (like a number, or plain text) and not an XML document.
|
120
|
+
# @option opts [String, Saxon::QName] :mode The name of the initial mode
|
121
|
+
# to use when processing starts.
|
122
|
+
# @option opts [Hash<String, Saxon::QName => Object>] :global_parameters
|
123
|
+
# Additional global parameters to set. Setting already-defined
|
124
|
+
# parameters will replace their value for this invocation of the XSLT
|
125
|
+
# only, it won't affect the {XSLT::Compiler}'s context.
|
126
|
+
# @option opts [Hash<String, Saxon::QName => Object>]
|
127
|
+
# :initial_template_parameters Additional parameters to pass to the
|
128
|
+
# first template matched. Setting already-defined parameters will
|
129
|
+
# replace their value for this invocation of the XSLT only, it won't
|
130
|
+
# affect the {XSLT::Compiler}'s context.
|
131
|
+
# @option opts [Hash<String, Saxon::QName => Object>]
|
132
|
+
# :initial_template_tunnel_parameters Additional tunnelling parameters
|
133
|
+
# to pass to the first template matched. Setting already-defined
|
134
|
+
# parameters will replace their value for this invocation of the XSLT
|
135
|
+
# only, it won't affect the {XSLT::Compiler}'s context.
|
136
|
+
# @return [Saxon::XSLT::Invocation] the transformation result
|
137
|
+
def call_template(template_name = nil, opts = {})
|
32
138
|
transformation(opts).call_template(template_name)
|
33
139
|
end
|
34
140
|
|
141
|
+
# Invoke a named function in the XSLT.
|
142
|
+
#
|
143
|
+
# @note Function name {QName}s have to have prefixes, so they can't be
|
144
|
+
# supplied as {::String}s. Any other {QName}s supplied as {::String}s (e.g.
|
145
|
+
# for the template name) MUST be resolvable as a QName without extra
|
146
|
+
# information, so they must be prefix-less (so, 'name', and never
|
147
|
+
# 'ns:name')
|
148
|
+
# @note the function you're calling needs to be have been defined with
|
149
|
+
# +visibility="public"+ or +visibility="final"+
|
150
|
+
#
|
151
|
+
# @param function_name [Saxon::QName] the name of the function to be
|
152
|
+
# invoked.
|
153
|
+
# @param opts [Hash] a hash of options for invoking the transformation
|
154
|
+
# @option opts [Boolean] :raw (false) Whether the transformation should be
|
155
|
+
# executed 'raw', because it is expected to return a simple XDM Value
|
156
|
+
# (like a number, or plain text) and not an XML document.
|
157
|
+
# @option opts [Hash<String, Saxon::QName => Object>] :global_parameters
|
158
|
+
# Additional global parameters to set. Setting already-defined
|
159
|
+
# parameters will replace their value for this invocation of the XSLT
|
160
|
+
# only, it won't affect the {XSLT::Compiler}'s context.
|
161
|
+
# @return [Saxon::XSLT::Invocation] the transformation result
|
162
|
+
def call_function(function_name, opts = {})
|
163
|
+
args = opts.fetch(:args, [])
|
164
|
+
transformation(opts.reject { |k, v| k == :args }).call_function(function_name, args)
|
165
|
+
end
|
166
|
+
|
167
|
+
# Create a {Serializer::Object} configured using the options that were set
|
168
|
+
# by +<xsl:output>+.
|
169
|
+
#
|
170
|
+
# @return [Saxon::Serializer::Object] the Serializer
|
171
|
+
def serializer
|
172
|
+
Saxon::Serializer::Object.new(@s9_xslt_executable.load30.newSerializer)
|
173
|
+
end
|
174
|
+
requires_saxon_version :serializer, '>= 9.9'
|
175
|
+
|
35
176
|
# @return [net.sf.saxon.s9api.XsltExecutable] the underlying Saxon
|
36
|
-
#
|
177
|
+
# +XsltExecutable+
|
37
178
|
def to_java
|
38
179
|
@s9_xslt_executable
|
39
180
|
end
|
@@ -69,22 +210,23 @@ module Saxon
|
|
69
210
|
end
|
70
211
|
end
|
71
212
|
|
72
|
-
|
73
|
-
|
213
|
+
# @api private
|
214
|
+
# Represents a loaded XSLT transformation ready to be applied against a
|
215
|
+
# context node.
|
216
|
+
class Transformation
|
217
|
+
# A list of valid option names for the transform
|
218
|
+
VALID_OPTS = [:raw, :mode, :global_context_item, :global_parameters, :initial_template_parameters, :initial_template_tunnel_parameters]
|
74
219
|
|
75
|
-
|
76
|
-
|
77
|
-
end
|
220
|
+
attr_reader :s9_transformer, :opts
|
221
|
+
private :s9_transformer, :opts
|
78
222
|
|
79
|
-
|
80
|
-
|
81
|
-
|
223
|
+
# Return the default initial template namne for XSLT 3 named-template invocation
|
224
|
+
# @return [Saxon::QName] the default initial template QName
|
225
|
+
def self.default_initial_template
|
226
|
+
@default_initial_template ||= Saxon::QName.clark('{http://www.w3.org/1999/XSL/Transform}initial-template')
|
82
227
|
end
|
83
|
-
end
|
84
|
-
|
85
|
-
class Transformation
|
86
|
-
attr_reader :s9_transformer, :opts
|
87
228
|
|
229
|
+
# @api private
|
88
230
|
def initialize(args)
|
89
231
|
@s9_transformer = args.fetch(:s9_transformer)
|
90
232
|
@destination = args.fetch(:destination, nil)
|
@@ -94,36 +236,54 @@ module Saxon
|
|
94
236
|
@raw = false
|
95
237
|
end
|
96
238
|
|
239
|
+
# Apply templates to Source, using all the context set up when we were
|
240
|
+
# created.
|
97
241
|
def apply_templates(source)
|
98
|
-
|
242
|
+
transformation_invocation(:applyTemplates, source.to_java)
|
99
243
|
end
|
100
244
|
|
245
|
+
# Call the named template, using all the context set up when we were
|
246
|
+
# created.
|
101
247
|
def call_template(template_name)
|
102
|
-
|
248
|
+
transformation_invocation(:callTemplate, resolve_template_name(template_name))
|
249
|
+
end
|
250
|
+
|
251
|
+
# Call the named function, using all the context set up when we were
|
252
|
+
# created.
|
253
|
+
def call_function(function_name, args)
|
254
|
+
function_name = Saxon::QName.resolve(function_name).to_java
|
255
|
+
transformation_invocation(:callFunction, function_name, function_args(args))
|
103
256
|
end
|
104
257
|
|
105
258
|
private
|
106
259
|
|
107
|
-
def
|
260
|
+
def transformation_invocation(invocation_method, *invocation_args)
|
108
261
|
set_opts!
|
109
|
-
|
110
|
-
Result.new(result_xdm_value(s9_transformer.send(*transformer_args)), s9_transformer)
|
262
|
+
XSLT::Invocation.new(s9_transformer, invocation_lambda(invocation_method, invocation_args), raw?)
|
111
263
|
end
|
112
264
|
|
113
|
-
def
|
114
|
-
|
115
|
-
|
116
|
-
|
265
|
+
def invocation_lambda(invocation_method, invocation_args)
|
266
|
+
->(destination) {
|
267
|
+
if destination.nil?
|
268
|
+
s9_transformer.send(invocation_method, *invocation_args)
|
269
|
+
else
|
270
|
+
s9_transformer.send(invocation_method, *invocation_args, destination.to_java)
|
271
|
+
end
|
272
|
+
}
|
117
273
|
end
|
118
274
|
|
119
|
-
def
|
120
|
-
|
121
|
-
|
122
|
-
|
275
|
+
def resolve_template_name(template_name)
|
276
|
+
return self.class.default_initial_template.to_java if template_name.nil?
|
277
|
+
Saxon::QName.resolve(template_name).to_java
|
278
|
+
end
|
279
|
+
|
280
|
+
def function_args(args = [])
|
281
|
+
args.map { |val| Saxon::XDM.Value(val).to_java }.to_java(S9API::XdmValue)
|
123
282
|
end
|
124
283
|
|
125
284
|
def set_opts!
|
126
285
|
opts.each do |opt, value|
|
286
|
+
raise BadOptionError, opt unless VALID_OPTS.include?(opt)
|
127
287
|
send(opt, value)
|
128
288
|
end
|
129
289
|
end
|
@@ -140,16 +300,33 @@ module Saxon
|
|
140
300
|
s9_transformer.setInitialMode(Saxon::QName.resolve(mode_name).to_java)
|
141
301
|
end
|
142
302
|
|
303
|
+
def global_context_item(xdm_item)
|
304
|
+
s9_transformer.setGlobalContextItem(xdm_item.to_java)
|
305
|
+
end
|
306
|
+
|
143
307
|
def global_parameters(parameters)
|
144
308
|
s9_transformer.setStylesheetParameters(XSLT::ParameterHelper.to_java(parameters))
|
145
309
|
end
|
146
310
|
|
147
311
|
def initial_template_parameters(parameters)
|
148
|
-
s9_transformer.setInitialTemplateParameters(XSLT::ParameterHelper.to_java(parameters)
|
312
|
+
s9_transformer.setInitialTemplateParameters(XSLT::ParameterHelper.to_java(parameters), false)
|
149
313
|
end
|
150
314
|
|
151
315
|
def initial_template_tunnel_parameters(parameters)
|
152
|
-
s9_transformer.setInitialTemplateParameters(XSLT::ParameterHelper.to_java(parameters)
|
316
|
+
s9_transformer.setInitialTemplateParameters(XSLT::ParameterHelper.to_java(parameters), true)
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
# Raised if a bad option name is passed in the options hash to
|
321
|
+
# Executable#apply_templates et al
|
322
|
+
class BadOptionError < StandardError
|
323
|
+
def initialize(option_name)
|
324
|
+
@option_name = option_name
|
325
|
+
end
|
326
|
+
|
327
|
+
# return error message including the option name
|
328
|
+
def to_s
|
329
|
+
"Option :#{@option_name} is not a recognised option."
|
153
330
|
end
|
154
331
|
end
|
155
332
|
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require_relative '../serializer'
|
2
|
+
require_relative '../xdm/value'
|
3
|
+
|
4
|
+
|
5
|
+
module Saxon
|
6
|
+
module XSLT
|
7
|
+
# Represents the invocation of a compiled and loaded transformation,
|
8
|
+
# providing an idiomatic way to send the result a transformation to a
|
9
|
+
# particular Destination, or to serialize it directly to a file, string, or
|
10
|
+
# IO.
|
11
|
+
class Invocation
|
12
|
+
attr_reader :s9_transformer, :invocation_lambda
|
13
|
+
private :s9_transformer, :invocation_lambda
|
14
|
+
|
15
|
+
# @api private
|
16
|
+
def initialize(s9_transformer, invocation_lambda, raw)
|
17
|
+
@s9_transformer, @invocation_lambda, @raw = s9_transformer, invocation_lambda, raw
|
18
|
+
end
|
19
|
+
|
20
|
+
# Serialize the result to a string using the options specified in
|
21
|
+
# +<xsl:output/>+ in the XSLT
|
22
|
+
#
|
23
|
+
# @return [String] the serialized result of the transformation
|
24
|
+
def to_s
|
25
|
+
serializer_destination.serialize
|
26
|
+
end
|
27
|
+
|
28
|
+
# Serialize the result of the transformation. When called with a
|
29
|
+
# block, the block will be executed via instance-exec so that output
|
30
|
+
# properties can be set, e.g.
|
31
|
+
#
|
32
|
+
# result.serialize {
|
33
|
+
# output_property[:indent] = 'yes'
|
34
|
+
# }
|
35
|
+
#
|
36
|
+
# @overload serialize(io)
|
37
|
+
# Serialize the transformation to an IO
|
38
|
+
# @param [File, IO] io The IO to serialize to
|
39
|
+
# @return [nil]
|
40
|
+
# @yield the passed block bound via instance-exec to the new serializer
|
41
|
+
# @overload serialize(path)
|
42
|
+
# Serialize the transformation to file <tt>path</tt>
|
43
|
+
# @param [String, Pathname] path The path of the file to serialize to
|
44
|
+
# @return [nil]
|
45
|
+
# @yield the passed block bound via instance-exec to the new serializer
|
46
|
+
# @overload serialize
|
47
|
+
# Serialize the transformation to a String
|
48
|
+
# @return [String] The serialized XdmValue
|
49
|
+
def serialize(path_or_io = nil, &block)
|
50
|
+
serializer_destination(&block).serialize(path_or_io)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Return the result of the transformation as an XDM Value, either as it is
|
54
|
+
# returned (if the XSLT::Executable was created with :raw => true), or
|
55
|
+
# wrapped in a Document node and sequence normalized.
|
56
|
+
#
|
57
|
+
# @return [Saxon::XDM::Value] the XDM value returned by the transformation
|
58
|
+
def xdm_value
|
59
|
+
if raw?
|
60
|
+
XDM.Value(invocation_lambda.call(nil))
|
61
|
+
else
|
62
|
+
invocation_lambda.call(s9_xdm_destination)
|
63
|
+
XDM.Value(s9_xdm_destination.getXdmNode)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Send the result of the transformation to the supplied Destination
|
68
|
+
#
|
69
|
+
# @param s9_destination [net.sf.saxon.s9api.Destination] the Saxon
|
70
|
+
# destination to use
|
71
|
+
# @return [nil]
|
72
|
+
def to_destination(s9_destination)
|
73
|
+
invocation_lambda.call(s9_destination)
|
74
|
+
nil
|
75
|
+
end
|
76
|
+
|
77
|
+
# Whether the transformation was invoked as a 'raw' transformation, where
|
78
|
+
# an XDM Value result will be returned without being wrapped in a Document
|
79
|
+
# node, and without sequence normalization.
|
80
|
+
#
|
81
|
+
# @return [Boolean] whether the transformation was invoked 'raw' or not
|
82
|
+
def raw?
|
83
|
+
@raw
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def serializer_destination(&block)
|
89
|
+
Saxon::Serializer::Destination.new(s9_transformer.newSerializer, invocation_lambda, &block)
|
90
|
+
end
|
91
|
+
|
92
|
+
def s9_xdm_destination
|
93
|
+
@s9_xdm_destination ||= Saxon::S9API::XdmDestination.new
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|