saxon-rb 0.4.0-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.circleci/config.yml +62 -0
- data/.gitignore +13 -0
- data/.rspec +3 -0
- data/.ruby-version +1 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +43 -0
- data/Rakefile +20 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/net/sf/saxon/Saxon-HE/9.9.1-5/Saxon-HE-9.9.1-5.jar +0 -0
- data/lib/saxon.rb +6 -0
- data/lib/saxon/axis_iterator.rb +31 -0
- data/lib/saxon/configuration.rb +116 -0
- data/lib/saxon/document_builder.rb +28 -0
- data/lib/saxon/item_type.rb +290 -0
- data/lib/saxon/item_type/lexical_string_conversion.rb +383 -0
- data/lib/saxon/item_type/value_to_ruby.rb +78 -0
- data/lib/saxon/jaxp.rb +8 -0
- data/lib/saxon/loader.rb +93 -0
- data/lib/saxon/occurrence_indicator.rb +33 -0
- data/lib/saxon/parse_options.rb +127 -0
- data/lib/saxon/processor.rb +102 -0
- data/lib/saxon/qname.rb +153 -0
- data/lib/saxon/s9api.rb +34 -0
- data/lib/saxon/serializer.rb +143 -0
- data/lib/saxon/source.rb +187 -0
- data/lib/saxon/version.rb +3 -0
- data/lib/saxon/xdm.rb +35 -0
- data/lib/saxon/xdm/array.rb +77 -0
- data/lib/saxon/xdm/atomic_value.rb +173 -0
- data/lib/saxon/xdm/empty_sequence.rb +37 -0
- data/lib/saxon/xdm/external_object.rb +21 -0
- data/lib/saxon/xdm/function_item.rb +21 -0
- data/lib/saxon/xdm/item.rb +32 -0
- data/lib/saxon/xdm/map.rb +77 -0
- data/lib/saxon/xdm/node.rb +71 -0
- data/lib/saxon/xdm/sequence_like.rb +30 -0
- data/lib/saxon/xdm/value.rb +145 -0
- data/lib/saxon/xpath.rb +8 -0
- data/lib/saxon/xpath/compiler.rb +69 -0
- data/lib/saxon/xpath/executable.rb +58 -0
- data/lib/saxon/xpath/static_context.rb +161 -0
- data/lib/saxon/xpath/variable_declaration.rb +68 -0
- data/lib/saxon/xslt.rb +8 -0
- data/lib/saxon/xslt/compiler.rb +70 -0
- data/lib/saxon/xslt/evaluation_context.rb +165 -0
- data/lib/saxon/xslt/executable.rb +156 -0
- data/lib/saxon_jars.rb +10 -0
- data/saxon-rb.gemspec +39 -0
- data/saxon.gemspec +30 -0
- metadata +240 -0
@@ -0,0 +1,71 @@
|
|
1
|
+
require_relative '../axis_iterator'
|
2
|
+
require_relative '../s9api'
|
3
|
+
require_relative 'sequence_like'
|
4
|
+
|
5
|
+
module Saxon
|
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.
|
8
|
+
class Node
|
9
|
+
include XDM::SequenceLike
|
10
|
+
include XDM::ItemSequenceLike
|
11
|
+
include Enumerable
|
12
|
+
|
13
|
+
attr_reader :s9_xdm_node
|
14
|
+
private :s9_xdm_node
|
15
|
+
|
16
|
+
# @api private
|
17
|
+
def initialize(s9_xdm_node)
|
18
|
+
@s9_xdm_node = s9_xdm_node
|
19
|
+
end
|
20
|
+
|
21
|
+
# @return [Saxon::S9API::XdmNode] The underlying Saxon Java XDM node object.
|
22
|
+
def to_java
|
23
|
+
@s9_xdm_node
|
24
|
+
end
|
25
|
+
|
26
|
+
def node_name
|
27
|
+
return @node_name if instance_variable_defined?(:@node_name)
|
28
|
+
node_name = s9_xdm_node.getNodeName
|
29
|
+
@node_name = node_name.nil? ? nil : Saxon::QName.new(node_name)
|
30
|
+
end
|
31
|
+
|
32
|
+
def node_kind
|
33
|
+
@node_kind ||= case s9_xdm_node.nodeKind
|
34
|
+
when Saxon::S9API::XdmNodeKind::ELEMENT
|
35
|
+
:element
|
36
|
+
when Saxon::S9API::XdmNodeKind::TEXT
|
37
|
+
:text
|
38
|
+
when Saxon::S9API::XdmNodeKind::ATTRIBUTE
|
39
|
+
:attribute
|
40
|
+
when Saxon::S9API::XdmNodeKind::NAMESPACE
|
41
|
+
:namespace
|
42
|
+
when Saxon::S9API::XdmNodeKind::COMMENT
|
43
|
+
:comment
|
44
|
+
when Saxon::S9API::XdmNodeKind::PROCESSING_INSTRUCTION
|
45
|
+
:processing_instruction
|
46
|
+
when Saxon::S9API::XdmNodeKind::DOCUMENT
|
47
|
+
:document
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def ==(other)
|
52
|
+
return false unless other.is_a?(XDM::Node)
|
53
|
+
s9_xdm_node.equals(other.to_java)
|
54
|
+
end
|
55
|
+
|
56
|
+
alias_method :eql?, :==
|
57
|
+
|
58
|
+
def hash
|
59
|
+
@hash ||= s9_xdm_node.hashCode
|
60
|
+
end
|
61
|
+
|
62
|
+
def each(&block)
|
63
|
+
axis_iterator(:child).each(&block)
|
64
|
+
end
|
65
|
+
|
66
|
+
def axis_iterator(axis)
|
67
|
+
AxisIterator.new(self, axis)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Saxon
|
2
|
+
module XDM
|
3
|
+
module SequenceLike
|
4
|
+
def sequence_enum
|
5
|
+
raise NotImplementedError
|
6
|
+
end
|
7
|
+
|
8
|
+
def sequence_size
|
9
|
+
raise NotImplementedError
|
10
|
+
end
|
11
|
+
|
12
|
+
def append(other)
|
13
|
+
XDM::Value.create([self, other])
|
14
|
+
end
|
15
|
+
|
16
|
+
alias_method :<<, :append
|
17
|
+
alias_method :+, :append
|
18
|
+
end
|
19
|
+
|
20
|
+
module ItemSequenceLike
|
21
|
+
def sequence_enum
|
22
|
+
[self].to_enum
|
23
|
+
end
|
24
|
+
|
25
|
+
def sequence_size
|
26
|
+
1
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require_relative '../s9api'
|
2
|
+
require_relative 'sequence_like'
|
3
|
+
|
4
|
+
module Saxon
|
5
|
+
module XDM
|
6
|
+
# An XPath Data Model Value object, representing a Sequence.
|
7
|
+
class Value
|
8
|
+
include XDM::SequenceLike
|
9
|
+
include Enumerable
|
10
|
+
|
11
|
+
class << self
|
12
|
+
# Create a new XDM::Value sequence containing the items passed in as a Ruby enumerable.
|
13
|
+
#
|
14
|
+
# @param items [Enumerable] A list of members
|
15
|
+
# @return [Saxon::XDM::Value] The XDM value
|
16
|
+
def create(*items)
|
17
|
+
items = items.flatten
|
18
|
+
case items.size
|
19
|
+
when 0
|
20
|
+
XDM.EmptySequence()
|
21
|
+
when 1
|
22
|
+
if existing_value = maybe_xdm_value(items.first)
|
23
|
+
return existing_value
|
24
|
+
end
|
25
|
+
XDM.Item(items.first)
|
26
|
+
else
|
27
|
+
new(Saxon::S9API::XdmValue.new(wrap_items(items)))
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
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)
|
36
|
+
false
|
37
|
+
end
|
38
|
+
|
39
|
+
def wrap_items(items)
|
40
|
+
result = []
|
41
|
+
items.map { |item|
|
42
|
+
wrap_item(item, result)
|
43
|
+
}
|
44
|
+
result
|
45
|
+
end
|
46
|
+
|
47
|
+
def wrap_item(item, result)
|
48
|
+
if item.respond_to?(:sequence_enum)
|
49
|
+
item.sequence_enum.each do |item|
|
50
|
+
result << item.to_java
|
51
|
+
end
|
52
|
+
elsif item.respond_to?(:each)
|
53
|
+
item.each do |item|
|
54
|
+
result << XDM.Item(item).to_java
|
55
|
+
end
|
56
|
+
else
|
57
|
+
result << XDM.Item(item).to_java
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
attr_reader :s9_xdm_value
|
63
|
+
private :s9_xdm_value
|
64
|
+
|
65
|
+
# @api private
|
66
|
+
def initialize(s9_xdm_value)
|
67
|
+
@s9_xdm_value = s9_xdm_value
|
68
|
+
end
|
69
|
+
|
70
|
+
# @return [Fixnum] The size of the sequence
|
71
|
+
def size
|
72
|
+
s9_xdm_value.size
|
73
|
+
end
|
74
|
+
|
75
|
+
# Calls the given block once for each Item in the sequence, passing that
|
76
|
+
# item as a parameter. Returns the value itself.
|
77
|
+
#
|
78
|
+
# If no block is given, an Enumerator is returned.
|
79
|
+
#
|
80
|
+
# @overload
|
81
|
+
# @yield [item] The current XDM Item
|
82
|
+
# @yieldparam item [Saxon::XDM::AtomicValue, Saxon::XDM::Node] the item.
|
83
|
+
def each(&block)
|
84
|
+
to_enum.each(&block)
|
85
|
+
end
|
86
|
+
|
87
|
+
# @return [Saxon::S9API::XdmValue] The underlying Saxon Java XDM valuee object.
|
88
|
+
def to_java
|
89
|
+
@s9_xdm_value
|
90
|
+
end
|
91
|
+
|
92
|
+
# Compare this XDM::Value with another. Currently this requires iterating
|
93
|
+
# across the sequence, and the other sequence and comparing each member
|
94
|
+
# with the corresponding member in the other sequence.
|
95
|
+
#
|
96
|
+
# @param other [Saxon::XDM::Value] The XDM::Value to be compare against
|
97
|
+
# @return [Boolean] whether the two XDM::Values are equal
|
98
|
+
def ==(other)
|
99
|
+
return false unless other.is_a?(XDM::Value)
|
100
|
+
return false unless other.size == size
|
101
|
+
not_okay = to_enum.zip(other.to_enum).find { |mine, theirs|
|
102
|
+
mine != theirs
|
103
|
+
}
|
104
|
+
not_okay.nil? || !not_okay
|
105
|
+
end
|
106
|
+
|
107
|
+
alias_method :eql?, :==
|
108
|
+
|
109
|
+
# The hash code for the XDM::Value
|
110
|
+
# @return [Fixnum] The hash code
|
111
|
+
def hash
|
112
|
+
@hash ||= to_a.hash
|
113
|
+
end
|
114
|
+
|
115
|
+
# Returns a lazy Enumerator over the sequence
|
116
|
+
# @return [Enumerator::Lazy] the enumerator
|
117
|
+
def to_enum
|
118
|
+
s9_xdm_value.enum_for(:each).lazy.map { |s9_xdm_item|
|
119
|
+
XDM.Item(s9_xdm_item)
|
120
|
+
}.each
|
121
|
+
end
|
122
|
+
|
123
|
+
alias_method :enum_for, :to_enum
|
124
|
+
|
125
|
+
def sequence_enum
|
126
|
+
to_enum
|
127
|
+
end
|
128
|
+
|
129
|
+
def sequence_size
|
130
|
+
s9_xdm_value.size
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# Placeholder class for Saxon Items that we haven't gotten to yet
|
135
|
+
class XDM::UnhandledItem
|
136
|
+
def initialize(s9_xdm_item)
|
137
|
+
@s9_xdm_item = s9_xdm_item
|
138
|
+
end
|
139
|
+
|
140
|
+
def to_java
|
141
|
+
@s9_xdm_item
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
data/lib/saxon/xpath.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
require_relative './static_context'
|
3
|
+
require_relative './executable'
|
4
|
+
|
5
|
+
module Saxon
|
6
|
+
module XPath
|
7
|
+
# Compiles XPath expressions so they can be executed
|
8
|
+
class Compiler
|
9
|
+
# Create a new <tt>XPath::Compiler</tt> using the supplied Processor.
|
10
|
+
# Passing a block gives access to a DSL for setting up the compiler's
|
11
|
+
# static context.
|
12
|
+
#
|
13
|
+
# @param processor [Saxon::Processor] the {Saxon::Processor} to use
|
14
|
+
# @yield An XPath compiler DSL block
|
15
|
+
# @return [Saxon::XPath::Compiler] the new compiler instance
|
16
|
+
def self.create(processor, &block)
|
17
|
+
static_context = XPath::StaticContext.define(block)
|
18
|
+
new(processor.to_java, static_context)
|
19
|
+
end
|
20
|
+
|
21
|
+
extend Forwardable
|
22
|
+
|
23
|
+
attr_reader :static_context
|
24
|
+
private :static_context
|
25
|
+
|
26
|
+
# @api private
|
27
|
+
# @param s9_processor [net.sf.saxon.s9api.Processor] the Saxon
|
28
|
+
# <tt>Processor</tt> to wrap
|
29
|
+
# @param static_context [Saxon::XPath::StaticContext] the static context
|
30
|
+
# XPaths compiled using this compiler will have
|
31
|
+
def initialize(s9_processor, static_context)
|
32
|
+
@s9_processor, @static_context = s9_processor, static_context
|
33
|
+
end
|
34
|
+
|
35
|
+
def_delegators :static_context, :default_collation, :declared_namespaces, :declared_variables
|
36
|
+
# @!attribute [r] default_collation
|
37
|
+
# @return [String] the URI of the default declared collation
|
38
|
+
# @!attribute [r] declared_namespaces
|
39
|
+
# @return [Hash<String => String>] declared namespaces as prefix => URI hash
|
40
|
+
# @!attribute [r] declared_variables
|
41
|
+
# @return [Hash<Saxon::QName => Saxon::XPath::VariableDeclaration>] declared variables as QName => Declaration hash
|
42
|
+
|
43
|
+
# @param expression [String] the XPath expression to compile
|
44
|
+
# @return [Saxon::XPath::Executable] the executable query
|
45
|
+
def compile(expression)
|
46
|
+
Saxon::XPath::Executable.new(new_compiler.compile(expression), static_context)
|
47
|
+
end
|
48
|
+
|
49
|
+
def create(&block)
|
50
|
+
new_static_context = static_context.define(block)
|
51
|
+
self.class.new(@s9_processor, new_static_context)
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def new_compiler
|
57
|
+
compiler = @s9_processor.newXPathCompiler
|
58
|
+
declared_namespaces.each do |prefix, uri|
|
59
|
+
compiler.declareNamespace(prefix, uri)
|
60
|
+
end
|
61
|
+
declared_variables.each do |_, decl|
|
62
|
+
compiler.declareVariable(*decl.compiler_args)
|
63
|
+
end
|
64
|
+
compiler.declareDefaultCollation(default_collation) unless default_collation.nil?
|
65
|
+
compiler
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require_relative '../xdm'
|
2
|
+
|
3
|
+
module Saxon
|
4
|
+
module XPath
|
5
|
+
# Represents a compiled XPath query ready to be executed
|
6
|
+
class Executable
|
7
|
+
# @return [XPath::StaticContext] the XPath's static context
|
8
|
+
attr_reader :static_context
|
9
|
+
|
10
|
+
# @api private
|
11
|
+
# @param s9_xpath_executable [net.sf.saxon.s9api.XPathExecutable] the
|
12
|
+
# Saxon compiled XPath object
|
13
|
+
# @param static_context [XPath::StaticContext] the XPath's static
|
14
|
+
# context
|
15
|
+
def initialize(s9_xpath_executable, static_context)
|
16
|
+
@s9_xpath_executable, @static_context = s9_xpath_executable, static_context
|
17
|
+
end
|
18
|
+
|
19
|
+
# Run the compiled query using a passed-in node as the context item.
|
20
|
+
# @param context_item [Saxon::XDM::Node] the context item node
|
21
|
+
# @return [Saxon::XPath::Result] the result of the query as an
|
22
|
+
# enumerable
|
23
|
+
def run(context_item, variables = {})
|
24
|
+
selector = to_java.load
|
25
|
+
selector.setContextItem(context_item.to_java)
|
26
|
+
variables.each do |qname_or_string, value|
|
27
|
+
selector.setVariable(static_context.resolve_variable_qname(qname_or_string).to_java, Saxon::XDM.Value(value).to_java)
|
28
|
+
end
|
29
|
+
Result.new(selector.iterator)
|
30
|
+
end
|
31
|
+
|
32
|
+
# @return [net.sf.saxon.s9api.XPathExecutable] the underlying Saxon
|
33
|
+
# <tt>XPathExecutable</tt>
|
34
|
+
def to_java
|
35
|
+
@s9_xpath_executable
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# The result of executing an XPath query as an enumerable object
|
40
|
+
class Result
|
41
|
+
include Enumerable
|
42
|
+
|
43
|
+
# @api private
|
44
|
+
# @param result_iterator [java.util.Iterator] the result of calling
|
45
|
+
# <tt>#iterator</tt> on a Saxon <tt>XPathSelector</tt>
|
46
|
+
def initialize(result_iterator)
|
47
|
+
@result_iterator = result_iterator
|
48
|
+
end
|
49
|
+
|
50
|
+
# Yields <tt>XDM::Node</tt>s from the query result. If no block is passed,
|
51
|
+
# returns an <tt>Enumerator</tt>
|
52
|
+
# @yieldparam xdm_node [Saxon::XDM::Node] the name that is yielded
|
53
|
+
def each(&block)
|
54
|
+
@result_iterator.lazy.map { |s9_xdm_node| Saxon::XDM::Node.new(s9_xdm_node) }.each(&block)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
require_relative '../qname'
|
2
|
+
require_relative './variable_declaration'
|
3
|
+
module Saxon
|
4
|
+
module XPath
|
5
|
+
# Raised when an attempt to declare a variable is made using a string for
|
6
|
+
# the qname with a namespace prefix that has not been declared in the
|
7
|
+
# context yet
|
8
|
+
class MissingVariableNamespaceError < StandardError
|
9
|
+
def initialize(variable_name, prefix)
|
10
|
+
@variable_name, @prefix = variable_name, prefix
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_s
|
14
|
+
"Namespace prefix ‘#{@prefix}’ for variable name ‘#{@variable_name}’ is not bound to a URI"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Represents the static context for a compiled XPath. {StaticContext}s are immutable.
|
19
|
+
class StaticContext
|
20
|
+
# methods used by both {StaticContext} and {StaticContext::DSL}
|
21
|
+
module Common
|
22
|
+
# @param args [Hash]
|
23
|
+
# @option args [Hash<Saxon::QName => Saxon::XPath::VariableDeclaration>] :declared_variables Hash of declared variables
|
24
|
+
# @option args [Hash<String => String>] :declared_namespaces Hash of namespace bindings prefix => URI
|
25
|
+
# @option args [Hash<String => java.text.Collator>] :declared_collations Hash of URI => Collator bindings
|
26
|
+
# @option args [String] :default_collation URI of the default collation
|
27
|
+
def initialize(args = {})
|
28
|
+
@declared_variables = args.fetch(:declared_variables, {}).freeze
|
29
|
+
@declared_namespaces = args.fetch(:declared_namespaces, {}).freeze
|
30
|
+
@default_collation = args.fetch(:default_collation, nil).freeze
|
31
|
+
end
|
32
|
+
|
33
|
+
# returns the context details in a hash suitable for initializing a new one
|
34
|
+
# @return [Hash<Symbol => Hash,null>] the args hash
|
35
|
+
def args_hash
|
36
|
+
{
|
37
|
+
declared_namespaces: @declared_namespaces,
|
38
|
+
declared_variables: @declared_variables,
|
39
|
+
default_collation: @default_collation
|
40
|
+
}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Provides the hooks for constructing a {StaticContext} with a DSL.
|
45
|
+
# @api private
|
46
|
+
class DSL
|
47
|
+
include Common
|
48
|
+
|
49
|
+
# Create an instance based on the args hash, and execute the passed in Proc/lambda against it using <tt>#instance_exec</tt> and return a
|
50
|
+
# new {StaticContext} with the results
|
51
|
+
# @param block [Proc] a Proc/lambda (or <tt>to_proc</tt>'d containing DSL calls
|
52
|
+
# @return [Saxon::XPath::StaticContext]
|
53
|
+
def self.define(block, args = {})
|
54
|
+
dsl = new(args)
|
55
|
+
dsl.instance_exec(&block) unless block.nil?
|
56
|
+
StaticContext.new(dsl.args_hash)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Set the default Collation to use. This should be one of the special
|
60
|
+
# collation URIs Saxon recognises, or one that has been registered
|
61
|
+
# using Saxon::Processor#declare_collations on the Processor that
|
62
|
+
# created the {XPath::Compiler} this context is for.
|
63
|
+
#
|
64
|
+
# @param collation_uri [String] The URI of the Collation to set as the default
|
65
|
+
def default_collation(collation_uri)
|
66
|
+
@default_collation = collation_uri
|
67
|
+
end
|
68
|
+
|
69
|
+
# Bind prefixes to namespace URIs
|
70
|
+
#
|
71
|
+
# @param namespaces [Hash{String, Symbol => String}]
|
72
|
+
def namespace(namespaces = {})
|
73
|
+
@declared_namespaces = @declared_namespaces.merge(namespaces.transform_keys(&:to_s)).freeze
|
74
|
+
end
|
75
|
+
|
76
|
+
# Declare a XPath variable's existence in the context
|
77
|
+
#
|
78
|
+
# @param qname [String, Saxon::QName] The name of the variable as
|
79
|
+
# explicit QName or prefix:name string form. The string form requires
|
80
|
+
# the namespace prefix to have already been declared with {#namespace}
|
81
|
+
# @param type [String, Hash{Symbol => String, Class}, null] The type of the
|
82
|
+
# variable, either as a string using the same form as an XSLT
|
83
|
+
# <tt>as=""</tt> type definition, or as a hash of one key/value where
|
84
|
+
# that key is a Symbol taken from {Saxon::OccurenceIndicator} and the
|
85
|
+
# value is either a Class that {Saxon::ItemType} can convert to its
|
86
|
+
# XDM equivalent (e.g. {::String}), or a string that {Saxon::ItemType}
|
87
|
+
# can parse into an XDM type (e.g. <tt>xs:string</tthat
|
88
|
+
# {Saxon::ItemType} can parse into an XDM type (e.g.
|
89
|
+
# <tt>xs:string</tt> or <tt>element()</tt>).
|
90
|
+
# If it's nil, then the default <tt>item()*</tt> – anything – type declaration is used
|
91
|
+
def variable(qname, type = nil)
|
92
|
+
qname = resolve_variable_qname(qname)
|
93
|
+
@declared_variables = @declared_variables.merge({
|
94
|
+
qname => resolve_variable_declaration(qname, type)
|
95
|
+
}).freeze
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
def resolve_variable_qname(qname_or_string)
|
101
|
+
Saxon::QName.resolve(qname_or_string, @declared_namespaces)
|
102
|
+
end
|
103
|
+
|
104
|
+
def resolve_variable_type_decl(type_decl)
|
105
|
+
case type_decl
|
106
|
+
when String
|
107
|
+
occurence_char = type_decl[-1]
|
108
|
+
occurence = case occurence_char
|
109
|
+
when '?'
|
110
|
+
{zero_or_one: type_decl[0..-2]}
|
111
|
+
when '+'
|
112
|
+
{one_or_more: type_decl[0..-2]}
|
113
|
+
when '*'
|
114
|
+
{zero_or_more: type_decl[0..-2]}
|
115
|
+
else
|
116
|
+
{one: type_decl}
|
117
|
+
end
|
118
|
+
when Hash
|
119
|
+
type_decl
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def resolve_variable_declaration(qname, type)
|
124
|
+
args_hash = resolve_variable_type_decl(type) || {}
|
125
|
+
args_hash[:qname] = qname
|
126
|
+
Saxon::XPath::VariableDeclaration.new(args_hash)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
include Common
|
131
|
+
|
132
|
+
# Executes the Proc/lambda passed in with a new instance of
|
133
|
+
# {StaticContext} as <tt>self</tt>, allowing the DSL methods to be
|
134
|
+
# called in a DSL-ish way
|
135
|
+
#
|
136
|
+
# @param block [Proc] the block of DSL calls to be executed
|
137
|
+
# @return [Saxon::XPath::StaticContext] the static context created by the block
|
138
|
+
def self.define(block)
|
139
|
+
DSL.define(block)
|
140
|
+
end
|
141
|
+
|
142
|
+
attr_reader :declared_variables, :declared_namespaces, :default_collation
|
143
|
+
|
144
|
+
# @return [Saxon::QName]
|
145
|
+
# @overload resolve_variable_qname(qname)
|
146
|
+
# returns the QName
|
147
|
+
# @param qname_or_string [Saxon::QName] the name as a QName
|
148
|
+
# @overload resolve_variable_qname(string)
|
149
|
+
# resolve the <tt>prefix:local_name</tt> string into a proper QName by
|
150
|
+
# looking up the prefix in the {#declared_namespaces}
|
151
|
+
# @param qname_or_string [String] the name as a string
|
152
|
+
def resolve_variable_qname(qname_or_string)
|
153
|
+
Saxon::QName.resolve(qname_or_string, declared_namespaces)
|
154
|
+
end
|
155
|
+
|
156
|
+
def define(block)
|
157
|
+
DSL.define(block, args_hash)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|