saxon-rb 0.4.0-java → 0.7.2-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.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +429 -42
  3. data/.ruby-version +1 -1
  4. data/.yardopts +1 -0
  5. data/Gemfile +2 -2
  6. data/README.md +358 -10
  7. data/Rakefile +237 -7
  8. data/docs/templates/plugin.rb +73 -0
  9. 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
  10. data/lib/saxon-rb.rb +0 -0
  11. data/lib/{saxon_jars.rb → saxon-rb_jars.rb} +2 -2
  12. data/lib/saxon.rb +13 -0
  13. data/lib/saxon/axis_iterator.rb +8 -1
  14. data/lib/saxon/configuration.rb +16 -13
  15. data/lib/saxon/document_builder.rb +216 -5
  16. data/lib/saxon/feature_flags.rb +11 -0
  17. data/lib/saxon/feature_flags/errors.rb +8 -0
  18. data/lib/saxon/feature_flags/helpers.rb +15 -0
  19. data/lib/saxon/feature_flags/version.rb +100 -0
  20. data/lib/saxon/item_type.rb +129 -89
  21. data/lib/saxon/item_type/lexical_string_conversion.rb +214 -59
  22. data/lib/saxon/item_type/value_to_ruby.rb +25 -0
  23. data/lib/saxon/loader.rb +6 -1
  24. data/lib/saxon/nokogiri.rb +78 -0
  25. data/lib/saxon/occurrence_indicator.rb +32 -3
  26. data/lib/saxon/processor.rb +50 -5
  27. data/lib/saxon/qname.rb +37 -2
  28. data/lib/saxon/s9api.rb +5 -0
  29. data/lib/saxon/sequence_type.rb +131 -0
  30. data/lib/saxon/serializer.rb +3 -137
  31. data/lib/saxon/serializer/destination.rb +80 -0
  32. data/lib/saxon/serializer/object.rb +93 -0
  33. data/lib/saxon/serializer/output_properties.rb +83 -0
  34. data/lib/saxon/source.rb +207 -71
  35. data/lib/saxon/version.rb +7 -1
  36. data/lib/saxon/version/library.rb +89 -0
  37. data/lib/saxon/xdm.rb +7 -0
  38. data/lib/saxon/xdm/array.rb +16 -0
  39. data/lib/saxon/xdm/atomic_value.rb +10 -2
  40. data/lib/saxon/xdm/empty_sequence.rb +13 -0
  41. data/lib/saxon/xdm/external_object.rb +1 -0
  42. data/lib/saxon/xdm/function_item.rb +1 -0
  43. data/lib/saxon/xdm/item.rb +7 -0
  44. data/lib/saxon/xdm/map.rb +38 -0
  45. data/lib/saxon/xdm/node.rb +50 -1
  46. data/lib/saxon/xdm/sequence_like.rb +15 -0
  47. data/lib/saxon/xdm/value.rb +21 -5
  48. data/lib/saxon/xpath.rb +9 -0
  49. data/lib/saxon/xpath/compiler.rb +37 -2
  50. data/lib/saxon/xpath/executable.rb +53 -28
  51. data/lib/saxon/xpath/static_context.rb +25 -40
  52. data/lib/saxon/xpath/variable_declaration.rb +16 -49
  53. data/lib/saxon/xslt.rb +12 -0
  54. data/lib/saxon/xslt/compiler.rb +75 -6
  55. data/lib/saxon/xslt/evaluation_context.rb +30 -4
  56. data/lib/saxon/xslt/executable.rb +206 -29
  57. data/lib/saxon/xslt/invocation.rb +97 -0
  58. data/saxon-rb.gemspec +3 -3
  59. metadata +22 -10
  60. data/saxon.gemspec +0 -30
@@ -9,24 +9,31 @@ require_relative 'xdm/empty_sequence'
9
9
  require_relative 'xdm/item'
10
10
 
11
11
  module Saxon
12
+ # Classes for representing, creating, and working with the XPath Data Model
13
+ # type system used in XPath 2+, XSLT 2+, and XQuery.
12
14
  module XDM
