saxon-rb 0.4.0-java → 0.5.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +429 -42
  3. data/Gemfile +2 -2
  4. data/README.md +317 -10
  5. data/Rakefile +237 -7
  6. 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
  7. data/lib/saxon-rb.rb +1 -0
  8. data/lib/{saxon_jars.rb → saxon-rb_jars.rb} +2 -2
  9. data/lib/saxon.rb +13 -0
  10. data/lib/saxon/axis_iterator.rb +8 -1
  11. data/lib/saxon/configuration.rb +1 -0
  12. data/lib/saxon/item_type.rb +12 -17
  13. data/lib/saxon/item_type/lexical_string_conversion.rb +136 -58
  14. data/lib/saxon/item_type/value_to_ruby.rb +13 -0
  15. data/lib/saxon/loader.rb +4 -1
  16. data/lib/saxon/nokogiri.rb +78 -0
  17. data/lib/saxon/occurrence_indicator.rb +32 -3
  18. data/lib/saxon/processor.rb +32 -1
  19. data/lib/saxon/qname.rb +37 -2
  20. data/lib/saxon/s9api.rb +5 -0
  21. data/lib/saxon/sequence_type.rb +131 -0
  22. data/lib/saxon/source.rb +207 -71
  23. data/lib/saxon/version.rb +1 -1
  24. data/lib/saxon/xdm.rb +7 -0
  25. data/lib/saxon/xdm/array.rb +16 -0
  26. data/lib/saxon/xdm/atomic_value.rb +7 -1
  27. data/lib/saxon/xdm/empty_sequence.rb +13 -0
  28. data/lib/saxon/xdm/external_object.rb +1 -0
  29. data/lib/saxon/xdm/function_item.rb +1 -0
  30. data/lib/saxon/xdm/item.rb +7 -0
  31. data/lib/saxon/xdm/map.rb +38 -0
  32. data/lib/saxon/xdm/node.rb +19 -1
  33. data/lib/saxon/xdm/sequence_like.rb +15 -0
  34. data/lib/saxon/xdm/value.rb +21 -5
  35. data/lib/saxon/xpath.rb +9 -0
  36. data/lib/saxon/xpath/compiler.rb +36 -1
  37. data/lib/saxon/xpath/executable.rb +53 -28
  38. data/lib/saxon/xpath/static_context.rb +19 -39
  39. data/lib/saxon/xpath/variable_declaration.rb +16 -49
  40. data/lib/saxon/xslt.rb +12 -0
  41. data/lib/saxon/xslt/compiler.rb +75 -6
  42. data/lib/saxon/xslt/evaluation_context.rb +19 -3
  43. data/lib/saxon/xslt/executable.rb +204 -14
  44. data/saxon-rb.gemspec +1 -1
  45. metadata +9 -7
  46. data/saxon.gemspec +0 -30
@@ -5,11 +5,18 @@ module Saxon
5
5
  # A collection of lamba-like objects for converting XDM::AtomicValues into
6
6
  # appropriate Ruby values
7
7
  module ValueToRuby
8
+ # Regexp patterns to assist in converting XDM typed values into Ruby
9
+ # native types
8
10
  module Patterns
9
11
  DATE_TIME = /\A(-?[0-9]{4,})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2}(?:\.[0-9]+)?)(Z|[-+][0-9]{2}:[0-9]{2})?\z/
10
12
  end
11
13
 
14
+ # Helper class that converts XDM Date/Time strings into something Ruby's {Time} class can
15
+ # handle
12
16
  class DateTimeConvertor
17
+ # Convert an XDM Date/Time value into a native Ruby {Time} object.
18
+ # @return [Time, String] the converted Time, or the original XDM lexical
19
+ # string if conversion isn't possible
13
20
  def self.call(xdm_atomic_value)
14
21
  new(xdm_atomic_value).convert
15
22
  end
@@ -21,11 +28,15 @@ module Saxon
21
28
  @match = ValueToRuby::Patterns::DATE_TIME.match(@timestring)
22
29
  end
23
30
 
31
+ # Return a {Time} instance if possible, otherwise return the string value from the XDM.
32
+ # @return [Time, String] the converted Time, or the original string
24
33
  def convert
25
34
  return timestring if match.nil?
26
35
  Time.new(*integer_parts, decimal_part, tz_part)
27
36
  end
28
37
 
38
+ private
39
+
29
40
  def integer_parts
30
41
  match[1..5].map { |n| Integer(n, 10) }
