saxon-rb 0.4.0-java → 0.7.2-java
Sign up to get free protection for your applications and to get access to all the features.
- 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
|