saxon-rb 0.5.0-java → 0.7.3-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 +32 -2
- data/.rspec-jar-loading +2 -0
- data/.ruby-version +1 -1
- data/.yardopts +1 -0
- data/README.md +42 -1
- data/Rakefile +8 -2
- data/docs/templates/plugin.rb +73 -0
- data/lib/saxon-rb.rb +0 -1
- data/lib/saxon/configuration.rb +15 -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 +116 -71
- data/lib/saxon/item_type/lexical_string_conversion.rb +78 -1
- data/lib/saxon/item_type/value_to_ruby.rb +12 -0
- data/lib/saxon/loader.rb +55 -43
- data/lib/saxon/nokogiri.rb +1 -1
- data/lib/saxon/processor.rb +18 -4
- 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/version.rb +7 -1
- data/lib/saxon/version/library.rb +89 -0
- data/lib/saxon/xdm/atomic_value.rb +16 -9
- data/lib/saxon/xdm/node.rb +34 -3
- data/lib/saxon/xpath/compiler.rb +2 -2
- data/lib/saxon/xpath/static_context.rb +6 -1
- data/lib/saxon/xslt/evaluation_context.rb +11 -1
- data/lib/saxon/xslt/executable.rb +35 -48
- data/lib/saxon/xslt/invocation.rb +97 -0
- data/saxon-rb.gemspec +2 -2
- metadata +17 -6
@@ -8,6 +8,7 @@ module Saxon
|
|
8
8
|
# Regexp patterns to assist in converting XDM typed values into Ruby
|
9
9
|
# native types
|
10
10
|
module Patterns
|
11
|
+
# @see https://www.w3.org/TR/xmlschema-2/#dateTime-lexical-representation
|
11
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/
|
12
13
|
end
|
13
14
|
|
@@ -54,34 +55,45 @@ module Saxon
|
|
54
55
|
# A collection of Lambdas (or objects responding to +#call+) for
|
55
56
|
# converting XDM typed values to native Ruby types.
|
56
57
|
module Convertors
|
58
|
+
# @see https://www.w3.org/TR/xmlschema-2/#integer
|
57
59
|
INTEGER = INT = SHORT = LONG = UNSIGNED_INT = UNSIGNED_SHORT = UNSIGNED_LONG = \
|
58
60
|
POSITIVE_INTEGER = NON_POSITIVE_INTEGER = NEGATIVE_INTEGER = NON_NEGATIVE_INTEGER = ->(xdm_atomic_value) {
|
59
61
|
xdm_atomic_value.to_java.getValue
|
60
62
|
}
|
63
|
+
# @see https://www.w3.org/TR/xmlschema-2/#decimal
|
61
64
|
DECIMAL = ->(xdm_atomic_value) {
|
62
65
|
BigDecimal(xdm_atomic_value.to_s)
|
63
66
|
}
|
67
|
+
# @see https://www.w3.org/TR/xmlschema-2/#float
|
64
68
|
FLOAT = DOUBLE = ->(xdm_atomic_value) {
|
65
69
|
xdm_atomic_value.to_java.getValue
|
66
70
|
}
|
71
|
+
# @see https://www.w3.org/TR/xmlschema-2/#dateTime
|
67
72
|
DATE_TIME = DATE_TIME_STAMP = ValueToRuby::DateTimeConvertor
|
73
|
+
# @see https://www.w3.org/TR/xmlschema-2/#boolean
|
68
74
|
BOOLEAN = ->(xdm_atomic_value) {
|
69
75
|
xdm_atomic_value.to_java.getValue
|
70
76
|
}
|
77
|
+
# @see https://www.w3.org/TR/xmlschema-2/#NOTATION
|
78
|
+
# @see https://www.w3.org/TR/xmlschema-2/#QName
|
71
79
|
NOTATION = QNAME = ->(xdm_atomic_value) {
|
72
80
|
Saxon::QName.new(xdm_atomic_value.to_java.getQNameValue)
|
73
81
|
}
|
82
|
+
# @see https://www.w3.org/TR/xmlschema-2/#base64Binary
|
74
83
|
BASE64_BINARY = ->(xdm_atomic_value) {
|
75
84
|
Base64.decode64(xdm_atomic_value.to_s)
|
76
85
|
}
|
86
|
+
# @see https://www.w3.org/TR/xmlschema-2/#hexBinary
|
77
87
|
HEX_BINARY = ->(xdm_atomic_value) {
|
78
88
|
bytes = []
|
79
89
|
xdm_atomic_value.to_s.scan(/../) { |x| bytes << x.hex.chr(Encoding::ASCII_8BIT) }
|
80
90
|
bytes.join
|
81
91
|
}
|
92
|
+
# @see https://www.w3.org/TR/xmlschema-2/#byte
|
82
93
|
BYTE = ->(xdm_atomic_value) {
|
83
94
|
[xdm_atomic_value.to_java.getLongValue].pack('c')
|
84
95
|
}
|
96
|
+
# @see https://www.w3.org/TR/xmlschema-2/#unsignedByte
|
85
97
|
UNSIGNED_BYTE = ->(xdm_atomic_value) {
|
86
98
|
[xdm_atomic_value.to_java.getLongValue].pack('C')
|
87
99
|
}
|
data/lib/saxon/loader.rb
CHANGED
@@ -19,6 +19,7 @@ module Saxon
|
|
19
19
|
@path = path
|
20
20
|
end
|
21
21
|
|
22
|
+
# returns an error message including the missing path
|
22
23
|
def to_s
|
23
24
|
"The path ('#{@path}') you supplied for the Saxon .jar files doesn't exist, sorry"
|
24
25
|
end
|
@@ -31,65 +32,76 @@ module Saxon
|
|
31
32
|
@path = path
|
32
33
|
end
|
33
34
|
|
35
|
+
# returns an error message including the path looked in and jars we were looking for
|
34
36
|
def to_s
|
35
37
|
"One of saxon9he.jar, saxon9pe.jar, or saxon9ee.jar must be present in the path ('#{@path}') you supplied, sorry"
|
36
38
|
end
|
37
39
|
end
|
38
40
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
LOAD_SEMAPHORE.synchronize do
|
46
|
-
if Saxon::S9API.const_defined?(:Processor)
|
41
|
+
class << self
|
42
|
+
# Are the Saxon jars missing from the Classpath?
|
43
|
+
# @return [Boolean] true if the Jars are not on the Classpath
|
44
|
+
def jars_not_on_classpath?
|
45
|
+
begin
|
46
|
+
Java::net.sf.saxon.s9api.Processor
|
47
47
|
false
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
48
|
+
rescue
|
49
|
+
true
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Are the Saxon JARs on the Classpath?
|
54
|
+
# @return [Boolean] whether the Jars are on the Classpath already
|
55
|
+
def jars_on_classpath?
|
56
|
+
!jars_not_on_classpath?
|
57
|
+
end
|
58
|
+
|
59
|
+
# @param saxon_home [String, Pathname] the path to the dir containing
|
60
|
+
# Saxon's .jars. Defaults to the vendored Saxon HE
|
61
|
+
# @return [true, false] Returns true if Saxon had not been loaded and
|
62
|
+
# is now, and false if Saxon was already loaded
|
63
|
+
def load!(saxon_home = nil)
|
64
|
+
return false if instance_variable_defined?(:@saxon_loaded) && @saxon_loaded
|
65
|
+
LOAD_SEMAPHORE.synchronize do
|
66
|
+
if Saxon::S9API.const_defined?(:Processor)
|
67
|
+
false
|
68
|
+
else
|
69
|
+
if jars_not_on_classpath?
|
70
|
+
if saxon_home.nil?
|
71
|
+
require 'saxon-rb_jars'
|
72
|
+
else
|
73
|
+
saxon_home = Pathname.new(saxon_home)
|
74
|
+
raise NoJarsError, saxon_home unless saxon_home.directory?
|
75
|
+
jars = [main_jar(saxon_home)].compact
|
76
|
+
raise MissingJarError if jars.empty?
|
77
|
+
jars += extra_jars(saxon_home)
|
58
78
|
|
59
|
-
|
79
|
+
add_jars_to_classpath!(saxon_home, jars)
|
80
|
+
end
|
60
81
|
end
|
61
|
-
end
|
62
82
|
|
63
|
-
|
64
|
-
|
83
|
+
@saxon_loaded = true
|
84
|
+
true
|
85
|
+
end
|
65
86
|
end
|
66
87
|
end
|
67
|
-
end
|
68
88
|
|
69
|
-
|
70
|
-
|
71
|
-
def self.main_jar(path)
|
72
|
-
['saxon9he.jar', 'saxon9pe.jar', 'saxon9ee.jar'].map { |jar| path.join(jar) }.find { |jar| jar.file? }
|
73
|
-
end
|
89
|
+
private
|
74
90
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
([icu] + optional).compact
|
79
|
-
end
|
91
|
+
def main_jar(path)
|
92
|
+
['saxon9he.jar', 'saxon9pe.jar', 'saxon9ee.jar'].map { |jar| path.join(jar) }.find { |jar| jar.file? }
|
93
|
+
end
|
80
94
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
rescue
|
86
|
-
true
|
95
|
+
def extra_jars(path)
|
96
|
+
optional = ['saxon9-unpack.jar', 'saxon9-sql.jar'].map { |jar| path.join(jar) }.select { |jar| jar.file? }
|
97
|
+
icu = path.children.find { |jar| jar.extname == '.jar' && !jar.basename.to_s.match(/^saxon-icu|^icu4j/).nil? }
|
98
|
+
([icu] + optional).compact
|
87
99
|
end
|
88
|
-
end
|
89
100
|
|
90
|
-
|
91
|
-
|
92
|
-
|
101
|
+
def add_jars_to_classpath!(saxon_home, jars)
|
102
|
+
jars.each do |jar|
|
103
|
+
$CLASSPATH << jar.to_s
|
104
|
+
end
|
93
105
|
end
|
94
106
|
end
|
95
107
|
end
|
data/lib/saxon/nokogiri.rb
CHANGED
@@ -44,7 +44,7 @@ module Saxon
|
|
44
44
|
# @return [String] a serialization of the the input document
|
45
45
|
def serialize(doc_node)
|
46
46
|
s9_transformer = @s9_xslt_executable.load30
|
47
|
-
serializer = Saxon::Serializer.new(s9_transformer.newSerializer)
|
47
|
+
serializer = Saxon::Serializer::Object.new(s9_transformer.newSerializer)
|
48
48
|
serializer.serialize(doc_node.to_java)
|
49
49
|
end
|
50
50
|
|
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
|
@@ -82,6 +85,17 @@ module Saxon
|
|
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
|
data/lib/saxon/serializer.rb
CHANGED
@@ -1,143 +1,9 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require_relative './serializer/destination.rb'
|
2
|
+
require_relative './serializer/object.rb'
|
3
3
|
|
4
4
|
module Saxon
|
5
5
|
# Serialize XDM objects.
|
6
|
-
|
7
|
-
# Manage access to the serialization properties of this serializer, with
|
8
|
-
# hash-like access.
|
9
|
-
#
|
10
|
-
# Properties can be set explicitly through this API, or via XSLT or XQuery
|
11
|
-
# serialization options like `<xsl:output>`.
|
12
|
-
#
|
13
|
-
# Properties set explicitly here will override properties set through the
|
14
|
-
# document like `<xsl:output>`.
|
15
|
-
class OutputProperties
|
16
|
-
# @api private
|
17
|
-
# Provides mapping between symbols and the underlying Saxon property
|
18
|
-
# instances
|
19
|
-
def self.output_properties
|
20
|
-
@output_properties ||= Hash[
|
21
|
-
Saxon::S9API::Serializer::Property.values.map { |property|
|
22
|
-
qname = property.getQName
|
23
|
-
key = [
|
24
|
-
qname.getPrefix,
|
25
|
-
qname.getLocalName.tr('-', '_')
|
26
|
-
].reject { |str| str == '' }.join('_').to_sym
|
27
|
-
[key, property]
|
28
|
-
}
|
29
|
-
]
|
30
|
-
end
|
31
|
-
|
32
|
-
attr_reader :s9_serializer
|
33
|
-
|
34
|
-
# @api private
|
35
|
-
def initialize(s9_serializer)
|
36
|
-
@s9_serializer = s9_serializer
|
37
|
-
end
|
38
|
-
|
39
|
-
# @param [Symbol, Saxon::S9API::Serializer::Property] property The property to fetch
|
40
|
-
def [](property)
|
41
|
-
s9_serializer.getOutputProperty(resolved_property(property))
|
42
|
-
end
|
43
|
-
|
44
|
-
# @param [Symbol, Saxon::S9API::Serializer::Property] property The property to set
|
45
|
-
# @param [String] value The string value of the property
|
46
|
-
def []=(property, value)
|
47
|
-
s9_serializer.setOutputProperty(resolved_property(property), value)
|
48
|
-
end
|
49
|
-
|
50
|
-
# @overload fetch(property)
|
51
|
-
# @param [Symbol, Saxon::S9API::Serializer::Property] property The property to fetch
|
52
|
-
# @overload fetch(property, default)
|
53
|
-
# @param property [Symbol, Saxon::S9API::Serializer::Property] The property to fetch
|
54
|
-
# @param default [Object] The value to return if the property is unset
|
55
|
-
def fetch(property, default = nil)
|
56
|
-
explicit_value = self[property]
|
57
|
-
if explicit_value.nil? && !default.nil?
|
58
|
-
default
|
59
|
-
else
|
60
|
-
explicit_value
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
private
|
65
|
-
def resolved_property(property_key)
|
66
|
-
case property_key
|
67
|
-
when Symbol
|
68
|
-
self.class.output_properties.fetch(property_key)
|
69
|
-
else
|
70
|
-
property_key
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
attr_reader :s9_serializer
|
76
|
-
private :s9_serializer
|
77
|
-
|
78
|
-
# @api private
|
79
|
-
def initialize(s9_serializer)
|
80
|
-
@s9_serializer = s9_serializer
|
81
|
-
end
|
82
|
-
|
83
|
-
# @return [Saxon::Serializer::OutputProperties] hash-like access to the Output Properties
|
84
|
-
def output_property
|
85
|
-
@output_property ||= OutputProperties.new(s9_serializer)
|
86
|
-
end
|
87
|
-
|
88
|
-
# @overload serialize(xdm_value, io)
|
89
|
-
# Serialize an XdmValue to an IO
|
90
|
-
# @param [Saxon::XdmValue] xdm_value The XdmValue to serialize
|
91
|
-
# @param [File, IO] io The IO to serialize to
|
92
|
-
# @return [nil]
|
93
|
-
# @overload serialize(xdm_value, path)
|
94
|
-
# Serialize an XdmValue to file <tt>path</tt>
|
95
|
-
# @param [Saxon::XdmValue] xdm_value The XdmValue to serialize
|
96
|
-
# @param [String, Pathname] path The path of the file to serialize to
|
97
|
-
# @return [nil]
|
98
|
-
# @overload serialize(xdm_value)
|
99
|
-
# Serialize an XdmValue to a String
|
100
|
-
# @param [Saxon::XdmValue] xdm_value The XdmValue to serialize
|
101
|
-
# @return [String] The serialized XdmValue
|
102
|
-
def serialize(xdm_value, io_or_path = nil)
|
103
|
-
case io_or_path
|
104
|
-
when nil
|
105
|
-
serialize_to_string(xdm_value)
|
106
|
-
when String, Pathname
|
107
|
-
serialize_to_file(xdm_value, io_or_path)
|
108
|
-
else
|
109
|
-
serialize_to_io(xdm_value, io_or_path)
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
# @return [Saxon::S9API::Serializer] The underlying Saxon Serializer object
|
114
|
-
def to_java
|
115
|
-
s9_serializer
|
116
|
-
end
|
117
|
-
|
118
|
-
private
|
119
|
-
|
120
|
-
def serialize_to_io(xdm_value, io)
|
121
|
-
s9_serializer.setOutputStream(io.to_outputstream)
|
122
|
-
s9_serializer.serializeXdmValue(xdm_value.to_java)
|
123
|
-
nil
|
124
|
-
end
|
125
|
-
|
126
|
-
def serialize_to_string(xdm_value)
|
127
|
-
str_encoding = output_property.fetch(:encoding, Encoding.default_internal || Encoding.default_external)
|
128
|
-
StringIO.open { |io|
|
129
|
-
io.binmode
|
130
|
-
serialize_to_io(xdm_value, io)
|
131
|
-
io.string.force_encoding(str_encoding)
|
132
|
-
}
|
133
|
-
end
|
134
|
-
|
135
|
-
def serialize_to_file(xdm_value, path)
|
136
|
-
file = Java::JavaIO::File.new(path)
|
137
|
-
s9_serializer.setOutputFile(file)
|
138
|
-
s9_serializer.serializeXdmValue(xdm_value.to_java)
|
139
|
-
nil
|
140
|
-
end
|
6
|
+
module Serializer
|
141
7
|
end
|
142
8
|
end
|
143
9
|
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require_relative '../s9api'
|
2
|
+
require_relative './output_properties'
|
3
|
+
|
4
|
+
module Saxon
|
5
|
+
module Serializer
|
6
|
+
# A Saxon Serializer to be used as a Destination for a transformation rather
|
7
|
+
# than being directly called with existing XDM objects
|
8
|
+
class Destination
|
9
|
+
include OutputProperties
|
10
|
+
|
11
|
+
attr_reader :s9_serializer, :invocation_lambda
|
12
|
+
|
13
|
+
# @api private
|
14
|
+
def initialize(s9_serializer, invocation_lambda, &block)
|
15
|
+
@s9_serializer, @invocation_lambda = s9_serializer, invocation_lambda
|
16
|
+
if block_given?
|
17
|
+
instance_exec(&block)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# @overload serialize(io)
|
22
|
+
# Serialize the transformation to an IO
|
23
|
+
# @param [File, IO] io The IO to serialize to
|
24
|
+
# @return [nil]
|
25
|
+
# @overload serialize(path)
|
26
|
+
# Serialize the transformation to file <tt>path</tt>
|
27
|
+
# @param [String, Pathname] path The path of the file to serialize to
|
28
|
+
# @return [nil]
|
29
|
+
# @overload serialize
|
30
|
+
# Serialize the transformation to a String
|
31
|
+
# @return [String] The serialized XdmValue
|
32
|
+
def serialize(io_or_path = nil)
|
33
|
+
case io_or_path
|
34
|
+
when nil
|
35
|
+
serialize_to_string
|
36
|
+
when String, Pathname
|
37
|
+
serialize_to_file(io_or_path)
|
38
|
+
else
|
39
|
+
serialize_to_io(io_or_path)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# @return [Saxon::S9API::Serializer] The underlying Saxon Serializer object
|
44
|
+
def to_java
|
45
|
+
s9_serializer
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def run_transform!
|
51
|
+
invocation_lambda.call(self.to_java)
|
52
|
+
end
|
53
|
+
|
54
|
+
def serialize_to_string
|
55
|
+
str_encoding = output_property.fetch(:encoding, Encoding.default_internal || Encoding.default_external)
|
56
|
+
StringIO.open { |io|
|
57
|
+
io.binmode
|
58
|
+
set_output_io(io)
|
59
|
+
run_transform!
|
60
|
+
io.string.force_encoding(str_encoding)
|
61
|
+
}
|
62
|
+
end
|
63
|
+
|
64
|
+
def serialize_to_io(io)
|
65
|
+
set_output_io(io)
|
66
|
+
run_transform!
|
67
|
+
end
|
68
|
+
|
69
|
+
def set_output_io(io)
|
70
|
+
s9_serializer.setOutputStream(io.to_outputstream)
|
71
|
+
end
|
72
|
+
|
73
|
+
def serialize_to_file(path)
|
74
|
+
file = Java::JavaIO::File.new(path.to_s)
|
75
|
+
s9_serializer.setOutputFile(file)
|
76
|
+
run_transform!
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|