saxon-rb 0.4.0-java → 0.5.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 (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