saxon-rb 0.5.0-java → 0.7.3-java

Sign up to get free protection for your applications and to get access to all the features.
@@ -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