saxon 0.1.0-java

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,16 @@
1
+ require 'saxon/loader'
2
+
3
+ module Saxon
4
+ module S9API
5
+ def self.const_missing(name)
6
+ Saxon::Loader.load!
7
+ begin
8
+ const_get(name)
9
+ rescue NameError
10
+ msg = "uninitialized constant Saxon::S9API::#{name}"
11
+ e = NameError.new(msg, name)
12
+ raise e
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,143 @@
1
+ require 'saxon/s9api'
2
+ require 'stringio'
3
+
4
+ module Saxon
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
141
+ end
142
+ end
143
+
@@ -0,0 +1,187 @@
1
+ require 'java'
2
+ require 'saxon/jaxp'
3
+ require 'uri'
4
+ require 'pathname'
5
+
6
+ module Saxon
7
+ # Provides a wrapper around the JAXP StreamSource class Saxon uses to bring
8
+ # the XML bytestream in. Provides some extra methods to make handling closing
9
+ # the source and its inputstream after consumption more idiomatic
10
+ class Source
11
+ module Helpers
12
+ # Given a File, or IO object which will return either #path or
13
+ # #base_uri, return the #base_uri, if present, or the #path, if present, or
14
+ # nil
15
+ # @param [File, IO] io A File or IO
16
+ # object representing the input XML file or data, or a String containing
17
+ # the XML
18
+ # @return [String, nil] the path or URI from the IO (or nil if there is none)
19
+ def self.base_uri(io)
20
+ if io.respond_to?(:base_uri)
21
+ return io.base_uri.to_s
22
+ end
23
+ io.path if io.respond_to?(:path)
24
+ end
25
+
26
+ # Given a File or IO return a Java InputStream
27
+ # @param [File, IO, org.jruby.util.IOInputStream, java.io.InputStream]
28
+ # io input to be converted to an input stream
29
+ # @return [java.io.InputStream] the wrapped input
30
+ def self.inputstream(io)
31
+ case io
32
+ when org.jruby.util.IOInputStream, java.io.InputStream
33
+ io
34
+ else
35
+ io.to_inputstream if io.respond_to?(:read)
36
+ end
37
+ end
38
+
39
+ # Given a path return a Java File object
40
+ # @param [String, Pathname] path the path to the file
41
+ # @return [java.io.File] the Java File object
42
+ def self.file(path)
43
+ java.io.File.new(path.to_s)
44
+ end
45
+ end
46
+
47
+ PathChecker = ->(path) {
48
+ File.file?(path)
49
+ }
50
+ URIChecker = ->(uri) {
51
+ begin
52
+ URI.parse(uri)
53
+ true
54
+ rescue URI::InvalidURIError
55
+ false
56
+ end
57
+ }
58
+
59
+ # Generate a Saxon::Source given an IO-like
60
+ #
61
+ # @param [IO, File] io The IO-like containing XML to be parsed
62
+ # @param [Hash] opts
63
+ # @option opts [String] :base_uri The Base URI for the Source - an
64
+ # absolute URI or relative path that will be used to resolve relative
65
+ # URLs in the XML. Setting this will override any path or URI derived
66
+ # from the IO-like.
67
+ # @return [Saxon::Source] the Saxon::Source wrapping the input
68
+ def self.from_io(io, opts = {})
69
+ base_uri = opts.fetch(:base_uri) { Helpers.base_uri(io) }
70
+ inputstream = Helpers.inputstream(io)
71
+ stream_source = Saxon::JAXP::StreamSource.new(inputstream, base_uri)
72
+ new(stream_source, inputstream)
73
+ end
74
+
75
+ # Generate a Saxon::Source given a path to a file
76
+ #
77
+ # @param [String, Pathname] path The path to the XML file to be parsed
78
+ # @param [Hash] opts
79
+ # @option opts [String] :base_uri The Base URI for the Source - an
80
+ # absolute URI or relative path that will be used to resolve relative
81
+ # URLs in the XML. Setting this will override the file path.
82
+ # @return [Saxon::Source] the Saxon::Source wrapping the input
83
+ def self.from_path(path, opts = {})
84
+ stream_source = Saxon::JAXP::StreamSource.new(Helpers.file(path))
85
+ stream_source.setSystemId(opts[:base_uri]) if opts[:base_uri]
86
+ new(stream_source)
87
+ end
88
+
89
+ # Generate a Saxon::Source given a URI
90
+ #
91
+ # @param [String, URI] uri The URI to the XML file to be parsed
92
+ # @param [Hash] opts
93
+ # @option opts [String] :base_uri The Base URI for the Source - an
94
+ # absolute URI or relative path that will be used to resolve relative
95
+ # URLs in the XML. Setting this will override the given URI.
96
+ # @return [Saxon::Source] the Saxon::Source wrapping the input
97
+ def self.from_uri(uri, opts = {})
98
+ stream_source = Saxon::JAXP::StreamSource.new(uri.to_s)
99
+ stream_source.setSystemId(opts[:base_uri]) if opts[:base_uri]
100
+ new(stream_source)
101
+ end
102
+
103
+ # Generate a Saxon::Source given a string containing XML
104
+ #
105
+ # @param [String] string The string containing XML to be parsed
106
+ # @param [Hash] opts
107
+ # @option opts [String] :base_uri The Base URI for the Source - an
108
+ # absolute URI or relative path that will be used to resolve relative
109
+ # URLs in the XML. This will be nil unless set.
110
+ # @return [Saxon::Source] the Saxon::Source wrapping the input
111
+ def self.from_string(string, opts = {})
112
+ reader = java.io.StringReader.new(string)
113
+ stream_source = Saxon::JAXP::StreamSource.new(reader)
114
+ stream_source.setSystemId(opts[:base_uri]) if opts[:base_uri]
115
+ new(stream_source, reader)
116
+ end
117
+
118
+ def self.create(io_path_uri_or_string, opts = {})
119
+ case io_path_uri_or_string
120
+ when IO, File, java.io.InputStream
121
+ from_io(io_path_uri_or_string, opts)
122
+ when Pathname, PathChecker
123
+ from_file(io_path_uri_or_string, opts)
124
+ when URIChecker
125
+ from_uri(io_path_uri_or_string, opts)
126
+ else
127
+ from_string(io_path_uri_or_string, opts)
128
+ end
129
+ end
130
+
131
+ attr_reader :stream_source, :inputstream
132
+ private :stream_source, :inputstream
133
+
134
+ # @api private
135
+ # @param [java.xml.transform.stream.StreamSource] stream_source The Java JAXP StreamSource
136
+ # @param [java.io.InputStream, java.io.StringReader] inputstream The Java InputStream or StringReader
137
+ def initialize(stream_source, inputstream = nil)
138
+ @stream_source = stream_source
139
+ @inputstream = inputstream
140
+ @closed = false
141
+ end
142
+
143
+ # @return [String] The base URI of the Source
144
+ def base_uri
145
+ stream_source.getSystemId
146
+ end
147
+
148
+ # @param [String, URI] uri The URI to use as the Source's Base URI
149
+ # @return [String] The new base URI of the Source
150
+ def base_uri=(uri)
151
+ stream_source.setSystemId(uri.to_s)
152
+ base_uri
153
+ end
154
+
155
+ # Close the Source and its associated InputStream or Reader, allowing those
156
+ # resources to be freed.
157
+ # @return [TrueClass] Returns true
158
+ def close
159
+ inputstream.close
160
+ @closed = true
161
+ end
162
+
163
+ # @return [Boolean] Returns true if the source is closed, false otherwise
164
+ def closed?
165
+ @closed
166
+ end
167
+
168
+ # Yields itself and then closes itself. To be used by DocumentBuilders or
169
+ # other consumers, making it easy to ensure the source is closed after it
170
+ # has been consumed.
171
+ #
172
+ # @raise [Saxon::SourceClosedError] if the Source has already been closed
173
+ # @yield [source] Yields self to the block
174
+ def consume(&block)
175
+ raise SourceClosedError if closed?
176
+ block.call(self)
177
+ close
178
+ end
179
+
180
+ # @return [java.xml.transform.stream.StreamSource] The underlying JAXP StreamSource
181
+ def to_java
182
+ @stream_source
183
+ end
184
+ end
185
+
186
+ class SourceClosedError < Exception; end
187
+ end
@@ -0,0 +1,3 @@
1
+ module Saxon
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,48 @@
1
+ require_relative 'qname'
2
+
3
+ module Saxon
4
+ # An XPath Data Model Node object, representing an XML document, or an element or one of the other node chunks in the XDM.
5
+ class XdmAtomicValue
6
+ # convert a single Ruby value into an XdmAtomicValue
7
+ #
8
+ # @param value the value to convert
9
+ # @return [Saxon::XdmAtomicValue]
10
+ def self.create(value)
11
+ new(Saxon::S9API::XdmAtomicValue.new(value))
12
+ end
13
+
14
+ attr_reader :s9_xdm_atomic_value
15
+ private :s9_xdm_atomic_value
16
+
17
+ # @api private
18
+ def initialize(s9_xdm_atomic_value)
19
+ @s9_xdm_atomic_value = s9_xdm_atomic_value
20
+ end
21
+
22
+ # Return a {QName} representing the type of the value
23
+ #
24
+ # @return [Saxon::QName] the {QName} of the value's type
25
+ def type_name
26
+ @type_name ||= Saxon::QName.new(s9_xdm_atomic_value.getTypeName)
27
+ end
28
+
29
+ # @return [Saxon::S9API::XdmAtomicValue] The underlying Saxon Java XDM atomic value object.
30
+ def to_java
31
+ s9_xdm_atomic_value
32
+ end
33
+
34
+ # compares two {XdmAtomicValue}s using the underlying Saxon and XDM comparision rules
35
+ # @param other [Saxon::XdmAtomicValue]
36
+ # @return [Boolean]
37
+ def ==(other)
38
+ return false unless other.is_a?(XdmAtomicValue)
39
+ s9_xdm_atomic_value.equals(other.to_java)
40
+ end
41
+
42
+ alias_method :eql?, :==
43
+
44
+ def hash
45
+ @hash ||= s9_xdm_atomic_value.hashCode
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,65 @@
1
+ require_relative 'axis_iterator'
2
+
3
+ module Saxon
4
+ # An XPath Data Model Node object, representing an XML document, or an element or one of the other node chunks in the XDM.
5
+ class XdmNode
6
+ include Enumerable
7
+
8
+ attr_reader :s9_xdm_node
9
+ private :s9_xdm_node
10
+
11
+ # @api private
12
+ def initialize(s9_xdm_node)
13
+ @s9_xdm_node = s9_xdm_node
14
+ end
15
+
16
+ # @return [Saxon::S9API::XdmNode] The underlying Saxon Java XDM node object.
17
+ def to_java
18
+ @s9_xdm_node
19
+ end
20
+
21
+ def node_name
22
+ return @node_name if instance_variable_defined?(:@node_name)
23
+ node_name = s9_xdm_node.getNodeName
24
+ @node_name = node_name.nil? ? nil : Saxon::QName.new(node_name)
25
+ end
26
+
27
+ def node_kind
28
+ @node_kind ||= case s9_xdm_node.nodeKind
29
+ when Saxon::S9API::XdmNodeKind::ELEMENT
30
+ :element
31
+ when Saxon::S9API::XdmNodeKind::TEXT
32
+ :text
33
+ when Saxon::S9API::XdmNodeKind::ATTRIBUTE
34
+ :attribute
35
+ when Saxon::S9API::XdmNodeKind::NAMESPACE
36
+ :namespace
37
+ when Saxon::S9API::XdmNodeKind::COMMENT
38
+ :comment
39
+ when Saxon::S9API::XdmNodeKind::PROCESSING_INSTRUCTION
40
+ :processing_instruction
41
+ when Saxon::S9API::XdmNodeKind::DOCUMENT
42
+ :document
43
+ end
44
+ end
45
+
46
+ def ==(other)
47
+ return false unless other.is_a?(XdmNode)
48
+ s9_xdm_node.equals(other.to_java)
49
+ end
50
+
51
+ alias_method :eql?, :==
52
+
53
+ def hash
54
+ @hash ||= s9_xdm_node.hashCode
55
+ end
56
+
57
+ def each(&block)
58
+ axis_iterator(:child).each(&block)
59
+ end
60
+
61
+ def axis_iterator(axis)
62
+ AxisIterator.new(self, axis)
63
+ end
64
+ end
65
+ end