From a1a2190fe28dbcbdc4a4dda965a19660eb597690 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Mon, 25 Aug 2014 23:13:34 +0200 Subject: [PATCH] Support for the XPath substring() function. --- lib/oga/xpath/evaluator.rb | 39 +++++++++++++++++++ .../xpath/evaluator/calls/substring_spec.rb | 30 ++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 spec/oga/xpath/evaluator/calls/substring_spec.rb diff --git a/lib/oga/xpath/evaluator.rb b/lib/oga/xpath/evaluator.rb index 4debd4d..33a7aa2 100644 --- a/lib/oga/xpath/evaluator.rb +++ b/lib/oga/xpath/evaluator.rb @@ -920,6 +920,45 @@ module Oga return sep.empty? ? sep : after end + ## + # Processes the `substring()` function call. + # + # This function call returns the substring of the 1st argument, starting + # at the position given in the 2nd argument. If the third argument is + # given it is used as the length for the substring, otherwise the string + # is consumed until the end. + # + # XPath string indexes start from position 1, not position 0. + # + # @example Using a literal string + # substring("foo", 2) # => "oo" + # + # @exxample Using a literal string with a custom length + # substring("foo", 1, 2) # => "fo" + # + # @example Using a node set + # substring(users/user/username, 5) + # + # @param [Oga::XML::NodeSet] context + # @param [Oga::XPath::Node] haystack + # @param [Oga::XPath::Node] start + # @param [Oga::XPath::Node] length + # @return [String] + # + def on_call_substring(context, haystack, start, length = nil) + haystack_str = on_call_string(context, haystack) + start_index = on_call_number(context, start).to_i - 1 + + if length + length_int = on_call_number(context, length).to_i - 1 + stop_index = start_index + length_int + else + stop_index = -1 + end + + return haystack_str[start_index..stop_index] + end + ## # Processes an `(int)` node. # diff --git a/spec/oga/xpath/evaluator/calls/substring_spec.rb b/spec/oga/xpath/evaluator/calls/substring_spec.rb new file mode 100644 index 0000000..c07a3f6 --- /dev/null +++ b/spec/oga/xpath/evaluator/calls/substring_spec.rb @@ -0,0 +1,30 @@ +require 'spec_helper' + +describe Oga::XPath::Evaluator do + context 'substring() function' do + before do + @document = parse('foobar3') + @evaluator = described_class.new(@document) + end + + example 'return the substring of a string' do + @evaluator.evaluate('substring("foo", 2)').should == 'oo' + end + + example 'return the substring of a string using a custom length' do + @evaluator.evaluate('substring("foo", 2, 1)').should == 'o' + end + + example 'return the substring of a node set' do + @evaluator.evaluate('substring(root/a, 2)').should == 'oobar' + end + + example 'return the substring of a node set with a node set as the length' do + @evaluator.evaluate('substring(root/a, 1, root/b)').should == 'foo' + end + + example 'return an empty string when the source string is empty' do + @evaluator.evaluate('substring("", 1, 3)').should == '' + end + end +end