13
15
  class << self
16
+ # Convenience function for creating a new {AtomicValue}. See {AtomicValue.create}
14
17
  def AtomicValue(*args)
15
18
  XDM::AtomicValue.create(*args)
16
19
  end
17
20
 
21
+ # Convenience function for creating a new {Value}. See {Value.create}
18
22
  def Value(*args)
19
23
  XDM::Value.create(*args)
20
24
  end
21
25
 
26
+ # Returns the XDM {EmptySequence}. See {EmptySequence.create}
22
27
  def EmptySequence()
23
28
  XDM::EmptySequence.create
24
29
  end
25
30
 
31
+ # Convenience function for creating a new {Array}. See {Array.create}
26
32
  def Array(*args)
27
33
  XDM::Array.create(*args)
28
34
  end
29
35
 
36
+ # Convenience function for creating a new {Map}. See {Map.create}
30
37
  def Map(*args)
31
38
  XDM::Map.create(*args)
32
39
  end
@@ -5,6 +5,11 @@ module Saxon
5
5
  module XDM
6
6
  # Represents an XDM Array
7
7
  class Array
8
+ # Create a new {XDM::Array} from a Ruby Array. The contents of the array
9
+ # will be converted to {XDM::Value}s using {XDM.Value()}. An existing
10
+ # {S9API::XdmArray} will simply be wrapped and returned.
11
+ #
12
+ # @return [XDM::Array] the new XDM Array
8
13
  def self.create(array)
9
14
  case array
10
15
  when S9API::XdmArray
@@ -28,14 +33,19 @@ module Saxon
28
33
  @s9_xdm_array = s9_xdm_array
29
34
  end
30
35
 
36
+ # Iterate over the Array, yielding each element.
37
+ # @yieldparam value [XDM::Value] the current value from the Array
31
38
  def each(&block)
32
39
  cached_array.each(&block)
33
40
  end
34
41
 
42
+ # Fetch element at index +i+ in the array.
43
+ # @param i [Integer] the index of the element to retrieve.
35
44
  def [](i)
36
45
  cached_array[i]
37
46
  end
38
47
 
48
+ # @return [Integer] the length of the array
39
49
  def length
40
50
  s9_xdm_array.arrayLength
41
51
  end
@@ -53,16 +63,22 @@ module Saxon
53
63
  cached_array == other.to_a
54
64
  end
55
65
 
66
+ # Return a (frozen) Ruby {::Array} containing all the elements of the {XDM::Array}
56
67
  def to_a
57
68
  cached_array
58
69
  end
59
70
 
60
71
  alias_method :eql?, :==
61
72
 
73
+ # Compute a hash-code for this {Array}.
74
+ #
75
+ # Two {XDM::Array}s with the same content will have the same hash code (and will compare using eql?).
76
+ # @see Object#hash
62
77
  def hash
63
78
  @hash ||= cached_array.hash
64
79
  end
65
80
 
81
+ # @return the underlying Java XdmArray
66
82
  def to_java
67
83
  s9_xdm_array
68
84
  end
@@ -20,6 +20,7 @@ module Saxon
20
20
  # them imlpicitly through the XDM::AtomicValue creation process doesn't really
21
21
  # work. They need to be created explicitly and then handed in to be wrapped.
22
22
  class CannotCreateQNameFromString < StandardError
23
+ # returns an error message
23
24
  def to_s
24
25
  "QName XDM::AtomicValues must be created using an instance of Saxon::QName, not a string like 'prefix:name': Prefix URI binding is undefined at this point"
25
26
  end
@@ -29,19 +30,22 @@ module Saxon
29
30
  # isn't a way to create these outside of parsing an XML document within
30
31
  # Saxon, so attempting to do so raises this error.
31
32
  class NotationCannotBeDirectlyCreated < StandardError
32
- def to_s
33
+ # returns an error message
34
+ def to_s
33
35
  "xs:NOTATION XDM::AtomicValues cannot be directly created outside of XML parsing."
34
36
  end
35
37
  end
36
38
 
