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.
- checksums.yaml +4 -4
- data/.circleci/config.yml +429 -42
- data/Gemfile +2 -2
- data/README.md +317 -10
- data/Rakefile +237 -7
- 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
- data/lib/saxon-rb.rb +1 -0
- data/lib/{saxon_jars.rb → saxon-rb_jars.rb} +2 -2
- data/lib/saxon.rb +13 -0
- data/lib/saxon/axis_iterator.rb +8 -1
- data/lib/saxon/configuration.rb +1 -0
- data/lib/saxon/item_type.rb +12 -17
- data/lib/saxon/item_type/lexical_string_conversion.rb +136 -58
- data/lib/saxon/item_type/value_to_ruby.rb +13 -0
- data/lib/saxon/loader.rb +4 -1
- data/lib/saxon/nokogiri.rb +78 -0
- data/lib/saxon/occurrence_indicator.rb +32 -3
- data/lib/saxon/processor.rb +32 -1
- data/lib/saxon/qname.rb +37 -2
- data/lib/saxon/s9api.rb +5 -0
- data/lib/saxon/sequence_type.rb +131 -0
- data/lib/saxon/source.rb +207 -71
- data/lib/saxon/version.rb +1 -1
- data/lib/saxon/xdm.rb +7 -0
- data/lib/saxon/xdm/array.rb +16 -0
- data/lib/saxon/xdm/atomic_value.rb +7 -1
- data/lib/saxon/xdm/empty_sequence.rb +13 -0
- data/lib/saxon/xdm/external_object.rb +1 -0
- data/lib/saxon/xdm/function_item.rb +1 -0
- data/lib/saxon/xdm/item.rb +7 -0
- data/lib/saxon/xdm/map.rb +38 -0
- data/lib/saxon/xdm/node.rb +19 -1
- data/lib/saxon/xdm/sequence_like.rb +15 -0
- data/lib/saxon/xdm/value.rb +21 -5
- data/lib/saxon/xpath.rb +9 -0
- data/lib/saxon/xpath/compiler.rb +36 -1
- data/lib/saxon/xpath/executable.rb +53 -28
- data/lib/saxon/xpath/static_context.rb +19 -39
- data/lib/saxon/xpath/variable_declaration.rb +16 -49
- data/lib/saxon/xslt.rb +12 -0
- data/lib/saxon/xslt/compiler.rb +75 -6
- data/lib/saxon/xslt/evaluation_context.rb +19 -3
- data/lib/saxon/xslt/executable.rb +204 -14
- data/saxon-rb.gemspec +1 -1
- metadata +9 -7
- 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 '
|
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
|
-
#
|
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
|
-
|
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
|
data/lib/saxon/processor.rb
CHANGED
@@ -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
|
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 {
|
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
|
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
|