Skip to content

Commit 2fdf0db

Browse files
committed
fix: XPath following, following-sibling, preceding, preceding-sibling for multiple node
## Why? See: #251 (comment) - XPath : a/d/preceding::* => ["d", "c", "b"] ```xml <a> <b/> <!-- a/d/preceding::b --> <c/> <!-- a/d/preceding::c --> <d/> <!-- a/d/preceding::d --> <d/> <!-- self --> <e/> <f/> </a> ``` - XPath : a/d/following::* => ["d", "e", "f"] ```xml <a> <b/> <c/> <d/> <!-- self --> <d/> <!-- a/d/following::d --> <e/> <!-- a/d/following::e --> <f/> <!-- a/d/following::f --> </a> ``` - XPath : a/b/x/following-sibling:* => ["c", "d", "e"] ```xml <a> <b> <x/> <!-- self --> <c/> <!-- a/b/x/following-sibling::c --> <d/> <!-- a/b/x/following-sibling::d --> </b> <b> <x/> <!-- self --> <e/> <!-- a/b/x/following-sibling::e --> </b> </a> ``` - XPath : a/b/x/following-sibling:* => ["c", "d", "x", "e"] ```xml <a> <b> <x/> <!-- self --> <c/> <!-- a/b/x/following-sibling::c --> <d/> <!-- a/b/x/following-sibling::d --> <x/> <!-- a/b/x/following-sibling::x --> <e/> <!-- a/b/x/following-sibling::e --> </b> </a> ``` - XPath : a/b/x/preceding-sibling::* => ["e", "d", "c"] ```xml <a> <b> <c/> <!-- a/b/x/preceding-sibling::c --> <d/> <!-- a/b/x/preceding-sibling::d --> <x/> <!-- self --> </b> <b> <e/> <!-- a/b/x/preceding-sibling::e --> <x/> <!-- self --> </b> </a> ``` - XPath : a/b/x/preceding-sibling::* => ["e", "x", "d", "c"] ```xml <a> <b> <c/> <!-- a/b/x/preceding-sibling::c --> <d/> <!-- a/b/x/preceding-sibling::d --> <x/> <!-- a/b/x/preceding-sibling::x --> <e/> <!-- a/b/x/preceding-sibling::e --> <x/> <!-- self --> </b> </a> ``` - XPath : //a/x/following-sibling:*[1] => ["w", "x", "y", "z"] ```xml <div> <div> <a/> <-- self --> <w/> <-- //a/x/following-sibling:*[1] --> </div> <a/> <-- self --> <x/> <-- //a/x/following-sibling:*[1] --> <a/> <-- self --> <y/> <-- //a/x/following-sibling:*[1] --> <a/> <-- self --> <z/> <-- //a/x/following-sibling:*[1] --> </div> ```
1 parent de6f40e commit 2fdf0db

File tree

2 files changed

+40
-1
lines changed

2 files changed

+40
-1
lines changed

lib/rexml/xpath_parser.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ def match(path_stack, nodeset)
147147
unnode(result)
148148
else
149149
[result]
150-
end
150+
end.uniq
151151
end
152152

153153
private

test/xpath/test_base.rb

+39
Original file line numberDiff line numberDiff line change
@@ -416,10 +416,49 @@ def test_preceding
416416
assert_equal( 4, cs.length )
417417
end
418418

419+
def test_preceding_multiple
420+
d = REXML::Document.new("<a><b/><c/><d/><d/><e/><f/></a>")
421+
matches = REXML::XPath.match(d, "a/d/preceding::node()")
422+
assert_equal(["d", "c", "b"], matches.map(&:name))
423+
end
424+
425+
def test_following_multiple
426+
d = REXML::Document.new("<a><b/><c/><d/><d/><e/><f/></a>")
427+
matches = REXML::XPath.match(d, "a/d/following::node()")
428+
assert_equal(["d", "e", "f"], matches.map(&:name))
429+
end
430+
431+
def test_following_sibling
432+
d = REXML::Document.new("<a><b><x/><c/><d/></b><b><x/><e/></b></a>")
433+
matches = REXML::XPath.match(d, "a/b/x/following-sibling::node()")
434+
assert_equal(["c", "d", "e"], matches.map(&:name))
435+
436+
d = REXML::Document.new("
437+
<div>
438+
<div>
439+
<a/><w/>
440+
</div>
441+
<a/><x/>
442+
<a/><y/>
443+
<a/><z/>
444+
</div>")
445+
# Finds a node flowing <a/>
446+
matches = REXML::XPath.match(d, "//a/following-sibling::*[1]")
447+
assert_equal(["w", "x", "y", "z"], matches.map(&:name))
448+
449+
d = REXML::Document.new("<a><b><x/><c/><d/><x/><e/></b></a>")
450+
matches = REXML::XPath.match(d, "a/b/x/following-sibling::node()")
451+
assert_equal(["c", "d", "x", "e"], matches.map(&:name))
452+
end
453+
419454
def test_preceding_sibling
420455
d = REXML::Document.new("<a><b><c/><d/><x/></b><b><e/><x/></b></a>")
421456
matches = REXML::XPath.match(d, "a/b/x/preceding-sibling::node()")
422457
assert_equal(["e", "d", "c"], matches.map(&:name))
458+
459+
d = REXML::Document.new("<a><b><c/><d/><x/><e/><x/></b></a>")
460+
matches = REXML::XPath.match(d, "a/b/x/preceding-sibling::node()")
461+
assert_equal(["e", "x", "d", "c"], matches.map(&:name))
423462
end
424463

425464
def test_following

0 commit comments

Comments
 (0)