saxon-rb 0.4.0-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 (54) hide show
  1. checksums.yaml +7 -0
  2. data/.circleci/config.yml +62 -0
  3. data/.gitignore +13 -0
  4. data/.rspec +3 -0
  5. data/.ruby-version +1 -0
  6. data/CODE_OF_CONDUCT.md +74 -0
  7. data/Gemfile +6 -0
  8. data/LICENSE.txt +21 -0
  9. data/README.md +43 -0
  10. data/Rakefile +20 -0
  11. data/bin/console +14 -0
  12. data/bin/setup +8 -0
  13. data/lib/net/sf/saxon/Saxon-HE/9.9.1-5/Saxon-HE-9.9.1-5.jar +0 -0
  14. data/lib/saxon.rb +6 -0
  15. data/lib/saxon/axis_iterator.rb +31 -0
  16. data/lib/saxon/configuration.rb +116 -0
  17. data/lib/saxon/document_builder.rb +28 -0
  18. data/lib/saxon/item_type.rb +290 -0
  19. data/lib/saxon/item_type/lexical_string_conversion.rb +383 -0
  20. data/lib/saxon/item_type/value_to_ruby.rb +78 -0
  21. data/lib/saxon/jaxp.rb +8 -0
  22. data/lib/saxon/loader.rb +93 -0
  23. data/lib/saxon/occurrence_indicator.rb +33 -0
  24. data/lib/saxon/parse_options.rb +127 -0
  25. data/lib/saxon/processor.rb +102 -0
  26. data/lib/saxon/qname.rb +153 -0
  27. data/lib/saxon/s9api.rb +34 -0
  28. data/lib/saxon/serializer.rb +143 -0
  29. data/lib/saxon/source.rb +187 -0
  30. data/lib/saxon/version.rb +3 -0
  31. data/lib/saxon/xdm.rb +35 -0
  32. data/lib/saxon/xdm/array.rb +77 -0
  33. data/lib/saxon/xdm/atomic_value.rb +173 -0
  34. data/lib/saxon/xdm/empty_sequence.rb +37 -0
  35. data/lib/saxon/xdm/external_object.rb +21 -0
  36. data/lib/saxon/xdm/function_item.rb +21 -0
  37. data/lib/saxon/xdm/item.rb +32 -0
  38. data/lib/saxon/xdm/map.rb +77 -0
  39. data/lib/saxon/xdm/node.rb +71 -0
  40. data/lib/saxon/xdm/sequence_like.rb +30 -0
  41. data/lib/saxon/xdm/value.rb +145 -0
  42. data/lib/saxon/xpath.rb +8 -0
  43. data/lib/saxon/xpath/compiler.rb +69 -0
  44. data/lib/saxon/xpath/executable.rb +58 -0
  45. data/lib/saxon/xpath/static_context.rb +161 -0
  46. data/lib/saxon/xpath/variable_declaration.rb +68 -0
  47. data/lib/saxon/xslt.rb +8 -0
  48. data/lib/saxon/xslt/compiler.rb +70 -0
  49. data/lib/saxon/xslt/evaluation_context.rb +165 -0
  50. data/lib/saxon/xslt/executable.rb +156 -0
  51. data/lib/saxon_jars.rb +10 -0
  52. data/saxon-rb.gemspec +39 -0
  53. data/saxon.gemspec +30 -0
  54. metadata +240 -0