31
42
  end
@@ -40,6 +51,8 @@ module Saxon
40
51
  end
41
52
  end
42
53
 
54
+ # A collection of Lambdas (or objects responding to +#call+) for
55
+ # converting XDM typed values to native Ruby types.
43
56
  module Convertors
44
57
  INTEGER = INT = SHORT = LONG = UNSIGNED_INT = UNSIGNED_SHORT = UNSIGNED_LONG = \
45
58
  POSITIVE_INTEGER = NON_POSITIVE_INTEGER = NEGATIVE_INTEGER = NON_NEGATIVE_INTEGER = ->(xdm_atomic_value) {
data/lib/saxon/loader.rb CHANGED
@@ -6,8 +6,11 @@ module Saxon
6
6
  module S9API
7
7
  end
8
8
 
9
+ # The mechanism for adding the JARs for either the bundled Saxon HE, or an
10
+ # external Saxon HE/PE/EE version, into the CLASSPATH and requiring them.
9
11
  module Loader
10
12
  LOAD_SEMAPHORE = Mutex.new
13
+ private_constant :LOAD_SEMAPHORE
11
14
 
12
15
  # Error raised if Saxon::Loader.load! is called but the path handed
13
16
  # in does not exist or is not a directory
@@ -45,7 +48,7 @@ module Saxon
45
48
  else
46
49
  if jars_not_on_classpath?
47
50
  if saxon_home.nil?
48
- require 'saxon_jars'
51
+ require 'saxon-rb_jars'
49
52
  else
50
53
  saxon_home = Pathname.new(saxon_home)
51
54
  raise NoJarsError, saxon_home unless saxon_home.directory?
@@ -0,0 +1,78 @@
1
+ require 'saxon/xslt'
2
+
3
+ module Saxon
4
+ module XSLT
5
+ class Executable
6
+ # Provided for Nokogiri API compatibility. Cannot use many XSLT 2 and 3
7
+ # features as a result.
8
+ #
9
+ # Transform the input document by applying templates as in XSLT 1. All
10
+ # parameters will be interpreted as Strings
11
+ #
12
+ # @param doc_node [Saxon::XDM::Node] the document to transform
13
+ # @param params [Hash, Array] a Hash of param name => value, or an Array
14
+ # of param names and values of the form +['param', 'value', 'param2',
15
+ # 'value']+. The array must be of an even-numbered length
16
+ # @return [Saxon::XDM::Value] the result document
17
+ def transform(doc_node, params = {})
18
+ apply_templates(doc_node, v1_parameters(params)).xdm_value
19
+ end
20
+
21
+ # Provided for Nokogiri API compatibility. Cannot use many XSLT 2 and 3
22
+ # features as a result.
23
+ #
24
+ # Transform the input document by applying templates as in XSLT 1, and
25
+ # then serializing the result to a string using the serialization options
26
+ # set in the XSLT stylesheet's +<xsl:output/>+.
27
+ #
28
+ # @param doc_node [Saxon::XDM::Node] the document to transform
29
+ # @param params [Hash, Array] a Hash of param name => value, or an Array
30
+ # of param names and values of the form +['param', 'value', 'param2',
31
+ # 'value']+. The array must be of an even-numbered length
32
+ # @return [String] a serialization of the the result document
33
+ def apply_to(doc_node, params = {})
34
+ apply_templates(doc_node, v1_parameters(params)).to_s
35
+ end
36
+
37
+ # Provided for Nokogiri API compatibility. Cannot use many XSLT 2 and 3
38
+ # features as a result.
39
+ #
40
+ # Serialize the input document to a string using the serialization options
41
+ # set in the XSLT stylesheet's +<xsl:output/>+.
42
+ #
43
+ # @param doc_node [Saxon::XDM::Node] the document to serialize
44
+ # @return [String] a serialization of the the input document
45
+ def serialize(doc_node)
46
+ s9_transformer = @s9_xslt_executable.load30
47
+ serializer = Saxon::Serializer.new(s9_transformer.newSerializer)
48
+ serializer.serialize(doc_node.to_java)
49
+ end
50
+
51
+ private
52
+
53
+ def v1_parameters(params = [])
54
+ v1_params = v1_params_hash(params).map { |qname, value|
55
+ [Saxon::QName.resolve(qname), Saxon::XDM.AtomicValue(v1_param_value(value))]
56
+ }.to_h
57
+ return {} if v1_params.empty?
58
+ {global_parameters: v1_params}
59
+ end
60
+
61
+ def v1_params_hash(params = [])
62
+ return params if params.is_a?(Hash)
63
+ params.each_slice(2).map { |k,v|
64
+ raise ArgumentError.new("Odd number of values passed as params: #{params}") if v.nil?
65
+ [k, v]
66
+ }.to_h
67
+ end
68
+
69
+ def v1_param_value(value)
70
+ if /\A(['"]).+\1\z/.match(value)
71
+ value.slice(1..-2)
72
+ else
73
+ value
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -1,32 +1,61 @@
1
1
  require_relative 's9api'
2
2
 
3
3
  module Saxon
4
- # Provides simple access to Saxon's OccurrenceIndicator constants,
5
- # for use in declaring variable types
4
+ # Provides simple access to Saxon's OccurrenceIndicator constants, for
5
+ # declaring restrictions on the cardinality (length) of a sequence when, for
6
+ # example, defining a variable's type
6
7
  module OccurrenceIndicator
7
8
  class << self
9
+ # One thing
8
10
  def one
9
11
  @one ||= Saxon::S9API::OccurrenceIndicator::ONE
10
12
  end
11
13
 
14
+ # One or more things
12
15
  def one_or_more
13
16
  @one_or_more ||= Saxon::S9API::OccurrenceIndicator::ONE_OR_MORE
14
17
  end
15
18
 
19
+ # no things (the empty sequence)
16
20
  def zero
17
21
  @zero ||= Saxon::S9API::OccurrenceIndicator::ZERO
18
22
  end
19
23
 
24
+ # zero or more things
20
25
  def zero_or_more
21
26
  @zero_or_more ||= Saxon::S9API::OccurrenceIndicator::ZERO_OR_MORE
22
27
  end
23
28
 
29
+ # an optional thing
24
30
  def zero_or_one
25
31
  @zero_or_one ||= Saxon::S9API::OccurrenceIndicator::ZERO_OR_ONE
26
32
  end
27
33
 
34
+ # The list of valid occurence indicator names, as symbols. These
35
+ # correspond directly to the methods returning OccurrenceIndicators in
36
+ # this module.
37
+ #
38
+ # @return [Array<Symbol>] the indicator names
28
39
  def indicator_names
29
- @indicator_names ||= (public_methods(false) - Object.public_methods - [:indicator_names])
40
+ # .refine gets added to modules that have methods, so it's not in
41
+ # Module's public_methods list
42
+ @indicator_names ||= (public_methods(false) - Module.public_methods - [:indicator_names, :get_indicator, :refine])
43
+ end
44
+
45
+ # Return an OccurrenceIndicator given a name as a symbol. Passes through
46
+ # existing OccurrenceIndicator instances: this method is primarily for API
47
+ # use, most people will find it easier to directly call one of the
48
+ # methods, as in +OccurrenceIndicator.one+ rather than
49
+ # +OccurrenceIndicator.get_indicator(:one)+.
50
+ #
51
+ # @param indicator_name [Symbol, Saxon::S9API::OccurrenceIndicator] the name of the OccurrenceIndicator to return
52
+ # @return [Saxon::S9API::OccurrenceIndicator] the OccurrenceIndicator
53
+ def get_indicator(indicator_name)
54
+ return indicator_name if indicator_name.is_a?(Saxon::S9API::OccurrenceIndicator)
55
+ unless indicator_names.include?(indicator_name)
56
+ raise ArgumentError, "#{indicator_name.inspect} is not a valid indicator name (one of #{indicator_names.map(&:inspect).join(', ')})"
57
+ end
58
+ OccurrenceIndicator.send(indicator_name)
30
59
  end
31
60
  end
32
61
  end
@@ -76,7 +76,7 @@ module Saxon
76
76
  # <tt>Processor</tt>. Sharing <tt>XSLT::Compiler</tt>s across threads is
77
77
  # fine as long as the static context is not changed.
78
78
  #
79
- # @yield An XPath compiler DSL block, see {Saxon::XSLT::Compiler.create}
79
+ # @yield An XSLT compiler DSL block, see {Saxon::XSLT::Compiler.create}
80
80
  # @return [Saxon::XSLT::Compiler] a new XSLT compiler
81
81
  def xslt_compiler(&block)
82
82
  Saxon::XSLT::Compiler.create(self, &block)
@@ -98,5 +98,36 @@ module Saxon
98
98
  def config
99
99
  @config ||= Saxon::Configuration.create(self)
100
100
  end
101
+
102
+ # Create a {DocumentBuilder} and construct a {Source} and parse some XML.
103
+ # The args are passed to {Saxon::Source.create}, and the returned {Source}
104
+ # is parsed using {DocumentBuilder#build}. If a {Source} is passed in, parse
105
+ # that. Any options in +opts+ will be ignored in that case.
106
+ #
107
+ # @param input [Saxon::Source, IO, File, String, Pathname, URI] the input to
108
+ # be turned into a {Source} and parsed.
109
+ # @param opts [Hash] for Source creation. See {Saxon::Source.create}.
110
+ # @return [Saxon::XDM::Node] the XML document
111
+ def XML(input, opts = {})
112
+ source = Source.create(input, opts)
113
+ document_builder.build(source)
114
+ end
115
+
116
+ # Construct a {Source} containing an XSLT stylesheet, create an
117
+ # {XSLT::Compiler}, and compile the source, returning the {XSLT::Executable}
118
+ # produced. If a {Source} is passed as +input+, then it will be passed
119
+ # through to the compiler and any source-related options in +opts+ will be
120
+ # ignored.
121
+ #
122
+ # @param input [Saxon::Source, IO, File, String, Pathname, URI] the input to
123
+ # be turned into a {Source} and parsed.
124
+ # @param opts [Hash] for Source creation. See {Saxon::Source.create}.
125
+ # @yield the block is executed as an {XSLT::EvaluationContext::DSL} instance
126
+ # and applied to the compiler
127
+ # @return [Saxon::XSLT::Executable] the XSLT Executable
128
+ def XSLT(input, opts = {}, &block)
129
+ source = Source.create(input, opts)
130
+ xslt_compiler(&block).compile(source)
131
+ end
101
132
  end
102
133
  end
data/lib/saxon/qname.rb CHANGED
@@ -3,16 +3,39 @@ require 'saxon/s9api'
3
3
  module Saxon
4
4
  # Represents QNames
5
5
  class QName
6
+ # Create a {QName} from a Clark-notation string.
7
+ #
8
+ # Clark-notation for QNames uses +{}+ to delimit the namespace, so for a
9
+ # QName not in a namespace it's simply +local-name+, and for one in a
10
+ # namespace it's +{http://example.org/ns}local-name+
11
+ #
12
+ # @param clark_string [String] A QName in Clark notation.
13
+ # @return [Saxon::QName] A QName
6
14
  def self.clark(clark_string)
7
15
  s9_qname = Saxon::S9API::QName.fromClarkName(clark_string)
8
16
  new(s9_qname)
9
17
  end
10
18
 
19
+ # Create a {QName} from an Expanded QName string.
20
+ #
21
+ # Expanded QNames uses +Q{}+ to delimit the namespace, so for a
22
+ # QName not in a namespace it's simply +Q{}local-name+ (or +local-name}), and for one in a
23
+ # namespace it's +Q{http://example.org/ns}local-name+
24
+ #
25
+ # @param eqname_string [String] A QName in Expanded QName notation.
26
+ # @return [Saxon::QName] A QName
11
27
  def self.eqname(eqname_string)
12
28
  s9_qname = Saxon::S9API::QName.fromEQName(eqname_string)
13
29
  new(s9_qname)
14
30
  end
15
31
 
32
+ # Create a {QName} from prefix, uri, and local name options
33
+ #
34
+ # @param opts [Hash]
35
+ # @option [String] :prefix the namespace prefix to use (optional, requires +:uri+ passed too)
36
+ # @option [String] :uri the namespace URI to use (only required for QNames in a namespace)
37
+ # @option [String] :local_name the local-part of the QName. Required.
38
+ # @return [Saxon::QName] the QName
16
39
  def self.create(opts = {})
17
40
  prefix = opts[:prefix]
18
41
  uri = opts[:uri]
@@ -32,7 +55,7 @@ module Saxon
32
55
  # it's an instance of the underlying Saxon Java QName, it'll be wrapped
33
56
  # into a {Saxon::QName}
34
57
  #
35
- # If the arg is a string, it's resolved by using {resolve_variable_name}
58
+ # If the arg is a string, it's resolved by using {resolve_qname_string}
36
59
  #
37
60
  # @param qname_or_string [String, Symbol, Saxon::QName] the qname to resolve
38
61
  # @param namespaces [Hash<String => String>] the set of namespaces as a hash of <tt>"prefix" => "namespace-uri"</tt>
@@ -48,7 +71,7 @@ module Saxon
48
71
  end
49
72
  end
50
73
 
51
- # Resolve a QName string of the form <tt>"prefix:local-name"</tt> into a
74
+ # Resolve a QName string of the form +"prefix:local-name"+ into a
52
75
  # {Saxon::QName} by looking up the namespace URI in a hash of
53
76
  # <tt>"prefix" => "namespace-uri"</tt>
54
77
  #
@@ -110,12 +133,21 @@ module Saxon
110
133
  @s9_qname.getEQName
111
134
  end
112
135
 
136
+ # Compare this QName with another. They compare equal if they have same URI
137
+ # and local name. Prefix is ignored.
138
+ #
139
+ # @param other [Saxon::QName] the QName to compare against
140
+ # @return [Boolean] whether the two compare equal
113
141
  def ==(other)
114
142
  return false unless other.is_a?(QName)
115
143
  s9_qname.equals(other.to_java)
116
144
  end
117
145
  alias_method :eql?, :==
118
146
 
147
+ # Compute a hash-code for this {QName}.
148
+ #
149
+ # Two {QNames}s with the same local name and URI will have the same hash code (and will compare using eql?).
150
+ # @see Object#hash
119
151
  def hash
120
152
  @hash ||= (local_name + uri).hash
121
153
  end
@@ -134,6 +166,8 @@ module Saxon
134
166
  s9_qname.to_s
135
167
  end
136
168
 
169
+ # Returns a more detailed string representation of the object, showing
170
+ # prefix, uri, and local_name instance variables
137
171
  def inspect
138
172
  "<Saxon::QName @prefix=#{prefix} @uri=#{uri} @local_name=#{local_name}>"
139
173
  end
@@ -145,6 +179,7 @@ module Saxon
145
179
  @qname_string, @prefix = qname_string, prefix
146
180
  end
147
181
 
182
+ # The error message reports the unbound prefix and complete QName
148
183
  def to_s
149
184
  "Namespace prefix ‘#{@prefix}’ for QName ‘#{@qname_string}’ is not bound to a URI"
150
185
  end
data/lib/saxon/s9api.rb CHANGED
@@ -3,8 +3,13 @@ require 'saxon/loader'
3
3
  module Saxon
4
4
  module S9API
5
5
  CLASS_IMPORT_SEMAPHORE = Mutex.new
6
+ private_constant :CLASS_IMPORT_SEMAPHORE
6
7
 
7
8
  class << self
9
+ # Override the +const_missing+ hook in {S9API} so that we can delay
10
+ # loading the Saxon JARs until the user has had a chance to set an
11
+ # alternate location for them, if they don't want to use the bundled Saxon
12
+ # HE
8
13
  def const_missing(name)
9
14
  Saxon::Loader.load!
10
15
  begin
@@ -0,0 +1,131 @@
1
+ require_relative './item_type'
2
+ require_relative './occurrence_indicator'
3
+
4
+ module Saxon
5
+ # Represents a type definition for an XDM Sequence: an {ItemType} plus an
6
+ # {OccurrenceIndicator} as a restriction on the cardinality (length) of the
7
+ # sequence. Used most often to define variables in XPath or XSLT, plus in
8
+ # extension function definition.
9
+ class SequenceType
10
+ class << self
11
+ # Generate a {SequenceType} from a type declaration string (see
12
+ # {.from_type_decl}), or some combination of type name/Ruby class (see
13
+ # {ItemType.get_type}), and an {OccurrenceIndicator} or symbol referencing
14
+ # an OccurenceIndicator (one of +:zero_or_more+, +:one_or_more+,
15
+ # +:zero_or_one+, or +:one+)
16
+ #
17
+ # @return [Saxon::SequenceType] the resulting SequenceType
18
+ def create(type_name, occurrence_indicator = nil)
19
+ case type_name
20
+ when SequenceType
21
+ return type_name
22
+ when S9API::SequenceType
23
+ return new(type_name)
24
+ else
25
+ check_for_complete_decl!(type_name, occurrence_indicator)
26
+ return from_type_decl(type_name) if type_name.is_a?(String) && occurrence_indicator.nil?
27
+ item_type = ItemType.get_type(type_name)
28
+ occurrence_indicator = OccurrenceIndicator.get_indicator(occurrence_indicator)
29
+ new(item_type, occurrence_indicator)
30
+ end
31
+ end
32
+
33
+ # Generate a {SequenceType} from a declaration string following the rules
34
+ # of parameter and function +as=+ declarations in XSLT, like
35
+ # <tt><xsl:variable ... as="xs:string+"/></tt>
36
+ #
37
+ # @param type_decl [String] the declaration string
38
+ # @return [Saxon::SequenceType] the resulting SequenceType
39
+ def from_type_decl(type_decl)
40
+ occurence_char = type_decl[-1]
41
+ occurence = case occurence_char
42
+ when '?'
43
+ new(ItemType.get_type(type_decl[0..-2]), OccurrenceIndicator.zero_or_one)
44
+ when '+'
45
+ new(ItemType.get_type(type_decl[0..-2]), OccurrenceIndicator.one_or_more)
46
+ when '*'
47
+ new(ItemType.get_type(type_decl[0..-2]), OccurrenceIndicator.zero_or_more)
48
+ else
49
+ new(ItemType.get_type(type_decl), OccurrenceIndicator.one)
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ def check_for_complete_decl!(type_name, occurrence_indicator)
56
+ return true if occurrence_indicator.nil?
57
+ if type_name_is_complete_decl?(type_name)
58
+ raise ArgumentError, "Cannot pass a complete type declaration (#{type_name}) and an OccurrenceIndicator"
59
+ end
60
+ end
61
+
62
+ def type_name_is_complete_decl?(type_name)
63
+ !!(type_name.is_a?(String) && type_name.match(/[+*?]$/))
64
+ end
65
+ end
66
+
67
+ # @overload initialize(item_type, occurrence_indicator)
68
+ # creates new instance using item type and occurrence indicator
69
+ # @param item_type [Saxon::ItemType] the sequence's item type
70
+ # @param occurrence_indicator [net.sf.saxon.s9api.OccurrenceIndicator] the
71
+ # occurrence indicator (cardinality) of the sequence
72
+ # @overload initialize(s9_sequence_type)
73
+ # create a new instance by wrapping one of Saxon's underlying Java
74
+ # +SequenceType+s
75
+ # @param s9_sequence_type [net.sf.saxon.s9api.SequenceType]
76
+ # @return [Saxon::SequenceType] the new SequenceType
77
+ def initialize(item_type, occurrence_indicator = nil)
78
+ if occurrence_indicator.nil? && !item_type.is_a?(S9API::SequenceType)
79
+ raise ArgumentError, "Expected a Java s9api.SequenceType when handed a single argument, but got a #{item_type.class}"
80
+ end
81
+
82
+ if occurrence_indicator.nil?
83
+ @s9_sequence_type = item_type
84
+ else
85
+ @item_type = item_type
86
+ @occurrence_indicator = occurrence_indicator
87
+ end
88
+ end
89
+
90
+ # @return [Saxon::ItemType] the type's ItemType
91
+ def item_type
92
+ @item_type ||= Saxon::ItemType.get_type(s9_sequence_type.getItemType)
93
+ end
94
+
95
+ # @return [net.sf.saxon.s9api.OccurrenceIndicator] the type's OccurrenceIndicator
96
+ def occurrence_indicator
97
+ @occurrence_indicator ||= s9_sequence_type.getOccurrenceIndicator
98
+ end
99
+
100
+ # @return [net.sf.saxon.s9api.SequenceType] the underlying Saxon SequenceType
101
+ def to_java
102
+ s9_sequence_type
103
+ end
104
+
105
+ # Compare equal with another SequenceType
106
+ # @param other [Saxon::SequenceType]
107
+ # @return [Boolean] the result of comparing +self+ and +other+
108
+ def ==(other)
109
+ return false if other.class != self.class
110
+ item_type == other.item_type && occurrence_indicator == other.occurrence_indicator
111
+ end
112
+ alias_method :eql?, :==
113
+
114
+ # Generated hash code for use as keys in Hashes
115
+ def hash
116
+ @hash ||= item_type.hash ^ occurrence_indicator.hash
117
+ end
118
+
119
+ private
120
+
121
+ def s9_sequence_type
122
+ @s9_sequence_type ||= S9API::SequenceType.makeSequenceType(item_type.to_java, occurrence_indicator.to_java)
123
+ end
124
+ end
125
+
126
+ # Convenience wrapper for {SequenceType.create}
127
+ # @see SequenceType.create
128
+ def self.SequenceType(*args)
129
+ SequenceType.create(*args)
130
+ end
131
+ end