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
data/lib/saxon/xpath.rb
CHANGED
@@ -3,6 +3,15 @@ require_relative './xpath/compiler'
|
|
3
3
|
module Saxon
|
4
4
|
# Classes for compiling, configuring, and executing XPath queries against
|
5
5
|
# XDM nodes or documents
|
6
|
+
#
|
7
|
+
# Using an XPath involves creating a compiler, compiling an XPath into an
|
8
|
+
# executable, and then running that XPath executable against an XDM node.
|
9
|
+
#
|
10
|
+
# The easiest way to create an XPath::Compiler instance is by using the {Saxon::Processor#xpath_compiler} method.
|
11
|
+
#
|
12
|
+
# @see Saxon::XPath::Compiler
|
13
|
+
# @see Saxon::XPath::Executable
|
14
|
+
# @see Saxon::Processor#xpath_compiler
|
6
15
|
module XPath
|
7
16
|
end
|
8
17
|
end
|
data/lib/saxon/xpath/compiler.rb
CHANGED
@@ -4,14 +4,43 @@ require_relative './executable'
|
|
4
4
|
|
5
5
|
module Saxon
|
6
6
|
module XPath
|
7
|
-
#
|
7
|
+
# An {XPath::Compiler} turns XPath expressions into executable queries you
|
8
|
+
# can run against XDM Nodes (like XML documents, or parts of XML documents).
|
9
|
+
#
|
10
|
+
# To compile an XPath requires an +XPath::Compiler+ instance. You can create
|
11
|
+
# one by calling {Compiler.create} and passing a {Saxon::Processor}, with an
|
12
|
+
# optional block for context like bound namespaces and declared variables.
|
13
|
+
# Alternately, and much more easily, you can call {Processor#xpath_compiler}
|
14
|
+
# on the {Saxon::Processor} instance you're already working with.
|
15
|
+
#
|
16
|
+
# processor = Saxon::Processor.create
|
17
|
+
# compiler = processor.xpath_compiler {
|
18
|
+
# namespace a: 'http://example.org/a'
|
19
|
+
# variable 'a:var', 'xs:string'
|
20
|
+
# }
|
21
|
+
# # Or...
|
22
|
+
# compiler = Saxon::XPath::Compiler.create(processor) {
|
23
|
+
# namespace a: 'http://example.org/a'
|
24
|
+
# variable 'a:var', 'xs:string'
|
25
|
+
# }
|
26
|
+
# xpath = compiler.compile('//a:element[@attr = $a:var]')
|
27
|
+
# matches = xpath.evaluate(document_node, {
|
28
|
+
# 'a:var' => 'the value'
|
29
|
+
# }) #=> Saxon::XDM::Value
|
30
|
+
#
|
31
|
+
# In order to use prefixed QNames in your XPaths, like +/ns:name/+, then you need
|
32
|
+
# to declare prefix/namespace URI bindings when you create a compiler.
|
33
|
+
#
|
34
|
+
# It's also possible to make use of variables in your XPaths by declaring them at
|
35
|
+
# the compiler creation stage, and then passing in values for them as XPath run
|
36
|
+
# time.
|
8
37
|
class Compiler
|
9
38
|
# Create a new <tt>XPath::Compiler</tt> using the supplied Processor.
|
10
39
|
# Passing a block gives access to a DSL for setting up the compiler's
|
11
40
|
# static context.
|
12
41
|
#
|
13
42
|
# @param processor [Saxon::Processor] the {Saxon::Processor} to use
|
14
|
-
# @yield An XPath
|
43
|
+
# @yield An XPath::StaticContext::DSL block
|
15
44
|
# @return [Saxon::XPath::Compiler] the new compiler instance
|
16
45
|
def self.create(processor, &block)
|
17
46
|
static_context = XPath::StaticContext.define(block)
|
@@ -46,6 +75,12 @@ module Saxon
|
|
46
75
|
Saxon::XPath::Executable.new(new_compiler.compile(expression), static_context)
|
47
76
|
end
|
48
77
|
|
78
|
+
# Allows the creation of a new {Compiler} starting from a copy of this
|
79
|
+
# Compiler's static context. As with {.create}, passing a block gives
|
80
|
+
# access to a DSL for setting up the compiler's static context.
|
81
|
+
#
|
82
|
+
# @yield An XPath::StaticContext::DSL block
|
83
|
+
# @return [Saxon::XPath::Compiler] the new compiler instance
|
49
84
|
def create(&block)
|
50
85
|
new_static_context = static_context.define(block)
|
51
86
|
self.class.new(@s9_processor, new_static_context)
|
@@ -2,7 +2,23 @@ require_relative '../xdm'
|
|
2
2
|
|
3
3
|
module Saxon
|
4
4
|
module XPath
|
5
|
-
# Represents a compiled XPath query ready to be executed
|
5
|
+
# Represents a compiled XPath query ready to be executed. An
|
6
|
+
# {XPath::Executable} is created by compiling an XPath expression with
|
7
|
+
# {XPath::Compiler#compile}.
|
8
|
+
#
|
9
|
+
# To run the +XPath::Executable+ you can call {XPath::Executable#evaluate},
|
10
|
+
# to generate an {XDM::Value} of the results, or you can call
|
11
|
+
# {XPath::Executable#as_enum} to return an Enumerator over the results.
|
12
|
+
#
|
13
|
+
# processor = Saxon::Processor.create
|
14
|
+
# compiler = processor.xpath_compiler
|
15
|
+
# xpath = compiler.compile('//element[@attr = $var]')
|
16
|
+
#
|
17
|
+
# matches = xpath.evaluate(document_node, {'var' => 'the value'}) #=> Saxon::XDM::Value
|
18
|
+
#
|
19
|
+
# xpath.as_enum(document_node, {'var' => 'the value'}).each do |node|
|
20
|
+
# ...
|
21
|
+
# end
|
6
22
|
class Executable
|
7
23
|
# @return [XPath::StaticContext] the XPath's static context
|
8
24
|
attr_reader :static_context
|
@@ -16,17 +32,34 @@ module Saxon
|
|
16
32
|
@s9_xpath_executable, @static_context = s9_xpath_executable, static_context
|
17
33
|
end
|
18
34
|
|
19
|
-
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
35
|
+
|
36
|
+
# Evaluate the XPath against the context node given and return an
|
37
|
+
# +Enumerator+ over the result.
|
38
|
+
#
|
39
|
+
# @param context_item [Saxon::XDM::Node, Saxon::XDM::AtomicValue] the item
|
40
|
+
# to be used as the context item for evaluating the XPath from.
|
41
|
+
# @param variables [Hash<Saxon::QName => Saxon::XDM::Value, Saxon::XDM::Node,
|
42
|
+
# Saxon::XDM::AtomicValue>] any variable values to set within the XPath
|
43
|
+
# @return [Enumerator] an Enumerator over the items in the result sequence
|
44
|
+
def as_enum(context_item, variables = {})
|
45
|
+
generate_selector(context_item, variables).iterator.lazy.
|
46
|
+
map { |s9_xdm_object| Saxon::XDM.Value(s9_xdm_object) }
|
47
|
+
end
|
48
|
+
|
49
|
+
# Evaluate the XPath against the context node given and return the result.
|
50
|
+
#
|
51
|
+
# If the result is a single item, then that will be returned directly
|
52
|
+
# (e.g. an {XDM::Node} or an {XDM::AtomicValue}). If the result is an
|
53
|
+
# empty sequence then {XDM::EmptySequence} is returned.
|
54
|
+
#
|
55
|
+
# @param context_item [Saxon::XDM::Node, Saxon::XDM::AtomicValue] the item
|
56
|
+
# to be used as the context item for evaluating the XPath from.
|
57
|
+
# @param variables [Hash<Saxon::QName => Saxon::XDM::Value, Saxon::XDM::Node,
|
58
|
+
# Saxon::XDM::AtomicValue>] any variable values to set within the XPath
|
59
|
+
# @return [Saxon::XDM::Value] the XDM value returned
|
60
|
+
def evaluate(context_item, variables = {})
|
61
|
+
s9_xdm_value = generate_selector(context_item, variables).evaluate
|
62
|
+
Saxon::XDM.Value(s9_xdm_value)
|
30
63
|
end
|
31
64
|
|
32
65
|
# @return [net.sf.saxon.s9api.XPathExecutable] the underlying Saxon
|
@@ -34,24 +67,16 @@ module Saxon
|
|
34
67
|
def to_java
|
35
68
|
@s9_xpath_executable
|
36
69
|
end
|
37
|
-
end
|
38
70
|
|
39
|
-
|
40
|
-
class Result
|
41
|
-
include Enumerable
|
71
|
+
private
|
42
72
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
# Yields <tt>XDM::Node</tt>s from the query result. If no block is passed,
|
51
|
-
# returns an <tt>Enumerator</tt>
|
52
|
-
# @yieldparam xdm_node [Saxon::XDM::Node] the name that is yielded
|
53
|
-
def each(&block)
|
54
|
-
@result_iterator.lazy.map { |s9_xdm_node| Saxon::XDM::Node.new(s9_xdm_node) }.each(&block)
|
73
|
+
def generate_selector(context_item, variables = {})
|
74
|
+
selector = to_java.load
|
75
|
+
selector.setContextItem(context_item.to_java)
|
76
|
+
variables.each do |qname_or_string, value|
|
77
|
+
selector.setVariable(static_context.resolve_variable_qname(qname_or_string).to_java, Saxon::XDM.Value(value).to_java)
|
78
|
+
end
|
79
|
+
selector
|
55
80
|
end
|
56
81
|
end
|
57
82
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require_relative '../qname'
|
2
2
|
require_relative './variable_declaration'
|
3
|
+
|
3
4
|
module Saxon
|
4
5
|
module XPath
|
5
6
|
# Raised when an attempt to declare a variable is made using a string for
|
@@ -10,11 +11,13 @@ module Saxon
|
|
10
11
|
@variable_name, @prefix = variable_name, prefix
|
11
12
|
end
|
12
13
|
|
14
|
+
# error message reports which unbound prefix is a problem, and how it was used
|
13
15
|
def to_s
|
14
16
|
"Namespace prefix ‘#{@prefix}’ for variable name ‘#{@variable_name}’ is not bound to a URI"
|
15
17
|
end
|
16
18
|
end
|
17
19
|
|
20
|
+
# @api private
|
18
21
|
# Represents the static context for a compiled XPath. {StaticContext}s are immutable.
|
19
22
|
class StaticContext
|
20
23
|
# methods used by both {StaticContext} and {StaticContext::DSL}
|
@@ -41,11 +44,12 @@ module Saxon
|
|
41
44
|
end
|
42
45
|
end
|
43
46
|
|
47
|
+
# @api public
|
44
48
|
# Provides the hooks for constructing a {StaticContext} with a DSL.
|
45
|
-
# @api private
|
46
49
|
class DSL
|
47
50
|
include Common
|
48
51
|
|
52
|
+
# @api private
|
49
53
|
# 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
|
50
54
|
# new {StaticContext} with the results
|
51
55
|
# @param block [Proc] a Proc/lambda (or <tt>to_proc</tt>'d containing DSL calls
|
@@ -70,28 +74,23 @@ module Saxon
|
|
70
74
|
#
|
71
75
|
# @param namespaces [Hash{String, Symbol => String}]
|
72
76
|
def namespace(namespaces = {})
|
73
|
-
@declared_namespaces = @declared_namespaces.merge(namespaces.
|
77
|
+
@declared_namespaces = @declared_namespaces.merge(namespaces.map { |k, v| [k.to_s, v] }.to_h).freeze
|
74
78
|
end
|
75
79
|
|
76
80
|
# Declare a XPath variable's existence in the context
|
77
81
|
#
|
78
82
|
# @param qname [String, Saxon::QName] The name of the variable as
|
79
|
-
#
|
80
|
-
#
|
81
|
-
# @param
|
82
|
-
# variable, either as a string using the same form as an XSLT
|
83
|
-
#
|
84
|
-
#
|
85
|
-
#
|
86
|
-
|
87
|
-
# can parse into an XDM type (e.g. <tt>xs:string</tthat
|
88
|
-
# {Saxon::ItemType} can parse into an XDM type (e.g.
|
89
|
-
# <tt>xs:string</tt> or <tt>element()</tt>).
|
90
|
-
# If it's nil, then the default <tt>item()*</tt> – anything – type declaration is used
|
91
|
-
def variable(qname, type = nil)
|
83
|
+
# explicit QName or prefix:name string form. The string form requires
|
84
|
+
# the namespace prefix to have already been declared with {#namespace}
|
85
|
+
# @param sequence_type [String, Saxon::SequenceType, null] The type of
|
86
|
+
# the variable, either as a string using the same form as an XSLT
|
87
|
+
# <tt>as=""</tt> type definition, or as a {Saxon::SequenceType} directly.
|
88
|
+
#
|
89
|
+
# If it's nil, then the default <tt>item()*</tt> – anything – type declaration is used
|
90
|
+
def variable(qname, sequence_type = nil)
|
92
91
|
qname = resolve_variable_qname(qname)
|
93
92
|
@declared_variables = @declared_variables.merge({
|
94
|
-
qname => resolve_variable_declaration(qname,
|
93
|
+
qname => resolve_variable_declaration(qname, sequence_type)
|
95
94
|
}).freeze
|
96
95
|
end
|
97
96
|
|
@@ -101,29 +100,8 @@ module Saxon
|
|
101
100
|
Saxon::QName.resolve(qname_or_string, @declared_namespaces)
|
102
101
|
end
|
103
102
|
|
104
|
-
def
|
105
|
-
|
106
|
-
when String
|
107
|
-
occurence_char = type_decl[-1]
|
108
|
-
occurence = case occurence_char
|
109
|
-
when '?'
|
110
|
-
{zero_or_one: type_decl[0..-2]}
|
111
|
-
when '+'
|
112
|
-
{one_or_more: type_decl[0..-2]}
|
113
|
-
when '*'
|
114
|
-
{zero_or_more: type_decl[0..-2]}
|
115
|
-
else
|
116
|
-
{one: type_decl}
|
117
|
-
end
|
118
|
-
when Hash
|
119
|
-
type_decl
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
def resolve_variable_declaration(qname, type)
|
124
|
-
args_hash = resolve_variable_type_decl(type) || {}
|
125
|
-
args_hash[:qname] = qname
|
126
|
-
Saxon::XPath::VariableDeclaration.new(args_hash)
|
103
|
+
def resolve_variable_declaration(qname, sequence_type = nil)
|
104
|
+
Saxon::XPath::VariableDeclaration.new(qname, Saxon.SequenceType(sequence_type || 'item()*'))
|
127
105
|
end
|
128
106
|
end
|
129
107
|
|
@@ -139,7 +117,12 @@ module Saxon
|
|
139
117
|
DSL.define(block)
|
140
118
|
end
|
141
119
|
|
142
|
-
|
120
|
+
# @return [String] The default collation URI as a String
|
121
|
+
attr_reader :default_collation
|
122
|
+
# @return [Hash<Saxon::QName => Saxon::XPath::VariableDeclaration] the declared variables
|
123
|
+
attr_reader :declared_variables
|
124
|
+
# @return [Hash<String => String>] the declared namespaces, as a prefix => uri hash
|
125
|
+
attr_reader :declared_namespaces
|
143
126
|
|
144
127
|
# @return [Saxon::QName]
|
145
128
|
# @overload resolve_variable_qname(qname)
|
@@ -153,6 +136,8 @@ module Saxon
|
|
153
136
|
Saxon::QName.resolve(qname_or_string, declared_namespaces)
|
154
137
|
end
|
155
138
|
|
139
|
+
# @api private
|
140
|
+
# Create a new {StaticContext} based on this one. Passed Proc is evaluated in the same way as {DSL.define}
|
156
141
|
def define(block)
|
157
142
|
DSL.define(block, args_hash)
|
158
143
|
end
|
@@ -1,67 +1,34 @@
|
|
1
|
-
require_relative '../
|
2
|
-
require_relative '../occurrence_indicator'
|
1
|
+
require_relative '../sequence_type'
|
3
2
|
|
4
3
|
module Saxon
|
5
4
|
module XPath
|
6
|
-
# Represents an XPath variable declaration in the static context of a
|
5
|
+
# Represents an XPath variable declaration in the static context of a
|
6
|
+
# compiled XPath, providing an idiomatic Ruby way to deal with these.
|
7
7
|
class VariableDeclaration
|
8
8
|
# @return [Saxon::QName]
|
9
9
|
attr_reader :qname
|
10
|
-
# @return [Saxon::
|
11
|
-
attr_reader :
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
#
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
@qname = opts.fetch(:qname)
|
20
|
-
@item_type, @occurrences = extract_type_decl(opts.reject { |k, v| k == :qname })
|
10
|
+
# @return [Saxon::SequenceType]
|
11
|
+
attr_reader :sequence_type
|
12
|
+
|
13
|
+
# @param qname [Saxon::QName] the name of the variable
|
14
|
+
# @param sequence_type [Saxon::SequenceType] the SequenceType of the
|
15
|
+
# variable
|
16
|
+
def initialize(qname, sequence_type)
|
17
|
+
@qname = qname
|
18
|
+
@sequence_type = sequence_type || Saxon.SequenceType('item()*')
|
21
19
|
end
|
22
20
|
|
23
|
-
# VariableDeclarations compare equal if their qname
|
21
|
+
# VariableDeclarations compare equal if their qname and sequence_type are equal
|
24
22
|
# @param other [Saxon::VariableDeclaration]
|
25
23
|
# @return [Boolean]
|
26
24
|
def ==(other)
|
27
|
-
VariableDeclaration === other && qname == other.qname &&
|
25
|
+
VariableDeclaration === other && qname == other.qname && sequence_type == other.sequence_type
|
28
26
|
end
|
29
27
|
|
30
28
|
# @api private
|
29
|
+
# return the arguments XPathCompiler.declareVariable expects
|
31
30
|
def compiler_args
|
32
|
-
[qname.to_java, item_type.to_java,
|
33
|
-
end
|
34
|
-
|
35
|
-
private
|
36
|
-
|
37
|
-
def self.valid_opt_keys
|
38
|
-
@valid_opt_keys ||= [:qname] + Saxon::OccurrenceIndicator.indicator_names
|
39
|
-
end
|
40
|
-
|
41
|
-
def extract_type_decl(type_decl)
|
42
|
-
raise VariableDeclarationError, type_decl.keys if type_decl.length > 1
|
43
|
-
unless (type_decl.keys - Saxon::OccurrenceIndicator.indicator_names).empty?
|
44
|
-
raise VariableDeclarationError, type_decl.keys
|
45
|
-
end
|
46
|
-
|
47
|
-
return [Saxon::ItemType.get_type('item()'), Saxon::OccurrenceIndicator.zero_or_more] if type_decl.empty?
|
48
|
-
occurrence, type = type_decl.first
|
49
|
-
[Saxon::ItemType.get_type(type), Saxon::OccurrenceIndicator.send(occurrence)]
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
# Raised when an attempt to declare a variable is made using an occurrence
|
54
|
-
# indicator that does not exist
|
55
|
-
class VariableDeclarationError < StandardError
|
56
|
-
attr_reader :keys
|
57
|
-
|
58
|
-
def initialize(keys)
|
59
|
-
@keys = keys
|
60
|
-
end
|
61
|
-
|
62
|
-
# reports allowable occurrence indicator keys and what was actually passed in
|
63
|
-
def to_s
|
64
|
-
"requires :qname, and optionally one of #{Saxon::OccurrenceIndicator.indicator_names}, was passed #{keys.join(', ')}"
|
31
|
+
[qname.to_java, sequence_type.item_type.to_java, sequence_type.occurrence_indicator.to_java]
|
65
32
|
end
|
66
33
|
end
|
67
34
|
end
|
data/lib/saxon/xslt.rb
CHANGED
@@ -3,6 +3,18 @@ require_relative './xslt/compiler'
|
|
3
3
|
module Saxon
|
4
4
|
# Classes for compiling, configuring, and executing XSLT transformations
|
5
5
|
# against XDM nodes or documents
|
6
|
+
#
|
7
|
+
# Using XSLT involves creating a compiler, compiling an XSLT file into an
|
8
|
+
# executable, and then invoking that executable through applying templates
|
9
|
+
# against an XML document, calling a named template, or calling a named
|
10
|
+
# function.
|
11
|
+
#
|
12
|
+
# The easiest way to create an {XSLT::Compiler} instance is by using the
|
13
|
+
# {Saxon::Processor#xslt_compiler} method.
|
14
|
+
#
|
15
|
+
# @see Saxon::XSLT::Compiler
|
16
|
+
# @see Saxon::XSLT::Executable
|
17
|
+
# @see Saxon::Processor#xslt_compiler
|
6
18
|
module XSLT
|
7
19
|
end
|
8
20
|
end
|
data/lib/saxon/xslt/compiler.rb
CHANGED
@@ -4,7 +4,67 @@ require_relative './executable'
|
|
4
4
|
|
5
5
|
module Saxon
|
6
6
|
module XSLT
|
7
|
-
#
|
7
|
+
# The simplest way to construct an {XSLT::Compiler} is to call
|
8
|
+
# {Saxon::Processor#xslt_compiler}.
|
9
|
+
#
|
10
|
+
# processor = Saxon::Processor.create
|
11
|
+
# # Simplest, default options
|
12
|
+
# compiler = processor.xslt_compiler
|
13
|
+
#
|
14
|
+
# In order to set compile-time options, declare static compile-time
|
15
|
+
# parameters then pass a block to the method using the DSL syntax (see
|
16
|
+
# {Saxon::XSLT::EvaluationContext::DSL}
|
17
|
+
#
|
18
|
+
# compiler = processor.xslt_compiler {
|
19
|
+
# static_parameters 'param' => 'value'
|
20
|
+
# default_collation 'https://www.w3.org/2005/xpath-functions/collation/html-ascii-case-insensitive/'
|
21
|
+
# }
|
22
|
+
#
|
23
|
+
# The static evaluation context for a Compiler cannot be changed, you must
|
24
|
+
# create a new one with the context you want. It’s very simple to create a
|
25
|
+
# new Compiler based on an existing one. Declaring a parameter with a an
|
26
|
+
# existing name overwrites the old value.
|
27
|
+
#
|
28
|
+
# new_compiler = compiler.create {
|
29
|
+
# static_parameters 'param' => 'new value'
|
30
|
+
# }
|
31
|
+
# new_compiler.default_collation #=> "https://www.w3.org/2005/xpath-functions/collation/html-ascii-case-insensitive/"
|
32
|
+
#
|
33
|
+
# If you wanted to remove a value, you need to start from scratch. You can,
|
34
|
+
# of course, extract any data you want from a compiler instance separately
|
35
|
+
# and use that to create a new one.
|
36
|
+
#
|
37
|
+
# params = compiler.static_parameters
|
38
|
+
# new_compiler = processor.xslt_compiler {
|
39
|
+
# static_parameters params
|
40
|
+
# }
|
41
|
+
# new_compiler.default_collation #=> nil
|
42
|
+
#
|
43
|
+
# Once you have a compiler, call {Compiler#compile} and pass in a
|
44
|
+
# {Saxon::Source} or an existing {Saxon::XDM::Node}. Parameters and other
|
45
|
+
# run-time configuration options can be set using a block in the same way as
|
46
|
+
# creating a compiler. You'll be returned a {Saxon::XSLT::Executable}.
|
47
|
+
#
|
48
|
+
# source = Saxon::Source.create('my.xsl')
|
49
|
+
# xslt = compiler.compile(source) {
|
50
|
+
# initial_template_parameters 'param' => 'other value'
|
51
|
+
# }
|
52
|
+
#
|
53
|
+
# You can also pass in (or override) parameters at stylesheet execution
|
54
|
+
# time, but if you'll be executing the same stylesheet against many
|
55
|
+
# documents with the same initial parameters then setting them at compile
|
56
|
+
# time is simpler.
|
57
|
+
#
|
58
|
+
# Global and initial template parameters can be set at compiler creation
|
59
|
+
# time, compile time, or execution time. Static parameters can only be set
|
60
|
+
# at compiler creation or compile time.
|
61
|
+
#
|
62
|
+
# xslt = compiler.compile(source) {
|
63
|
+
# static_parameters 'static-param' => 'static value'
|
64
|
+
# global_parameters 'param' => 'global value'
|
65
|
+
# initial_template_parameters 'param' => 'other value'
|
66
|
+
# initial_template_tunnel_parameters 'param' => 'tunnel value'
|
67
|
+
# }
|
8
68
|
class Compiler
|
9
69
|
# Create a new <tt>XSLT::Compiler</tt> using the supplied Processor.
|
10
70
|
# Passing a block gives access to a DSL for setting up the compiler's
|
@@ -42,14 +102,23 @@ module Saxon
|
|
42
102
|
# Saxon::XDM::AtomicValue>] parameters required at compile time as QName => value hash
|
43
103
|
|
44
104
|
# @param source [Saxon::Source] the Source to compile
|
105
|
+
# @yield the block is executed in the context of an {XSLT::EvaluationContext} DSL instance
|
45
106
|
# @return [Saxon::XSLT::Executable] the executable stylesheet
|
46
107
|
def compile(source, &block)
|
108
|
+
new_evaluation_context = evaluation_context.define(block)
|
109
|
+
s9_compiler = new_compiler(new_evaluation_context)
|
47
110
|
Saxon::XSLT::Executable.new(
|
48
|
-
|
49
|
-
|
111
|
+
s9_compiler.compile(source.to_java),
|
112
|
+
new_evaluation_context
|
50
113
|
)
|
51
114
|
end
|
52
115
|
|
116
|
+
# Allows the creation of a new {Compiler} starting from a copy of this
|
117
|
+
# Compiler's static context. As with {.create}, passing a block gives
|
118
|
+
# access to a DSL for setting up the compiler's static context.
|
119
|
+
#
|
120
|
+
# @yield An XSLT compiler DSL block
|
121
|
+
# @return [Saxon::XSLT::Compiler] the new compiler instance
|
53
122
|
def create(&block)
|
54
123
|
new_evaluation_context = evaluation_context.define(block)
|
55
124
|
self.class.new(@s9_processor, new_evaluation_context)
|
@@ -57,10 +126,10 @@ module Saxon
|
|
57
126
|
|
58
127
|
private
|
59
128
|
|
60
|
-
def new_compiler
|
129
|
+
def new_compiler(evaluation_context)
|
61
130
|
compiler = @s9_processor.newXsltCompiler
|
62
|
-
compiler.declareDefaultCollation(default_collation) unless default_collation.nil?
|
63
|
-
static_parameters.each do |qname, value|
|
131
|
+
compiler.declareDefaultCollation(evaluation_context.default_collation) unless evaluation_context.default_collation.nil?
|
132
|
+
evaluation_context.static_parameters.each do |qname, value|
|
64
133
|
compiler.setParameter(qname.to_java, value.to_java)
|
65
134
|
end
|
66
135
|
compiler
|