@@ -0,0 +1,68 @@
1
+ require_relative '../item_type'
2
+ require_relative '../occurrence_indicator'
3
+
4
+ module Saxon
5
+ 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.
7
+ class VariableDeclaration
8
+ # @return [Saxon::QName]
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 })
21
+ end
22
+
23
+ # VariableDeclarations compare equal if their qname, item_type, and occurrences are equal
24
+ # @param other [Saxon::VariableDeclaration]
25
+ # @return [Boolean]
26
+ def ==(other)
27
+ VariableDeclaration === other && qname == other.qname && item_type == other.item_type && occurrences == other.occurrences
28
+ end
29
+
30
+ # @api private
31
+ 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(', ')}"
65
+ end
66
+ end
67
+ end
68
+ end
data/lib/saxon/xslt.rb ADDED
@@ -0,0 +1,8 @@
1
+ require_relative './xslt/compiler'
2
+
3
+ module Saxon
4
+ # Classes for compiling, configuring, and executing XSLT transformations
5
+ # against XDM nodes or documents
6
+ module XSLT
7
+ end
8
+ end
@@ -0,0 +1,70 @@
1
+ require 'forwardable'
2
+ require_relative './evaluation_context'
3
+ require_relative './executable'
4
+
5
+ module Saxon
6
+ module XSLT
7
+ # Compiles XSLT stylesheets so they can be executed
8
+ class Compiler
9
+ # Create a new <tt>XSLT::Compiler</tt> using the supplied Processor.
10
+ # Passing a block gives access to a DSL for setting up the compiler's
11
+ # static context.
12
+ #
13
+ # @param processor [Saxon::Processor] the {Saxon::Processor} to use
14
+ # @yield An XSLT compiler DSL block
15
+ # @return [Saxon::XSLT::Compiler] the new compiler instance
16
+ def self.create(processor, &block)
17
+ evaluation_context = XSLT::EvaluationContext.define(block)
18
+ new(processor.to_java, evaluation_context)
19
+ end
20
+
21
+ extend Forwardable
22
+
23
+ attr_reader :evaluation_context
24
+ private :evaluation_context
25
+
26
+ # @api private
27
+ # @param s9_processor [net.sf.saxon.s9api.Processor] the Saxon
28
+ # <tt>Processor</tt> to wrap
29
+ # @param evaluation_context [Saxon::XSLT::EvaluationContext] the static context
30
+ # XPaths compiled using this compiler will have
31
+ def initialize(s9_processor, evaluation_context)
32
+ @s9_processor, @evaluation_context = s9_processor, evaluation_context
33
+ end
34
+
35
+ def_delegators :evaluation_context, :default_collation, :static_parameters, :global_parameters, :initial_template_parameters, :initial_template_tunnel_parameters
36
+ # @!attribute [r] declared_collations
37
+ # @return [Hash<String => java.text.Collator>] declared collations as URI => Collator hash
38
+ # @!attribute [r] default_collation
39
+ # @return [String] the URI of the default declared collation
40
+ # @!attribute [r] static_parameters
41
+ # @return [Hash<Saxon::QName => Saxon::XDM::Value, Saxon::XDM::Node,
42
+ # Saxon::XDM::AtomicValue>] parameters required at compile time as QName => value hash
43
+
44
+ # @param source [Saxon::Source] the Source to compile
45
+ # @return [Saxon::XSLT::Executable] the executable stylesheet
46
+ def compile(source, &block)
47
+ Saxon::XSLT::Executable.new(
48
+ new_compiler.compile(source.to_java),
49
+ evaluation_context.define(block)
50
+ )
51
+ end
52
+
53
+ def create(&block)
54
+ new_evaluation_context = evaluation_context.define(block)
55
+ self.class.new(@s9_processor, new_evaluation_context)
56
+ end
57
+
58
+ private
59
+
60
+ def new_compiler
61
+ compiler = @s9_processor.newXsltCompiler
62
+ compiler.declareDefaultCollation(default_collation) unless default_collation.nil?
63
+ static_parameters.each do |qname, value|
64
+ compiler.setParameter(qname.to_java, value.to_java)
65
+ end
66
+ compiler
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,165 @@
1
+ require 'set'
2
+ require_relative '../qname'
3
+
4
+ module Saxon
5
+ module XSLT
6
+ # Represents the evaluation context for an XSLT compiler, and stylesheets
7
+ # compiled using one. {EvaluationContext}s are immutable.
8
+ class EvaluationContext
9
+ # methods used by both {EvaluationContext} and {EvaluationContext::DSL}
10
+ module Common
11
+ # @param args [Hash]
12
+ # @option args [String] default_collation URI of the default collation
13
+ # @option args [Hash<String,Symbol,Saxon::QName =>
14
+ # Object,Saxon::XDM::Value] static_parameters Hash of QName => value
15
+ # bindings for static (compile-time) parameters for this compiler
16
+ def initialize(args = {})
17
+ @default_collation = args.fetch(:default_collation, nil).freeze
18
+ @static_parameters = args.fetch(:static_parameters, {}).freeze
19
+ @global_parameters = args.fetch(:global_parameters, {}).freeze
20
+ @initial_template_parameters = args.fetch(:initial_template_parameters, {}).freeze
21
+ @initial_template_tunnel_parameters = args.fetch(:initial_template_tunnel_parameters, {}).freeze
22
+ end
23
+
24
+ # returns the context details in a hash suitable for initializing a new one
25
+ # @return [Hash<Symbol => Hash,null>] the args hash
26
+ def args_hash
27
+ check_for_clashing_parameters!
28
+ {
29
+ default_collation: @default_collation,
30
+ static_parameters: @static_parameters,
31
+ global_parameters: @global_parameters,
32
+ initial_template_parameters: @initial_template_parameters,
33
+ initial_template_tunnel_parameters: @initial_template_tunnel_parameters
34
+ }
35
+ end
36
+
37
+ private
38
+
39
+ def check_for_clashing_parameters!
40
+ @checked ||= begin
41
+ if Set.new(@static_parameters.keys).intersect?(Set.new(@global_parameters.keys))
42
+ raise GlobalAndStaticParameterClashError
43
+ else
44
+ true
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ # Provides the hooks for constructing a {EvaluationContext} with a DSL.
51
+ # @api private
52
+ class DSL
53
+ include Common
54
+
55
+ # 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
+ # new {EvaluationContext} with the results
57
+ # @param block [Proc] a Proc/lambda (or <tt>to_proc</tt>'d containing DSL calls
58
+ # @return [Saxon::XSLT::EvaluationContext]
59
+ def self.define(block, args = {})
60
+ dsl = new(args)
61
+ dsl.instance_exec(&block) unless block.nil?
62
+ EvaluationContext.new(dsl.args_hash)
63
+ end
64
+
65
+ # Set the default Collation to use. This should be one of the special
66
+ # collation URIs Saxon recognises, or one that has been registered
67
+ # using Saxon::Processor#declare_collations on the Processor that
68
+ # created the {XSLT::Compiler} this context is for.
69
+ #
70
+ # @param collation_uri [String] The URI of the Collation to set as the default
71
+ def default_collation(collation_uri)
72
+ @default_collation = collation_uri
73
+ end
74
+
75
+ # Set the value for static parameters (those that must be known at
76
+ # compile-time to avoid an error), as a hash of QName => Value pairs.
77
+ # Parameter QNames can be declared as Strings or Symbols if they are
78
+ # not in any namespace, otherwise an explicit {Saxon::QName} must be
79
+ # used. Values can be provided as explicit XDM::Values:
80
+ # {Saxon::XDM::Value}, {Saxon::XDM::Node}, and {Saxon::XDM::AtomicValue}, or
81
+ # as Ruby objects which will be converted to {Saxon::XDM::AtomicValue}s
82
+ # in the usual way.
83
+ #
84
+ # @param parameters [Hash<String,Symbol,Saxon::QName =>
85
+ # Object,Saxon::XDM::Value>] Hash of QName => value
86
+ def static_parameters(parameters = {})
87
+ @static_parameters = @static_parameters.merge(process_parameters(parameters)).freeze
88
+ end
89
+
90
+ # Set the values for global parameters (those that are available to all templates and functions).
91
+ #
92
+ # @see EvaluationContext#static_parameters for details of the argument format
93
+ #
94
+ # @param parameters [Hash<String,Symbol,Saxon::QName =>
95
+ # Object,Saxon::XDM::Value>] Hash of QName => value
96
+ def global_parameters(parameters = {})
97
+ @global_parameters = @global_parameters.merge(process_parameters(parameters)).freeze
98
+ end
99
+
100
+ # Set the values for parameters made available only to the initial
101
+ # template invoked (either via apply_templates or call_template),
102
+ # effectively as if <tt><xsl:with-param tunnel="no"></tt> was being used.
103
+ #
104
+ # @see EvaluationContext#static_parameters for details of the argument format
105
+ #
106
+ # @param parameters [Hash<String,Symbol,Saxon::QName =>
107
+ # Object,Saxon::XDM::Value>] Hash of QName => value
108
+ def initial_template_parameters(parameters = {})
109
+ @initial_template_parameters = @initial_template_parameters.merge(process_parameters(parameters))
110
+ end
111
+
112
+ # Set the values for tunneling parameters made available only to the initial
113
+ # template invoked (either via apply_templates or call_template),
114
+ # effectively as if <tt><xsl:with-param tunnel="yes"></tt> was being used.
115
+ #
116
+ # @see EvaluationContext#static_parameters for details of the argument format
117
+ #
118
+ # @param parameters [Hash<String,Symbol,Saxon::QName =>
119
+ # Object,Saxon::XDM::Value>] Hash of QName => value
120
+ def initial_template_tunnel_parameters(parameters = {})
121
+ @initial_template_tunnel_parameters = @initial_template_tunnel_parameters.merge(process_parameters(parameters))
122
+ end
123
+
124
+ private
125
+
126
+ def process_parameters(parameters)
127
+ XSLT::ParameterHelper.process_parameters(parameters)
128
+ end
129
+ end
130
+
131
+ include Common
132
+
133
+ # Executes the Proc/lambda passed in with a new instance of
134
+ # {EvaluationContext} as <tt>self</tt>, allowing the DSL methods to be
135
+ # called in a DSL-ish way
136
+ #
137
+ # @param block [Proc] the block of DSL calls to be executed
138
+ # @return [Saxon::XSLT::EvaluationContext] the static context created by the block
139
+ def self.define(block)
140
+ DSL.define(block)
141
+ end
142
+
143
+ attr_reader :default_collation, :static_parameters, :global_parameters, :initial_template_parameters, :initial_template_tunnel_parameters
144
+
145
+ def define(block)
146
+ block.nil? ? self : DSL.define(block, args_hash)
147
+ end
148
+ end
149
+
150
+ class GlobalAndStaticParameterClashError < StandardError
151
+ end
152
+
153
+ module ParameterHelper
154
+ def self.process_parameters(parameters)
155
+ Hash[parameters.map { |qname, value|
156
+ [Saxon::QName.resolve(qname), Saxon::XDM.Value(value)]
157
+ }]
158
+ end
159
+
160
+ def self.to_java(parameters)
161
+ Hash[parameters.map { |k,v| [k.to_java, v.to_java] }].to_java
162
+ end
163
+ end
164
+ end
165
+ end
@@ -0,0 +1,156 @@
1
+ require 'forwardable'
2
+ require_relative 'evaluation_context'
3
+ require_relative '../serializer'
4
+ require_relative '../xdm'
5
+ require_relative '../qname'
6
+
7
+ module Saxon
8
+ module XSLT
9
+ # Represents a compiled XSLT stylesheet ready to be executed
10
+ class Executable
11
+ extend Forwardable
12
+
13
+ attr_reader :evaluation_context
14
+ private :evaluation_context
15
+
16
+ # @api private
17
+ # @param s9_xslt_executable [net.sf.saxon.s9api.XsltExecutable] the
18
+ # Saxon compiled XSLT object
19
+ # @param evaluation_context [XSLT::EvaluationContext] the XSLT's evaluation
20
+ # context
21
+ def initialize(s9_xslt_executable, evaluation_context)
22
+ @s9_xslt_executable, @evaluation_context = s9_xslt_executable, evaluation_context
23
+ end
24
+
25
+ def_delegators :evaluation_context, :global_parameters, :initial_template_parameters, :initial_template_tunnel_parameters
26
+
27
+ def apply_templates(source, opts = {})
28
+ transformation(opts).apply_templates(source)
29
+ end
30
+
31
+ def call_template(template_name, opts = {})
32
+ transformation(opts).call_template(template_name)
33
+ end
34
+
35
+ # @return [net.sf.saxon.s9api.XsltExecutable] the underlying Saxon
36
+ # <tt>XsltExecutable</tt>
37
+ def to_java
38
+ @s9_xslt_executable
39
+ end
40
+
41
+ private
42
+
43
+ def transformation(opts)
44
+ Transformation.new(params_merged_opts(opts).merge({
45
+ s9_transformer: @s9_xslt_executable.load30,
46
+ }))
47
+ end
48
+
49
+ def params_merged_opts(opts)
50
+ merged_opts = params_hash.dup
51
+ opts.each do |key, value|
52
+ if [:global_parameters, :initial_template_parameters, :initial_template_tunnel_parameters].include?(key)
53
+ merged_opts[key] = merged_opts.fetch(key, {}).merge(XSLT::ParameterHelper.process_parameters(value))
54
+ else
55
+ merged_opts[key] = value
56
+ end
57
+ end
58
+ merged_opts
59
+ end
60
+
61
+ def params_hash
62
+ @params_hash ||= begin
63
+ params_hash = {}
64
+ params_hash[:global_parameters] = global_parameters unless global_parameters.empty?
65
+ params_hash[:initial_template_parameters] = initial_template_parameters unless initial_template_parameters.empty?
66
+ params_hash[:initial_template_tunnel_parameters] = initial_template_tunnel_parameters unless initial_template_tunnel_parameters.empty?
67
+ params_hash
68
+ end.freeze
69
+ end
70
+ end
71
+
72
+ class Result
73
+ attr_reader :xdm_value
74
+
75
+ def initialize(xdm_value, s9_transformer)
76
+ @xdm_value, @s9_transformer = xdm_value, s9_transformer
77
+ end
78
+
79
+ def to_s
80
+ serializer = Serializer.new(@s9_transformer.newSerializer)
81
+ serializer.serialize(xdm_value.to_java)
82
+ end
83
+ end
84
+
85
+ class Transformation
86
+ attr_reader :s9_transformer, :opts
87
+
88
+ def initialize(args)
89
+ @s9_transformer = args.fetch(:s9_transformer)
90
+ @destination = args.fetch(:destination, nil)
91
+ @opts = args.reject { |opt, _|
92
+ [:s9_transformer, :destination].include?(opt)
93
+ }
94
+ @raw = false
95
+ end
96
+
97
+ def apply_templates(source)
98
+ transformation_result(:applyTemplates, source)
99
+ end
100
+
101
+ def call_template(template_name)
102
+ transformation_result(:callTemplate, Saxon::QName.resolve(template_name))
103
+ end
104
+
105
+ private
106
+
107
+ def transformation_result(invocation_method, invocation_arg)
108
+ set_opts!
109
+ transformer_args = [invocation_method, invocation_arg.to_java, destination].compact
110
+ Result.new(result_xdm_value(s9_transformer.send(*transformer_args)), s9_transformer)
111
+ end
112
+
113
+ def result_xdm_value(transformer_return_value)
114
+ XDM.Value(
115
+ transformer_return_value.nil? ? destination.getXdmNode : transformer_return_value
116
+ )
117
+ end
118
+
119
+ def destination
120
+ @destination ||= begin
121
+ Saxon::S9API::XdmDestination.new unless raw?
122
+ end
123
+ end
124
+
125
+ def set_opts!
126
+ opts.each do |opt, value|
127
+ send(opt, value)
128
+ end
129
+ end
130
+
131
+ def raw(value)
132
+ @raw = value
133
+ end
134
+
135
+ def raw?
136
+ @raw
137
+ end
138
+
139
+ def mode(mode_name)
140
+ s9_transformer.setInitialMode(Saxon::QName.resolve(mode_name).to_java)
141
+ end
142
+
143
+ def global_parameters(parameters)
144
+ s9_transformer.setStylesheetParameters(XSLT::ParameterHelper.to_java(parameters))
145
+ end
146
+
147
+ def initial_template_parameters(parameters)
148
+ s9_transformer.setInitialTemplateParameters(XSLT::ParameterHelper.to_java(parameters) , false)
149
+ end
150
+
151
+ def initial_template_tunnel_parameters(parameters)
152
+ s9_transformer.setInitialTemplateParameters(XSLT::ParameterHelper.to_java(parameters) , true)
153
+ end
154
+ end
155
+ end
156
+ end