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
@@ -0,0 +1,93 @@
|
|
1
|
+
require_relative '../s9api'
|
2
|
+
require_relative './output_properties'
|
3
|
+
require 'stringio'
|
4
|
+
|
5
|
+
module Saxon
|
6
|
+
module Serializer
|
7
|
+
# A Saxon Serializer to be used directly with XDM Values rather than being
|
8
|
+
# called as a Destination for a transformation.
|
9
|
+
class Object
|
10
|
+
# Create a serializer from the passed in +Processor+. When called with a
|
11
|
+
# block, the block will be executed via instance-exec so that output
|
12
|
+
# properties can be set, e.g.
|
13
|
+
#
|
14
|
+
# Serializer::Object.create(processor) {
|
15
|
+
# output_property[:indent] = 'yes'
|
16
|
+
# }
|
17
|
+
#
|
18
|
+
# @param processor [Saxon::Processor] the processor to create this
|
19
|
+
# +Serializer::Object+ from
|
20
|
+
# @yield the passed block bound via instance-exec to the new serializer
|
21
|
+
def self.create(processor, &block)
|
22
|
+
new(processor.to_java.newSerializer, &block)
|
23
|
+
end
|
24
|
+
|
25
|
+
include OutputProperties
|
26
|
+
|
27
|
+
attr_reader :s9_serializer
|
28
|
+
private :s9_serializer
|
29
|
+
|
30
|
+
# @api private
|
31
|
+
def initialize(s9_serializer, &block)
|
32
|
+
@s9_serializer = s9_serializer
|
33
|
+
if block_given?
|
34
|
+
instance_exec(&block)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# @overload serialize(xdm_value, io)
|
39
|
+
# Serialize an XdmValue to an IO
|
40
|
+
# @param [Saxon::XdmValue] xdm_value The XdmValue to serialize
|
41
|
+
# @param [File, IO] io The IO to serialize to
|
42
|
+
# @return [nil]
|
43
|
+
# @overload serialize(xdm_value, path)
|
44
|
+
# Serialize an XdmValue to file <tt>path</tt>
|
45
|
+
# @param [Saxon::XdmValue] xdm_value The XdmValue to serialize
|
46
|
+
# @param [String, Pathname] path The path of the file to serialize to
|
47
|
+
# @return [nil]
|
48
|
+
# @overload serialize(xdm_value)
|
49
|
+
# Serialize an XdmValue to a String
|
50
|
+
# @param [Saxon::XdmValue] xdm_value The XdmValue to serialize
|
51
|
+
# @return [String] The serialized XdmValue
|
52
|
+
def serialize(xdm_value, io_or_path = nil)
|
53
|
+
case io_or_path
|
54
|
+
when nil
|
55
|
+
serialize_to_string(xdm_value)
|
56
|
+
when String, Pathname
|
57
|
+
serialize_to_file(xdm_value, io_or_path)
|
58
|
+
else
|
59
|
+
serialize_to_io(xdm_value, io_or_path)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# @return [Saxon::S9API::Serializer] The underlying Saxon Serializer object
|
64
|
+
def to_java
|
65
|
+
s9_serializer
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def serialize_to_io(xdm_value, io)
|
71
|
+
s9_serializer.setOutputStream(io.to_outputstream)
|
72
|
+
s9_serializer.serializeXdmValue(xdm_value.to_java)
|
73
|
+
nil
|
74
|
+
end
|
75
|
+
|
76
|
+
def serialize_to_string(xdm_value)
|
77
|
+
str_encoding = output_property.fetch(:encoding, Encoding.default_internal || Encoding.default_external)
|
78
|
+
StringIO.open { |io|
|
79
|
+
io.binmode
|
80
|
+
serialize_to_io(xdm_value, io)
|
81
|
+
io.string.force_encoding(str_encoding)
|
82
|
+
}
|
83
|
+
end
|
84
|
+
|
85
|
+
def serialize_to_file(xdm_value, path)
|
86
|
+
file = Java::JavaIO::File.new(path.to_s)
|
87
|
+
s9_serializer.setOutputFile(file)
|
88
|
+
s9_serializer.serializeXdmValue(xdm_value.to_java)
|
89
|
+
nil
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module Saxon
|
2
|
+
module Serializer
|
3
|
+
# Manage access to the serialization properties of this serializer, with
|
4
|
+
# hash-like access.
|
5
|
+
#
|
6
|
+
# Properties can be set explicitly through this API, or via XSLT or XQuery
|
7
|
+
# serialization options like +<xsl:output>+.
|
8
|
+
#
|
9
|
+
# Properties set explicitly here will override properties set through the
|
10
|
+
# document by +<xsl:output>+.
|
11
|
+
module OutputProperties
|
12
|
+
# @return [Saxon::Serializer::OutputProperties] hash-like access to the Output Properties
|
13
|
+
def output_property
|
14
|
+
@output_property ||= OutputProperties::Accessor.new(s9_serializer)
|
15
|
+
end
|
16
|
+
|
17
|
+
# @api private
|
18
|
+
#
|
19
|
+
# The private wrapper class that manages getting and setting output
|
20
|
+
# properties on a Serializer in an idiomatic Ruby-like way.
|
21
|
+
class Accessor
|
22
|
+
# @api private
|
23
|
+
# Provides mapping between symbols and the underlying Saxon property
|
24
|
+
# instances
|
25
|
+
def self.output_properties
|
26
|
+
@output_properties ||= Hash[
|
27
|
+
Saxon::S9API::Serializer::Property.values.map { |property|
|
28
|
+
qname = property.getQName
|
29
|
+
key = [
|
30
|
+
qname.getPrefix,
|
31
|
+
qname.getLocalName.tr('-', '_')
|
32
|
+
].reject { |str| str == '' }.join('_').to_sym
|
33
|
+
[key, property]
|
34
|
+
}
|
35
|
+
]
|
36
|
+
end
|
37
|
+
|
38
|
+
attr_reader :s9_serializer
|
39
|
+
|
40
|
+
# @api private
|
41
|
+
def initialize(s9_serializer)
|
42
|
+
@s9_serializer = s9_serializer
|
43
|
+
end
|
44
|
+
|
45
|
+
# @param [Symbol, Saxon::S9API::Serializer::Property] property The property to fetch
|
46
|
+
def [](property)
|
47
|
+
s9_serializer.getOutputProperty(resolved_property(property))
|
48
|
+
end
|
49
|
+
|
50
|
+
# @param [Symbol, Saxon::S9API::Serializer::Property] property The property to set
|
51
|
+
# @param [String] value The string value of the property
|
52
|
+
def []=(property, value)
|
53
|
+
s9_serializer.setOutputProperty(resolved_property(property), value)
|
54
|
+
end
|
55
|
+
|
56
|
+
# @overload fetch(property)
|
57
|
+
# @param [Symbol, Saxon::S9API::Serializer::Property] property The property to fetch
|
58
|
+
# @overload fetch(property, default)
|
59
|
+
# @param property [Symbol, Saxon::S9API::Serializer::Property] The property to fetch
|
60
|
+
# @param default [Object] The value to return if the property is unset
|
61
|
+
def fetch(property, default = nil)
|
62
|
+
explicit_value = self[property]
|
63
|
+
if explicit_value.nil? && !default.nil?
|
64
|
+
default
|
65
|
+
else
|
66
|
+
explicit_value
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def resolved_property(property_key)
|
73
|
+
case property_key
|
74
|
+
when Symbol
|
75
|
+
self.class.output_properties.fetch(property_key)
|
76
|
+
else
|
77
|
+
property_key
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/lib/saxon/version.rb
CHANGED
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'saxon/s9api'
|
2
|
+
|
3
|
+
module Saxon
|
4
|
+
module Version
|
5
|
+
# The version of the underlying Saxon library, which we need to discover at
|
6
|
+
# runtime based on what version is on the Classpath
|
7
|
+
class Library
|
8
|
+
# The loaded version of the Saxon Java library
|
9
|
+
#
|
10
|
+
# @return [Saxon::Version::Library] the version of the loaded library
|
11
|
+
def self.loaded_version
|
12
|
+
Saxon::Loader.load!
|
13
|
+
|
14
|
+
sv = Java::net.sf.saxon.Version
|
15
|
+
new(sv.getProductVersion, sv.getStructuredVersionNumber, sv.softwareEdition)
|
16
|
+
end
|
17
|
+
|
18
|
+
include Comparable
|
19
|
+
|
20
|
+
# @return [String] the version string (e.g. '9.9.1.6', '10.0')
|
21
|
+
attr_reader :version
|
22
|
+
# @return [String] the version components (e.g. <tt>[9, 9, 1, 6]</tt>, <tt>[10, 0]</tt>)
|
23
|
+
attr_reader :components
|
24
|
+
# @return [Symbol] the edition (+:he+, +:pe+, or +:ee+)
|
25
|
+
attr_reader :edition
|
26
|
+
|
27
|
+
# @param version [String] the version string
|
28
|
+
# @param components [Array<Integer>] the version components separated
|
29
|
+
# @param edition [String, Symbol] the name of the Saxon edition (e.g. +:he+, +'HE'+)
|
30
|
+
def initialize(version, components, edition)
|
31
|
+
@version = version.dup.freeze
|
32
|
+
@components = components.dup.freeze
|
33
|
+
@edition = edition.downcase.to_sym
|
34
|
+
end
|
35
|
+
|
36
|
+
# Comparison against another instance
|
37
|
+
#
|
38
|
+
# @param other [Saxon::Version::Library] the other version to compare against
|
39
|
+
# @return [Integer] -1 for less, 1 for greater, 0 for equal
|
40
|
+
def <=>(other)
|
41
|
+
return false unless other.is_a?(self.class)
|
42
|
+
|
43
|
+
n_components = [self.components.length, other.components.length].max
|
44
|
+
(0..(n_components - 1)).reduce(0, &comparator(other))
|
45
|
+
end
|
46
|
+
|
47
|
+
# Pessimistic comparison à la rubygems +~>+: do I satisfy the other
|
48
|
+
# version if considered as a pessimistic version constraint
|
49
|
+
#
|
50
|
+
# @param pessimistic_version [Saxon::Version::Library] the version to
|
51
|
+
# compare pessimistically
|
52
|
+
# @return [Boolean] do I satisfy the constraint?
|
53
|
+
def pessimistic_compare(pessimistic_version)
|
54
|
+
pessimistic_components = pessimistic_version.components
|
55
|
+
pessimistic_components = pessimistic_components + [0] if pessimistic_components.length == 1
|
56
|
+
locked = pessimistic_components[0..-2]
|
57
|
+
locked = locked.zip(components[0..locked.length])
|
58
|
+
variable = [pessimistic_components[-1], components[locked.length]]
|
59
|
+
|
60
|
+
locked_ok = locked.all? { |check, mine|
|
61
|
+
check == mine
|
62
|
+
}
|
63
|
+
|
64
|
+
return false unless locked_ok
|
65
|
+
|
66
|
+
check, mine = variable
|
67
|
+
mine >= check
|
68
|
+
end
|
69
|
+
|
70
|
+
# @return [String] the version string
|
71
|
+
def to_s
|
72
|
+
version
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def comparator(other)
|
78
|
+
->(cmp, i) {
|
79
|
+
return cmp unless cmp == 0
|
80
|
+
|
81
|
+
mine = self.components[i].nil? ? 0 : self.components[i]
|
82
|
+
theirs = other.components[i].nil? ? 0 : other.components[i]
|
83
|
+
|
84
|
+
mine <=> theirs
|
85
|
+
}
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
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,17 +30,23 @@ 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
|
-
|
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
|
|
37
|
-
# ItemType representing QNames
|
38
|
-
XS_QNAME = ItemType.get_type('xs:QName')
|
39
|
-
# ItemType representing NOTATION
|
40
|
-
XS_NOTATION = ItemType.get_type('xs:NOTATION')
|
41
|
-
|
42
39
|
class << self
|
40
|
+
# ItemType representing QNames
|
41
|
+
def xs_qname
|
42
|
+
@xs_qname ||= ItemType.get_type('xs:QName')
|
43
|
+
end
|
44
|
+
|
45
|
+
# ItemType representing NOTATION
|
46
|
+
def xs_notation
|
47
|
+
@xs_notation ||= ItemType.get_type('xs:NOTATION')
|
48
|
+
end
|
49
|
+
|
43
50
|
# Convert a single Ruby value into an XDM::AtomicValue
|
44
51
|
#
|
45
52
|
# If no explicit {ItemType} is passed, the correct type is guessed based
|
@@ -69,8 +76,8 @@ module Saxon
|
|
69
76
|
|
70
77
|
item_type = ItemType.get_type(item_type)
|
71
78
|
|
72
|
-
return new(Saxon::S9API::XdmAtomicValue.new(value.to_java)) if item_type ==
|
73
|
-
raise NotationCannotBeDirectlyCreated if item_type ==
|
79
|
+
return new(Saxon::S9API::XdmAtomicValue.new(value.to_java)) if item_type == xs_qname && value_is_qname?(value)
|
80
|
+
raise NotationCannotBeDirectlyCreated if item_type == xs_notation
|
74
81
|
|
75
82
|
value_lexical_string = item_type.lexical_string(value)
|
76
83
|
new(new_s9_xdm_atomic_value(value_lexical_string, item_type))
|
@@ -89,7 +96,7 @@ module Saxon
|
|
89
96
|
# @return [Saxon::XDM::AtomicValue]
|
90
97
|
def from_lexical_string(value, item_type)
|
91
98
|
item_type = ItemType.get_type(item_type)
|
92
|
-
raise CannotCreateQNameFromString if item_type ==
|
99
|
+
raise CannotCreateQNameFromString if item_type == xs_qname
|
93
100
|
new(new_s9_xdm_atomic_value(value.to_s, item_type))
|
94
101
|
end
|
95
102
|
|
data/lib/saxon/xdm/node.rb
CHANGED
@@ -33,9 +33,10 @@ module Saxon
|
|
33
33
|
@node_name = node_name.nil? ? nil : Saxon::QName.new(node_name)
|
34
34
|
end
|
35
35
|
|
36
|
-
# What kind of node this is. Returns one of +:
|
37
|
-
# +:attribute+, +:namespace+, +:comment+,
|
38
|
-
# +:comment+
|
36
|
+
# What kind of node this is. Returns one of +:document+, +:element+,
|
37
|
+
# +:text+, +:attribute+, +:namespace+, +:comment+,
|
38
|
+
# +:processing_instruction+, or +:comment+
|
39
|
+
#
|
39
40
|
# @return [Symbol] the kind of node this is
|
40
41
|
def node_kind
|
41
42
|
@node_kind ||= case s9_xdm_node.nodeKind
|
@@ -84,6 +85,36 @@ module Saxon
|
|
84
85
|
def axis_iterator(axis)
|
85
86
|
AxisIterator.new(self, axis)
|
86
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
|
87
118
|
end
|
88
119
|
end
|
89
120
|
end
|
data/lib/saxon/xpath/compiler.rb
CHANGED
@@ -40,7 +40,7 @@ module Saxon
|
|
40
40
|
# static context.
|
41
41
|
#
|
42
42
|
# @param processor [Saxon::Processor] the {Saxon::Processor} to use
|
43
|
-
# @yield An XPath
|
43
|
+
# @yield An XPath::StaticContext::DSL block
|
44
44
|
# @return [Saxon::XPath::Compiler] the new compiler instance
|
45
45
|
def self.create(processor, &block)
|
46
46
|
static_context = XPath::StaticContext.define(block)
|
@@ -79,7 +79,7 @@ module Saxon
|
|
79
79
|
# Compiler's static context. As with {.create}, passing a block gives
|
80
80
|
# access to a DSL for setting up the compiler's static context.
|
81
81
|
#
|
82
|
-
# @yield An
|
82
|
+
# @yield An XPath::StaticContext::DSL block
|
83
83
|
# @return [Saxon::XPath::Compiler] the new compiler instance
|
84
84
|
def create(&block)
|
85
85
|
new_static_context = static_context.define(block)
|
@@ -117,7 +117,12 @@ module Saxon
|
|
117
117
|
DSL.define(block)
|
118
118
|
end
|
119
119
|
|
120
|
-
|
120
|
+
# @return [String] The default collation URI as a String
|
121
|
+
attr_reader :default_collation
|
122
|
+
# @return [Hash<Saxon::QName => Saxon::XPath::VariableDeclaration] the declared variables
|
123
|
+
attr_reader :declared_variables
|
124
|
+
# @return [Hash<String => String>] the declared namespaces, as a prefix => uri hash
|
125
|
+
attr_reader :declared_namespaces
|
121
126
|
|
122
127
|
# @return [Saxon::QName]
|
123
128
|
# @overload resolve_variable_qname(qname)
|
@@ -143,7 +143,17 @@ module Saxon
|
|
143
143
|
DSL.define(block)
|
144
144
|
end
|
145
145
|
|
146
|
-
|
146
|
+
|
147
|
+
# @return [String] The default collation URI as a String
|
148
|
+
attr_reader :default_collation
|
149
|
+
# @return [Hash<Saxon::QName => Saxon::XDM::Value>] All the static parameters
|
150
|
+
attr_reader :static_parameters
|
151
|
+
# @return [Hash<Saxon::QName => Saxon::XDM::Value>] All the global parameters
|
152
|
+
attr_reader :global_parameters
|
153
|
+
# @return [Hash<Saxon::QName => Saxon::XDM::Value>] All the initial template parameters
|
154
|
+
attr_reader :initial_template_parameters
|
155
|
+
# @return [Hash<Saxon::QName => Saxon::XDM::Value>] All the initial template parameters with tunnelling = "yes"
|
156
|
+
attr_reader :initial_template_tunnel_parameters
|
147
157
|
|
148
158
|
# @api private
|
149
159
|
# When passed a Proc, create a new EvaluationContext based on this one, with the same DSL available as in {.define}.
|
@@ -1,8 +1,10 @@
|
|
1
1
|
require 'forwardable'
|
2
2
|
require_relative 'evaluation_context'
|
3
|
+
require_relative 'invocation'
|
3
4
|
require_relative '../serializer'
|
4
5
|
require_relative '../xdm'
|
5
6
|
require_relative '../qname'
|
7
|
+
require_relative '../feature_flags'
|
6
8
|
|
7
9
|
module Saxon
|
8
10
|
module XSLT
|
@@ -52,6 +54,7 @@ module Saxon
|
|
52
54
|
# prefix, you must use an explicit {Saxon::QName} to refer to it.
|
53
55
|
class Executable
|
54
56
|
extend Forwardable
|
57
|
+
extend Saxon::FeatureFlags::Helpers
|
55
58
|
|
56
59
|
attr_reader :evaluation_context
|
57
60
|
private :evaluation_context
|
@@ -96,7 +99,7 @@ module Saxon
|
|
96
99
|
# to pass to the first template matched. Setting already-defined
|
97
100
|
# parameters will replace their value for this invocation of the XSLT
|
98
101
|
# only, it won't affect the {XSLT::Compiler}'s context.
|
99
|
-
# @return [Saxon::XSLT::
|
102
|
+
# @return [Saxon::XSLT::Invocation] the transformation result
|
100
103
|
def apply_templates(source, opts = {})
|
101
104
|
transformation(opts).apply_templates(source)
|
102
105
|
end
|
@@ -130,7 +133,7 @@ module Saxon
|
|
130
133
|
# to pass to the first template matched. Setting already-defined
|
131
134
|
# parameters will replace their value for this invocation of the XSLT
|
132
135
|
# only, it won't affect the {XSLT::Compiler}'s context.
|
133
|
-
# @return [Saxon::XSLT::
|
136
|
+
# @return [Saxon::XSLT::Invocation] the transformation result
|
134
137
|
def call_template(template_name = nil, opts = {})
|
135
138
|
transformation(opts).call_template(template_name)
|
136
139
|
end
|
@@ -155,14 +158,23 @@ module Saxon
|
|
155
158
|
# Additional global parameters to set. Setting already-defined
|
156
159
|
# parameters will replace their value for this invocation of the XSLT
|
157
160
|
# only, it won't affect the {XSLT::Compiler}'s context.
|
158
|
-
# @return [Saxon::XSLT::
|
161
|
+
# @return [Saxon::XSLT::Invocation] the transformation result
|
159
162
|
def call_function(function_name, opts = {})
|
160
163
|
args = opts.fetch(:args, [])
|
161
164
|
transformation(opts.reject { |k, v| k == :args }).call_function(function_name, args)
|
162
165
|
end
|
163
166
|
|
167
|
+
# Create a {Serializer::Object} configured using the options that were set
|
168
|
+
# by +<xsl:output>+.
|
169
|
+
#
|
170
|
+
# @return [Saxon::Serializer::Object] the Serializer
|
171
|
+
def serializer
|
172
|
+
Saxon::Serializer::Object.new(@s9_xslt_executable.load30.newSerializer)
|
173
|
+
end
|
174
|
+
requires_saxon_version :serializer, '>= 9.9'
|
175
|
+
|
164
176
|
# @return [net.sf.saxon.s9api.XsltExecutable] the underlying Saxon
|
165
|
-
#
|
177
|
+
# +XsltExecutable+
|
166
178
|
def to_java
|
167
179
|
@s9_xslt_executable
|
168
180
|
end
|
@@ -202,6 +214,7 @@ module Saxon
|
|
202
214
|
# Represents a loaded XSLT transformation ready to be applied against a
|
203
215
|
# context node.
|
204
216
|
class Transformation
|
217
|
+
# A list of valid option names for the transform
|
205
218
|
VALID_OPTS = [:raw, :mode, :global_context_item, :global_parameters, :initial_template_parameters, :initial_template_tunnel_parameters]
|
206
219
|
|
207
220
|
attr_reader :s9_transformer, :opts
|
@@ -213,6 +226,7 @@ module Saxon
|
|
213
226
|
@default_initial_template ||= Saxon::QName.clark('{http://www.w3.org/1999/XSL/Transform}initial-template')
|
214
227
|
end
|
215
228
|
|
229
|
+
# @api private
|
216
230
|
def initialize(args)
|
217
231
|
@s9_transformer = args.fetch(:s9_transformer)
|
218
232
|
@destination = args.fetch(:destination, nil)
|
@@ -225,57 +239,48 @@ module Saxon
|
|
225
239
|
# Apply templates to Source, using all the context set up when we were
|
226
240
|
# created.
|
227
241
|
def apply_templates(source)
|
228
|
-
|
242
|
+
transformation_invocation(:applyTemplates, source.to_java)
|
229
243
|
end
|
230
244
|
|
231
245
|
# Call the named template, using all the context set up when we were
|
232
246
|
# created.
|
233
247
|
def call_template(template_name)
|
234
|
-
|
248
|
+
transformation_invocation(:callTemplate, resolve_template_name(template_name))
|
235
249
|
end
|
236
250
|
|
237
251
|
# Call the named function, using all the context set up when we were
|
238
252
|
# created.
|
239
253
|
def call_function(function_name, args)
|
240
254
|
function_name = Saxon::QName.resolve(function_name).to_java
|
241
|
-
|
242
|
-
call_function_result(function_name, args)
|
255
|
+
transformation_invocation(:callFunction, function_name, function_args(args))
|
243
256
|
end
|
244
257
|
|
245
258
|
private
|
246
259
|
|
247
|
-
def
|
260
|
+
def transformation_invocation(invocation_method, *invocation_args)
|
248
261
|
set_opts!
|
249
|
-
|
250
|
-
Result.new(result_xdm_value(s9_transformer.send(*transformer_args)), s9_transformer)
|
262
|
+
XSLT::Invocation.new(s9_transformer, invocation_lambda(invocation_method, invocation_args), raw?)
|
251
263
|
end
|
252
264
|
|
253
|
-
def
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
)
|
265
|
+
def invocation_lambda(invocation_method, invocation_args)
|
266
|
+
->(destination) {
|
267
|
+
if destination.nil?
|
268
|
+
s9_transformer.send(invocation_method, *invocation_args)
|
269
|
+
else
|
270
|
+
s9_transformer.send(invocation_method, *invocation_args, destination.to_java)
|
271
|
+
end
|
272
|
+
}
|
262
273
|
end
|
263
274
|
|
264
275
|
def resolve_template_name(template_name)
|
265
|
-
return self.class.default_initial_template if template_name.nil?
|
266
|
-
Saxon::QName.resolve(template_name)
|
276
|
+
return self.class.default_initial_template.to_java if template_name.nil?
|
277
|
+
Saxon::QName.resolve(template_name).to_java
|
267
278
|
end
|
268
279
|
|
269
280
|
def function_args(args = [])
|
270
281
|
args.map { |val| Saxon::XDM.Value(val).to_java }.to_java(S9API::XdmValue)
|
271
282
|
end
|
272
283
|
|
273
|
-
def destination
|
274
|
-
@destination ||= begin
|
275
|
-
Saxon::S9API::XdmDestination.new unless raw?
|
276
|
-
end
|
277
|
-
end
|
278
|
-
|
279
284
|
def set_opts!
|
280
285
|
opts.each do |opt, value|
|
281
286
|
raise BadOptionError, opt unless VALID_OPTS.include?(opt)
|
@@ -304,29 +309,11 @@ module Saxon
|
|
304
309
|
end
|
305
310
|
|
306
311
|
def initial_template_parameters(parameters)
|
307
|
-
s9_transformer.setInitialTemplateParameters(XSLT::ParameterHelper.to_java(parameters)
|
312
|
+
s9_transformer.setInitialTemplateParameters(XSLT::ParameterHelper.to_java(parameters), false)
|
308
313
|
end
|
309
314
|
|
310
315
|
def initial_template_tunnel_parameters(parameters)
|
311
|
-
s9_transformer.setInitialTemplateParameters(XSLT::ParameterHelper.to_java(parameters)
|
312
|
-
end
|
313
|
-
end
|
314
|
-
|
315
|
-
# Represents the result of a transformation, providing a simple default
|
316
|
-
# serializer as well
|
317
|
-
class Result
|
318
|
-
attr_reader :xdm_value
|
319
|
-
|
320
|
-
# @api private
|
321
|
-
def initialize(xdm_value, s9_transformer)
|
322
|
-
@xdm_value, @s9_transformer = xdm_value, s9_transformer
|
323
|
-
end
|
324
|
-
|
325
|
-
# Serialize the result to a string using the options specified in
|
326
|
-
# +<xsl:output/>+ in the XSLT
|
327
|
-
def to_s
|
328
|
-
serializer = Serializer.new(@s9_transformer.newSerializer)
|
329
|
-
serializer.serialize(xdm_value.to_java)
|
316
|
+
s9_transformer.setInitialTemplateParameters(XSLT::ParameterHelper.to_java(parameters), true)
|
330
317
|
end
|
331
318
|
end
|
332
319
|
|