39
+ # ItemType representing QNames
37
40
  XS_QNAME = ItemType.get_type('xs:QName')
41
+ # ItemType representing NOTATION
38
42
  XS_NOTATION = ItemType.get_type('xs:NOTATION')
39
43
 
40
44
  class << self
41
45
  # Convert a single Ruby value into an XDM::AtomicValue
42
46
  #
43
47
  # If no explicit {ItemType} is passed, the correct type is guessed based
44
- # on the class of the value. (e.g. <tt>xs:date</tt> for {Date}.)
48
+ # on the class of the value. (e.g. <tt>xs:date</tt> for {::Date}.)
45
49
  #
46
50
  # Values are converted based on Ruby idioms and operations, so an explicit
47
51
  # {ItemType} of <tt>xs:boolean</tt> will use truthyness to evaluate the
@@ -165,6 +169,10 @@ module Saxon
165
169
 
166
170
  alias_method :eql?, :==
167
171
 
172
+ # Compute a hash-code for this {AtomicValue}.
173
+ #
174
+ # Two {AtomicValue}s with the same content will have the same hash code (and will compare using eql?).
175
+ # @see Object#hash
168
176
  def hash
169
177
  @hash ||= s9_xdm_atomic_value.hashCode
170
178
  end
@@ -5,30 +5,43 @@ module Saxon
5
5
  module XDM
6
6
  # Represents the empty sequence in XDM
7
7
  class EmptySequence
8
+ # Returns an instance. Effectively a Singleton because the EmptySequence
9
+ # is immutable, and empty. An instance is completely interchangeable with
10
+ # another. The instance is cached, but multiple instances may exist across
11
+ # threads. We don't prevent that because it's immaterial.
12
+ # @return [EmptySequence] The empty sequence
8
13
  def self.create
9
14
  @instance ||= new
10
15
  end
11
16
 
12
17
  include SequenceLike
13
18
 
19
+ # @return [Enumerator] an enumerator over an empty Array
14
20
  def sequence_enum
15
21
  [].to_enum
16
22
  end
17
23
 
24
+ # @return [Integer] the size of the sequence (always 0)
18
25
  def sequence_size
19
26
  0
20
27
  end
21
28
 
29
+ # All instances of {EmptySequence} are equal to each other.
30
+ #
31
+ # @param other [Object] the object to compare self against
32
+ # @return [Boolean] Whether this object is equal to the other
22
33
  def ==(other)
23
34
  other.class == self.class
24
35
  end
25
36
 
26
37
  alias_method :eql?, :==
27
38
 
39
+ # @return [Integer] the hash code. All instances have the same hash code.
28
40
  def hash
29
41
  [].hash
30
42
  end
31
43
 
44
+ # @return [net.sf.saxon.s9api.XDMEmptySequence] the underlying Java empty sequence
32
45
  def to_java
33
46
  @s9_xdm_empty_sequence ||= Saxon::S9API::XdmEmptySequence.getInstance
34
47
  end
@@ -13,6 +13,7 @@ module Saxon
13
13
  @s9_xdm_external_object = s9_xdm_external_object
14
14
  end
15
15
 
16
+ # The underlying Saxon XdmExternalObject
16
17
  def to_java
17
18
  @s9_xdm_external_object
18
19
  end
@@ -13,6 +13,7 @@ module Saxon
13
13
  @s9_xdm_function_item = s9_xdm_function_item
14
14
  end
15
15
 
16
+ # The underlying Saxon XdmFunctionItem
16
17
  def to_java
17
18
  @s9_xdm_function_item
18
19
  end
@@ -1,5 +1,12 @@
1
1
  module Saxon
2
2
  module XDM
3
+ # Create one of the XdmItem-derived XDM objects from the passed in argument.
4
+ #
5
+ # Existing XDM::* objects are passed through. s9api.Xdm* Java objects are
6
+ # wrapped appropriately and returned. Ruby Arrays and Hashes are converted
7
+ # to {XDM::Array} and {XDM::Map} instances respectively. Ruby values that
8
+ # respond to +#each+ are converted to an {XDM::Array} (e.g. {Set}). Other
9
+ # Ruby values are converted to {XDM::AtomicValue}.
3
10
  def self.Item(item)
