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.
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