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.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +429 -42
  3. data/.ruby-version +1 -1
  4. data/.yardopts +1 -0
  5. data/Gemfile +2 -2
  6. data/README.md +358 -10
  7. data/Rakefile +237 -7
  8. data/docs/templates/plugin.rb +73 -0
  9. 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
  10. data/lib/saxon-rb.rb +0 -0
  11. data/lib/{saxon_jars.rb → saxon-rb_jars.rb} +2 -2
  12. data/lib/saxon.rb +13 -0
  13. data/lib/saxon/axis_iterator.rb +8 -1
  14. data/lib/saxon/configuration.rb +16 -13
  15. data/lib/saxon/document_builder.rb +216 -5
  16. data/lib/saxon/feature_flags.rb +11 -0
  17. data/lib/saxon/feature_flags/errors.rb +8 -0
  18. data/lib/saxon/feature_flags/helpers.rb +15 -0
  19. data/lib/saxon/feature_flags/version.rb +100 -0
  20. data/lib/saxon/item_type.rb +129 -89
  21. data/lib/saxon/item_type/lexical_string_conversion.rb +214 -59
  22. data/lib/saxon/item_type/value_to_ruby.rb +25 -0
  23. data/lib/saxon/loader.rb +6 -1
  24. data/lib/saxon/nokogiri.rb +78 -0
  25. data/lib/saxon/occurrence_indicator.rb +32 -3
  26. data/lib/saxon/processor.rb +50 -5
  27. data/lib/saxon/qname.rb +37 -2
  28. data/lib/saxon/s9api.rb +5 -0
  29. data/lib/saxon/sequence_type.rb +131 -0
  30. data/lib/saxon/serializer.rb +3 -137
  31. data/lib/saxon/serializer/destination.rb +80 -0
  32. data/lib/saxon/serializer/object.rb +93 -0
  33. data/lib/saxon/serializer/output_properties.rb +83 -0
  34. data/lib/saxon/source.rb +207 -71
  35. data/lib/saxon/version.rb +7 -1
  36. data/lib/saxon/version/library.rb +89 -0
  37. data/lib/saxon/xdm.rb +7 -0
  38. data/lib/saxon/xdm/array.rb +16 -0
  39. data/lib/saxon/xdm/atomic_value.rb +10 -2
  40. data/lib/saxon/xdm/empty_sequence.rb +13 -0
  41. data/lib/saxon/xdm/external_object.rb +1 -0
  42. data/lib/saxon/xdm/function_item.rb +1 -0
  43. data/lib/saxon/xdm/item.rb +7 -0
  44. data/lib/saxon/xdm/map.rb +38 -0
  45. data/lib/saxon/xdm/node.rb +50 -1
  46. data/lib/saxon/xdm/sequence_like.rb +15 -0
  47. data/lib/saxon/xdm/value.rb +21 -5
  48. data/lib/saxon/xpath.rb +9 -0
  49. data/lib/saxon/xpath/compiler.rb +37 -2
  50. data/lib/saxon/xpath/executable.rb +53 -28
  51. data/lib/saxon/xpath/static_context.rb +25 -40
  52. data/lib/saxon/xpath/variable_declaration.rb +16 -49
  53. data/lib/saxon/xslt.rb +12 -0
  54. data/lib/saxon/xslt/compiler.rb +75 -6
  55. data/lib/saxon/xslt/evaluation_context.rb +30 -4
  56. data/lib/saxon/xslt/executable.rb +206 -29
  57. data/lib/saxon/xslt/invocation.rb +97 -0
  58. data/saxon-rb.gemspec +3 -3
  59. metadata +22 -10
  60. data/saxon.gemspec +0 -30
@@ -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
@@ -4,14 +4,43 @@ require_relative './executable'
4
4
 
5
5
  module Saxon
6
6
  module XPath
7
- # Compiles XPath expressions so they can be executed
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 compiler DSL block
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
- # Run the compiled query using a passed-in node as the context item.
20
- # @param context_item [Saxon::XDM::Node] the context item node
21
- # @return [Saxon::XPath::Result] the result of the query as an
22
- # enumerable
23
- def run(context_item, variables = {})
24
- selector = to_java.load
25
- selector.setContextItem(context_item.to_java)
26
- variables.each do |qname_or_string, value|
27
- selector.setVariable(static_context.resolve_variable_qname(qname_or_string).to_java, Saxon::XDM.Value(value).to_java)
28
- end
29
- Result.new(selector.iterator)
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
- # The result of executing an XPath query as an enumerable object
40
- class Result
41
- include Enumerable
71
+ private
42
72
 
43
- # @api private
44
- # @param result_iterator [java.util.Iterator] the result of calling
45
- # <tt>#iterator</tt> on a Saxon <tt>XPathSelector</tt>
46
- def initialize(result_iterator)
47
- @result_iterator = result_iterator
48
- end
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.transform_keys(&:to_s)).freeze
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
- # explicit QName or prefix:name string form. The string form requires
80
- # the namespace prefix to have already been declared with {#namespace}
81
- # @param type [String, Hash{Symbol => String, Class}, null] The type of the
82
- # variable, either as a string using the same form as an XSLT
83
- # <tt>as=""</tt> type definition, or as a hash of one key/value where
84
- # that key is a Symbol taken from {Saxon::OccurenceIndicator} and the
85
- # value is either a Class that {Saxon::ItemType} can convert to its
86
- # XDM equivalent (e.g. {::String}), or a string that {Saxon::ItemType}
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, type)
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 resolve_variable_type_decl(type_decl)
105
- case type_decl
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
- attr_reader :declared_variables, :declared_namespaces, :default_collation
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 '../item_type'
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 compiled XPath, providing an idiomatic Ruby way to deal with these.
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::ItemType]
11
- attr_reader :item_type
12
- # @return [net.sf.saxon.s9api.OccurrenceIndicator]
13
- attr_reader :occurrences
14
-
15
- # @param opts [Hash]
16
- # @option opts [Saxon::QName] :qname The name of the variable as a {Saxon::QName}
17
- def initialize(opts = {})
18
- raise VariableDeclarationError, opts.keys if opts.keys.length > 2
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, item_type, and occurrences are equal
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 && item_type == other.item_type && occurrences == other.occurrences
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, occurrences]
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
@@ -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
@@ -4,7 +4,67 @@ require_relative './executable'
4
4
 
5
5
  module Saxon
6
6
  module XSLT
7
- # Compiles XSLT stylesheets so they can be executed
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
- new_compiler.compile(source.to_java),
49
- evaluation_context.define(block)
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