4
11
  case item
5
12
  when Value, AtomicValue, Node, Array, Map, ExternalObject
@@ -5,6 +5,12 @@ module Saxon
5
5
  module XDM
6
6
  # Represents an XDM Map
7
7
  class Map
8
+ # Create an {XDM::Map} from a Ruby Hash, by ensuring each key has been
9
+ # converted to an {AtomicValue}, and each value has been converted to an
10
+ # XDM Value of some sort.
11
+ # @return [XDM::Map] the new Map
12
+ # @see XDM.AtomicValue
13
+ # @see XDM.Value
8
14
  def self.create(hash)
9
15
  case hash
10
16
  when Saxon::S9API::XdmMap
@@ -30,39 +36,71 @@ module Saxon
30
36
  @s9_xdm_map = s9_xdm_map
31
37
  end
32
38
 
39
+ # Compare this Map against another. They're equal if they contain the same
40
+ # key, value pairs.
33
41
  def ==(other)
34
42
  return false unless other.is_a?(self.class)
35
43
  to_h == other.to_h
36
44
  end
37
45
 
46
+ # Fetch the value for the key given. +key+ is converted to an
47
+ # {XDM::AtomicValue} if it isn't already one.
48
+ # @param key [Object, XDM::AtomicValue] the key to retrieve
38
49
  def [](key)
39
50
  cached_hash[XDM.AtomicValue(key)]
40
51
  end
41
52
 
53
+ # Fetch the value for the key given, as {Hash#fetch} would. +key+ is
54
+ # converted to an {XDM::AtomicValue} if it isn't already one.
55
+ # @param key [XDM::AtomicValue, Object] the key to retrieve.
56
+ # @see Hash#fetch
42
57
  def fetch(key, *args, &block)
43
58
  cached_hash.fetch(XDM.AtomicValue(key), *args, &block)
44
59
  end
45
60
 
61
+ # Iterate over the Map as {Hash#each} would
62
+ # @yieldparam key [XDM::AtomicValue] the key
63
+ # @yieldparam value [XDM::Value] the value
46
64
  def each(&block)
47
65
  cached_hash.each(&block)
48
66
  end
49
67
 
68
+ # Return a new Map containing only key, value pairs for which the block
69
+ # returns true.
70
+ # @yieldparam key [XDM::AtomicValue] the key
71
+ # @yieldparam value [XDM::Value] the value
72
+ # @see ::Hash#select
50
73
  def select(&block)
51
74
  self.class.create(each.select(&block).to_h)
52
75
  end
53
76
 
77
+ # Return a new Map containing only key, value pairs for which the block
78
+ # DOES NOT return true.
79
+ # @yieldparam key [XDM::AtomicValue] the key
80
+ # @yieldparam value [XDM::Value] the value
81
+ # @see ::Hash#reject
54
82
  def reject(&block)
55
83
  self.class.create(each.reject(&block).to_h)
56
84
  end
57
85
 
86
+ # Create a new Map from the result of merging another Map into this one.
87
+ # In the case of duplicate keys, the value in the provided hash will be
88
+ # used.
89
+ # @yieldparam key [XDM::AtomicValue] the key
90
+ # @yieldparam value [XDM::Value] the value
91
+ # @return [XDM::Map] the new Map
92
+ # @see ::Hash#merge
58
93
  def merge(other)
59
94
  self.class.create(to_h.merge(other.to_h))
60
95
  end
61
96
 
97
+ # @return [S9API::XdmMap] the underlying Saxon XdmMap
62
98
  def to_java
63
99
  @s9_xdm_map
64
100
  end
65
101
 
102
+ # a (frozen) Ruby hash containing the keys and values from the Map.
103
+ # @return [Hash] the Map as a Ruby hash.
66
104
  def to_h
67
105
  cached_hash
68
106
  end
@@ -4,7 +4,8 @@ require_relative 'sequence_like'
4
4
 
5
5
  module Saxon
