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.
@@ -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
  }
@@ -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
- # @param saxon_home [String, Pathname] the path to the dir containing
40
- # Saxon's .jars. Defaults to the vendored Saxon HE
41
- # @return [true, false] Returns true if Saxon had not been loaded and
42
- # is now, and false if Saxon was already loaded
43
- def self.load!(saxon_home = nil)
44
- return false if instance_variable_defined?(:@saxon_loaded) && @saxon_loaded
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
- else
49
- if jars_not_on_classpath?
50
- if saxon_home.nil?
51
- require 'saxon-rb_jars'
52
- else
53
- saxon_home = Pathname.new(saxon_home)
54
- raise NoJarsError, saxon_home unless saxon_home.directory?
55
- jars = [main_jar(saxon_home)].compact
56
- raise MissingJarError if jars.empty?
57
- jars += extra_jars(saxon_home)
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
- add_jars_to_classpath!(saxon_home, jars)
79
+ add_jars_to_classpath!(saxon_home, jars)
80
+ end
60
81
  end
61
- end
62
82
 
63
- @saxon_loaded = true
64
- true
83
+ @saxon_loaded = true
84
+ true
85
+ end
65
86
  end
66
87
  end
67
- end
68
88
 
69
- private
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
- def self.extra_jars(path)
76
- optional = ['saxon9-unpack.jar', 'saxon9-sql.jar'].map { |jar| path.join(jar) }.select { |jar| jar.file? }
77
- icu = path.children.find { |jar| jar.extname == '.jar' && !jar.basename.to_s.match(/^saxon-icu|^icu4j/).nil? }
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
- def self.jars_not_on_classpath?
82
- begin
83
- Java::net.sf.saxon.s9api.Processor
84
- false
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
- def self.add_jars_to_classpath!(saxon_home, jars)
91
- jars.each do |jar|
92
- $CLASSPATH << jar.to_s
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
@@ -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
 
@@ -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
- # Sharing DocumentBuilders across threads is not recommended/
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.new(@s9_processor.newDocumentBuilder)
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
@@ -1,143 +1,9 @@
1
- require 'saxon/s9api'
2
- require 'stringio'
1
+ require_relative './serializer/destination.rb'
2
+ require_relative './serializer/object.rb'
3
3
 
4
4
  module Saxon
5
5
  # Serialize XDM objects.
6
- class Serializer
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