saxon-rb 0.4.0-java → 0.7.2-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +429 -42
- data/.ruby-version +1 -1
- data/.yardopts +1 -0
- data/Gemfile +2 -2
- data/README.md +358 -10
- data/Rakefile +237 -7
- data/docs/templates/plugin.rb +73 -0
- 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 +0 -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 +16 -13
- data/lib/saxon/document_builder.rb +216 -5
- data/lib/saxon/feature_flags.rb +11 -0
- data/lib/saxon/feature_flags/errors.rb +8 -0
- data/lib/saxon/feature_flags/helpers.rb +15 -0
- data/lib/saxon/feature_flags/version.rb +100 -0
- data/lib/saxon/item_type.rb +129 -89
- data/lib/saxon/item_type/lexical_string_conversion.rb +214 -59
- data/lib/saxon/item_type/value_to_ruby.rb +25 -0
- data/lib/saxon/loader.rb +6 -1
- data/lib/saxon/nokogiri.rb +78 -0
- data/lib/saxon/occurrence_indicator.rb +32 -3
- data/lib/saxon/processor.rb +50 -5
- 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/serializer.rb +3 -137
- data/lib/saxon/serializer/destination.rb +80 -0
- data/lib/saxon/serializer/object.rb +93 -0
- data/lib/saxon/serializer/output_properties.rb +83 -0
- data/lib/saxon/source.rb +207 -71
- data/lib/saxon/version.rb +7 -1
- data/lib/saxon/version/library.rb +89 -0
- data/lib/saxon/xdm.rb +7 -0
- data/lib/saxon/xdm/array.rb +16 -0
- data/lib/saxon/xdm/atomic_value.rb +10 -2
- 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 +50 -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 +37 -2
- data/lib/saxon/xpath/executable.rb +53 -28
- data/lib/saxon/xpath/static_context.rb +25 -40
- 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 +30 -4
- data/lib/saxon/xslt/executable.rb +206 -29
- data/lib/saxon/xslt/invocation.rb +97 -0
- data/saxon-rb.gemspec +3 -3
- metadata +22 -10
- data/saxon.gemspec +0 -30
@@ -5,11 +5,19 @@ 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
|
11
|
+
# @see https://www.w3.org/TR/xmlschema-2/#dateTime-lexical-representation
|
9
12
|
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
13
|
end
|
11
14
|
|
15
|
+
# Helper class that converts XDM Date/Time strings into something Ruby's {Time} class can
|
16
|
+
# handle
|
12
17
|
class DateTimeConvertor
|
18
|
+
# Convert an XDM Date/Time value into a native Ruby {Time} object.
|
19
|
+
# @return [Time, String] the converted Time, or the original XDM lexical
|
20
|
+
# string if conversion isn't possible
|
13
21
|
def self.call(xdm_atomic_value)
|
14
22
|
new(xdm_atomic_value).convert
|
15
23
|
end
|
@@ -21,11 +29,15 @@ module Saxon
|
|
21
29
|
@match = ValueToRuby::Patterns::DATE_TIME.match(@timestring)
|
22
30
|
end
|
23
31
|
|
32
|
+
# Return a {Time} instance if possible, otherwise return the string value from the XDM.
|
33
|
+
# @return [Time, String] the converted Time, or the original string
|
24
34
|
def convert
|
25
35
|
return timestring if match.nil?
|
26
36
|
Time.new(*integer_parts, decimal_part, tz_part)
|
27
37
|
end
|
28
38
|
|
39
|
+
private
|
40
|
+
|
29
41
|
def integer_parts
|
30
42
|
match[1..5].map { |n| Integer(n, 10) }
|
31
43
|
end
|
@@ -40,35 +52,48 @@ module Saxon
|
|
40
52
|
end
|
41
53
|
end
|
42
54
|
|
55
|
+
# A collection of Lambdas (or objects responding to +#call+) for
|
56
|
+
# converting XDM typed values to native Ruby types.
|
43
57
|
module Convertors
|
58
|
+
# @see https://www.w3.org/TR/xmlschema-2/#integer
|
44
59
|
INTEGER = INT = SHORT = LONG = UNSIGNED_INT = UNSIGNED_SHORT = UNSIGNED_LONG = \
|
45
60
|
POSITIVE_INTEGER = NON_POSITIVE_INTEGER = NEGATIVE_INTEGER = NON_NEGATIVE_INTEGER = ->(xdm_atomic_value) {
|
46
61
|
xdm_atomic_value.to_java.getValue
|
47
62
|
}
|
63
|
+
# @see https://www.w3.org/TR/xmlschema-2/#decimal
|
48
64
|
DECIMAL = ->(xdm_atomic_value) {
|
49
65
|
BigDecimal(xdm_atomic_value.to_s)
|
50
66
|
}
|
67
|
+
# @see https://www.w3.org/TR/xmlschema-2/#float
|
51
68
|
FLOAT = DOUBLE = ->(xdm_atomic_value) {
|
52
69
|
xdm_atomic_value.to_java.getValue
|
53
70
|
}
|
71
|
+
# @see https://www.w3.org/TR/xmlschema-2/#dateTime
|
54
72
|
DATE_TIME = DATE_TIME_STAMP = ValueToRuby::DateTimeConvertor
|
73
|
+
# @see https://www.w3.org/TR/xmlschema-2/#boolean
|
55
74
|
BOOLEAN = ->(xdm_atomic_value) {
|
56
75
|
xdm_atomic_value.to_java.getValue
|
57
76
|
}
|
77
|
+
# @see https://www.w3.org/TR/xmlschema-2/#NOTATION
|
78
|
+
# @see https://www.w3.org/TR/xmlschema-2/#QName
|
58
79
|
NOTATION = QNAME = ->(xdm_atomic_value) {
|
59
80
|
Saxon::QName.new(xdm_atomic_value.to_java.getQNameValue)
|
60
81
|
}
|
82
|
+
# @see https://www.w3.org/TR/xmlschema-2/#base64Binary
|
61
83
|
BASE64_BINARY = ->(xdm_atomic_value) {
|
62
84
|
Base64.decode64(xdm_atomic_value.to_s)
|
63
85
|
}
|
86
|
+
# @see https://www.w3.org/TR/xmlschema-2/#hexBinary
|
64
87
|
HEX_BINARY = ->(xdm_atomic_value) {
|
65
88
|
bytes = []
|
66
89
|
xdm_atomic_value.to_s.scan(/../) { |x| bytes << x.hex.chr(Encoding::ASCII_8BIT) }
|
67
90
|
bytes.join
|
68
91
|
}
|
92
|
+
# @see https://www.w3.org/TR/xmlschema-2/#byte
|
69
93
|
BYTE = ->(xdm_atomic_value) {
|
70
94
|
[xdm_atomic_value.to_java.getLongValue].pack('c')
|
71
95
|
}
|
96
|
+
# @see https://www.w3.org/TR/xmlschema-2/#unsignedByte
|
72
97
|
UNSIGNED_BYTE = ->(xdm_atomic_value) {
|
73
98
|
[xdm_atomic_value.to_java.getLongValue].pack('C')
|
74
99
|
}
|
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
|
@@ -16,6 +19,7 @@ module Saxon
|
|
16
19
|
@path = path
|
17
20
|
end
|
18
21
|
|
22
|
+
# returns an error message including the missing path
|
19
23
|
def to_s
|
20
24
|
"The path ('#{@path}') you supplied for the Saxon .jar files doesn't exist, sorry"
|
21
25
|
end
|
@@ -28,6 +32,7 @@ module Saxon
|
|
28
32
|
@path = path
|
29
33
|
end
|
30
34
|
|
35
|
+
# returns an error message including the path looked in and jars we were looking for
|
31
36
|
def to_s
|
32
37
|
"One of saxon9he.jar, saxon9pe.jar, or saxon9ee.jar must be present in the path ('#{@path}') you supplied, sorry"
|
33
38
|
end
|
@@ -45,7 +50,7 @@ module Saxon
|
|
45
50
|
else
|
46
51
|
if jars_not_on_classpath?
|
47
52
|
if saxon_home.nil?
|
48
|
-
require '
|
53
|
+
require 'saxon-rb_jars'
|
49
54
|
else
|
50
55
|
saxon_home = Pathname.new(saxon_home)
|
51
56
|
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::Object.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
@@ -4,6 +4,7 @@ require 'saxon/configuration'
|
|
4
4
|
require 'saxon/document_builder'
|
5
5
|
require 'saxon/xpath'
|
6
6
|
require 'saxon/xslt'
|
7
|
+
require 'saxon/serializer'
|
7
8
|
|
8
9
|
module Saxon
|
9
10
|
# Saxon::Processor wraps the S9API::Processor object. This is the object
|
@@ -45,12 +46,14 @@ module Saxon
|
|
45
46
|
@s9_processor = s9_processor
|
46
47
|
end
|
47
48
|
|
48
|
-
# Generate a new DocumentBuilder that uses this Processor.
|
49
|
-
#
|
49
|
+
# Generate a new DocumentBuilder that uses this Processor. Sharing
|
50
|
+
# DocumentBuilders across threads is not safe.
|
50
51
|
#
|
52
|
+
# @yield A DocumentBuilder configuration DSL block, see
|
53
|
+
# {Saxon::DocumentBuilder.create}
|
51
54
|
# @return [Saxon::DocumentBuilder] A new Saxon::DocumentBuilder
|
52
|
-
def document_builder
|
53
|
-
Saxon::DocumentBuilder.
|
55
|
+
def document_builder(&block)
|
56
|
+
Saxon::DocumentBuilder.create(self, &block)
|
54
57
|
end
|
55
58
|
|
56
59
|
# Declare custom collations for use by XSLT, XPath, and XQuery processors
|
@@ -76,12 +79,23 @@ module Saxon
|
|
76
79
|
# <tt>Processor</tt>. Sharing <tt>XSLT::Compiler</tt>s across threads is
|
77
80
|
# fine as long as the static context is not changed.
|
78
81
|
#
|
79
|
-
# @yield An
|
82
|
+
# @yield An XSLT compiler DSL block, see {Saxon::XSLT::Compiler.create}
|
80
83
|
# @return [Saxon::XSLT::Compiler] a new XSLT compiler
|
81
84
|
def xslt_compiler(&block)
|
82
85
|
Saxon::XSLT::Compiler.create(self, &block)
|
83
86
|
end
|
84
87
|
|
88
|
+
# Generate a new +Serializer+ for directly serializing XDM Values that uses
|
89
|
+
# this +Processor+. +Serializer+s are effectively one-shot objects, and
|
90
|
+
# shouldn't be reused.
|
91
|
+
#
|
92
|
+
# @yield the block passed will be called bound to the serializer instance. See
|
93
|
+
# {Saxon::Serializer::Object.create}
|
94
|
+
# @return [Saxon::Serializer::Object]
|
95
|
+
def serializer(&block)
|
96
|
+
Saxon::Serializer::Object.create(self, &block)
|
97
|
+
end
|
98
|
+
|
85
99
|
# @return [net.sf.saxon.s9api.Processor] The underlying Saxon processor
|
86
100
|
def to_java
|
87
101
|
@s9_processor
|
@@ -98,5 +112,36 @@ module Saxon
|
|
98
112
|
def config
|
99
113
|
@config ||= Saxon::Configuration.create(self)
|
100
114
|
end
|
115
|
+
|
116
|
+
# Create a {DocumentBuilder} and construct a {Source} and parse some XML.
|
117
|
+
# The args are passed to {Saxon::Source.create}, and the returned {Source}
|
118
|
+
# is parsed using {DocumentBuilder#build}. If a {Source} is passed in, parse
|
119
|
+
# that. Any options in +opts+ will be ignored in that case.
|
120
|
+
#
|
121
|
+
# @param input [Saxon::Source, IO, File, String, Pathname, URI] the input to
|
122
|
+
# be turned into a {Source} and parsed.
|
123
|
+
# @param opts [Hash] for Source creation. See {Saxon::Source.create}.
|
124
|
+
# @return [Saxon::XDM::Node] the XML document
|
125
|
+
def XML(input, opts = {})
|
126
|
+
source = Source.create(input, opts)
|
127
|
+
document_builder.build(source)
|
128
|
+
end
|
129
|
+
|
130
|
+
# Construct a {Source} containing an XSLT stylesheet, create an
|
131
|
+
# {XSLT::Compiler}, and compile the source, returning the {XSLT::Executable}
|
132
|
+
# produced. If a {Source} is passed as +input+, then it will be passed
|
133
|
+
# through to the compiler and any source-related options in +opts+ will be
|
134
|
+
# ignored.
|
135
|
+
#
|
136
|
+
# @param input [Saxon::Source, IO, File, String, Pathname, URI] the input to
|
137
|
+
# be turned into a {Source} and parsed.
|
138
|
+
# @param opts [Hash] for Source creation. See {Saxon::Source.create}.
|
139
|
+
# @yield the block is executed as an {XSLT::EvaluationContext::DSL} instance
|
140
|
+
# and applied to the compiler
|
141
|
+
# @return [Saxon::XSLT::Executable] the XSLT Executable
|
142
|
+
def XSLT(input, opts = {}, &block)
|
143
|
+
source = Source.create(input, opts)
|
144
|
+
xslt_compiler(&block).compile(source)
|
145
|
+
end
|
101
146
|
end
|
102
147
|
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
|