6
6
  module XDM
7
- # An XPath Data Model Node object, representing an XML document, or an element or one of the other node chunks in the XDM.
7
+ # An XPath Data Model Node object, representing an XML document, or an
8
+ # element or one of the other node chunks in the XDM.
8
9
  class Node
9
10
  include XDM::SequenceLike
10
11
  include XDM::ItemSequenceLike
@@ -23,12 +24,20 @@ module Saxon
23
24
  @s9_xdm_node
24
25
  end
25
26
 
27
+ # The name of the node, as a {Saxon::QName}, or +nil+ if the node is not
28
+ # of a kind that has a name
29
+ # @return [Saxon::QName, null] the name, if there is one
26
30
  def node_name
27
31
  return @node_name if instance_variable_defined?(:@node_name)
28
32
  node_name = s9_xdm_node.getNodeName
29
33
  @node_name = node_name.nil? ? nil : Saxon::QName.new(node_name)
30
34
  end
31
35
 
36
+ # What kind of node this is. Returns one of +:document+, +:element+,
37
+ # +:text+, +:attribute+, +:namespace+, +:comment+,
38
+ # +:processing_instruction+, or +:comment+
39
+ #
40
+ # @return [Symbol] the kind of node this is
32
41
  def node_kind
33
42
  @node_kind ||= case s9_xdm_node.nodeKind
34
43
  when Saxon::S9API::XdmNodeKind::ELEMENT
@@ -48,6 +57,7 @@ module Saxon
48
57
  end
49
58
  end
50
59
 
60
+ # Does this Node represent the same underlying node as the other?
51
61
  def ==(other)
52
62
  return false unless other.is_a?(XDM::Node)
53
63
  s9_xdm_node.equals(other.to_java)
@@ -55,17 +65,56 @@ module Saxon
55
65
 
56
66
  alias_method :eql?, :==
57
67
 
68
+ # Compute a hash-code for this {Node}.
69
+ #
70
+ # Two {Node}s with the same content will have the same hash code (and will compare using eql?).
71
+ # @see Object#hash
58
72
  def hash
59
73
  @hash ||= s9_xdm_node.hashCode
60
74
  end
61
75
 
76
+ # Execute the given block for every child node of this
77
+ # @yieldparam node [Saxon::XDM::Node] the child node
62
78
  def each(&block)
63
79
  axis_iterator(:child).each(&block)
64
80
  end
65
81
 
82
+ # Create an {AxisIterator} over this Node for the given XPath axis
83
+ # @param axis [Symbol] the axis to iterate along
84
+ # @see AxisIterator
66
85
  def axis_iterator(axis)
67
86
  AxisIterator.new(self, axis)
68
87
  end
88
+
89
+ # Use Saxon's naive XDM Node serialisation to serialize the node and its
90
+ # descendants. Saxon uses a new Serializer with default options to
91
+ # serialize the node. In particular, if the Node was produced by an XSLT
92
+ # that used +<xsl:character-map>+ through +<xsl:output>+ to modify the
93
+ # contents, then they *WILL* *NOT* have been applied.
94
+ #
95
+ # +<xsl:output>+ has its effect at serialization time, not at XDM tree
96
+ # creation time, so it won't be applied until you serialize the document.
97
+ #
98
+ # Even then, unless you use a {Serializer} configured with the XSLT's
99
+ # +<xsl:output>+. We make a properly configured serializer available in
100
+ # the result of any XSLT transform (a {Saxon::XSLT::Invocation}), e.g.:
101
+ #
102
+ # result = xslt.apply_templates(input)
103
+ # result.to_s
104
+ # # or
105
+ # result.serialize('/path/to/output.xml')
106
+ #
107
+ # You can also get that {Serializer} directly from {XSLT::Executable},
108
+ # should you want to use the serialization options from a particular XSLT
109
+ # to serialize arbitrary XDM values:
110
+ #
111
+ # serializer = xslt.serializer
112
+ # serializer.serialize(an_xdm_value)
113
+ #
114
+ # @see http://www.saxonica.com/documentation9.9/index.html#!javadoc/net.sf.saxon.s9api/XdmNode@toString
115
+ def to_s
116
+ s9_xdm_node.toString
117
+ end
69
118
  end
70
119
  end
71
120
  end
@@ -1,14 +1,25 @@
1
1
  module Saxon
2
2
  module XDM
3
+ # Mixin for objects that are XDM Sequence-like in behaviour
3
4
  module SequenceLike
5
+ # Implementors should return an {Enumerator} over the Sequence. For
6
+ # {XDM::Value}s, this will just be the items in the sequence. For
7
+ # XDM::AtomicValue or XDM::Node, this will be a single-item Enumerator so
8
+ # that Items can be correctly treated as single-item Values.
4
9
  def sequence_enum
5
10
  raise NotImplementedError
6
11
  end
7
12
 
13
+ # Implementors should return the size of the Sequence. For
14
+ # {XDM::AtomicValue} this will always be 1.
15
+ # @return [Integer] the sequence size
8
16
  def sequence_size
9
17
  raise NotImplementedError
10
18
  end
11
19
 
20
+ # Return a new XDM::Value from this Sequence with the passed in value
21
+ # appended to the end.
22
+ # @return [XDM::Value] the new Value
12
23
  def append(other)
13
24
  XDM::Value.create([self, other])
14
25
  end
@@ -17,11 +28,15 @@ module Saxon
17
28
  alias_method :+, :append
18
29
  end
19
30
 
31
+ # Mixin for objects that are Sequence-like but only contain a single item,
32
+ # like {XDM::AtomicValue} or {XDM::Node}
20
33
  module ItemSequenceLike
34
+ # return a single-item Enumerator containing +self+
21
35
  def sequence_enum
22
36
  [self].to_enum
23
37
  end
24
38
 
39
+ # Returns the sequence size, which will always be 1.
25
40
  def sequence_size
26
41
  1
27
42
  end
@@ -19,8 +19,8 @@ module Saxon
19
19
  when 0
20
20
  XDM.EmptySequence()
21
21
  when 1
22
- if existing_value = maybe_xdm_value(items.first)
23
- return existing_value
22
+ if value = maybe_xdm_value(items.first)
23
+ return value
24
24
  end
25
25
  XDM.Item(items.first)
26
26
  else
@@ -30,12 +30,25 @@ module Saxon
30
30
 
31
31
  private
32
32
 
33
- def maybe_xdm_value(item)
34
- return item if item.is_a?(self)
35
- return new(item) if item.instance_of?(Saxon::S9API::XdmValue)
33
+ def maybe_xdm_value(value)
34
+ return value if value.is_a?(self)
35
+ return value if value === XDM.EmptySequence()
36
+ return XDM.EmptySequence() if value.instance_of?(Saxon::S9API::XdmEmptySequence)
37
+ return check_for_empty_or_single_item_value(value) if value.instance_of?(Saxon::S9API::XdmValue)
36
38
  false
37
39
  end
38
40
 
41
+ def check_for_empty_or_single_item_value(s9_value)
42
+ case s9_value.size
43
+ when 0
44
+ XDM.EmptySequence()
45
+ when 1
46
+ XDM.Item(s9_value.item_at(0))
47
+ else
48
+ new(s9_value)
49
+ end
50
+ end
51
+
39
52
  def wrap_items(items)
40
53
  result = []
41
54
  items.map { |item|
@@ -122,10 +135,12 @@ module Saxon
122
135
 
123
136
  alias_method :enum_for, :to_enum
124
137
 
138
+ # Returns an enumerator over the Sequence
125
139
  def sequence_enum
126
140
  to_enum
127
141
  end
128
142
 
143
+ # @return [Integer] the size of the sequence
129
144
  def sequence_size
130
145
  s9_xdm_value.size
131
146
  end
@@ -137,6 +152,7 @@ module Saxon
137
152
  @s9_xdm_item = s9_xdm_item
138
153
  end
139
154
 
155
+ # Return the underlying s9api XdmItem
140
156
  def to_java
141
157
  @s9_xdm_item
142
158
  end