KEMBAR78
Fix reverse sort in xpath_parser by tompng · Pull Request #251 · ruby/rexml · GitHub
Skip to content

Conversation

@tompng
Copy link
Member

@tompng tompng commented Apr 30, 2025

The code below was failing with REXML::XPathParser#sort': undefined method '-@' for an instance of Array

d = REXML::Document.new("<a><b><c/><d/><x/></b><b><e/><x/></b></a>")
matches = REXML::XPath.match(d, "a/b/x/preceding-sibling::node()")
# Before: error
# After: [<e/>, <d/>, <c/>]

This pull request will fix it.

@naitoh
Copy link
Contributor

naitoh commented May 1, 2025

Thanks.
However, there may be other problems, since more <d/> tags would increase the number of <c/> and <b/> tags.

After

$ irb
> $LOAD_PATH.unshift(File.expand_path("lib"))
> require 'rexml'
> REXML::XPath.match(REXML::Document.new("<a><b/><c/><d/></a>"), "/a/d/preceding::node()")
=> [<c/>, <b/>]
> REXML::XPath.match(REXML::Document.new("<a><b/><c/><d/><d/></a>"), "/a/d/preceding::node()")
=> [<d/>, <c/>, <c/>, <b/>, <b/>]
> REXML::XPath.match(REXML::Document.new("<a><b/><c/><d/><d/><d/></a>"), "/a/d/preceding::node()")
=> [<d/>, <d/>, <d/>, <c/>, <c/>, <c/>, <b/>, <b/>, <b/>]
> REXML::XPath.match(REXML::Document.new("<a><b/><c/><d/><d/><d/><d/></a>"), "/a/d/preceding::node()")
=> [<d/>, <d/>, <d/>, <d/>, <d/>, <d/>, <c/>, <c/>, <c/>, <c/>, <b/>, <b/>, <b/>, <b/>]

@tompng
Copy link
Member Author

tompng commented May 1, 2025

I think the duplicated match result is not related to this change.
To avoid adding a test case of questionable duplicated match result, I changed the test to use preceding-sibling.

d = REXML::Document.new("<a><b><c/><d/><x/></b><b><e/><x/></b></a>")
matches = REXML::XPath.match(d, "a/b/x/preceding-sibling::node()")
# Before: REXML::XPathParser#sort': undefined method '-@' for an instance of Array
# After: [<e/>, <d/>, <c/>]

@naitoh
Copy link
Contributor

naitoh commented May 2, 2025

I think the duplicated match result is not related to this change.

I agree.
Thanks.

To avoid adding a test case of questionable duplicated match result, I changed the test to use preceding-sibling.

But, the response order is reversed from nokogiri and libxml, python(lxml).

@kou
Do you think the rexml responses is in the correct order? 🤔

$ irb -rnokogiri
> puts Nokogiri::HTML("<a><b><c/><d/><x/></b><b><e/><x/></b></a>").xpath( "//a/b/x/preceding-sibling::node()")
<c></c>
<d></d>
<e></e>
$ irb -rlibxml
> puts LibXML::XML::Document.string("<a><b><c/><d/><x/></b><b><e/><x/></b></a>").find("//a/b/x/preceding-sibling::node()").to_a
<c/>
<d/>
<e/>

https://programiz.pro/ide/python

from lxml import etree
print(etree.fromstring("<a><b><c/><d/><x/></b><b><e/><x/></b></a>").xpath('//a/b/x/preceding-sibling::node()'))

[<Element c at 0x7887f2cc7580>, <Element d at 0x7887f2cc75c0>, <Element e at 0x7887f2cc7600>]

https://scrapinghub.github.io/xpath-playground/

2025-05-02 8 38 51

https://www.w3.org/TR/2017/REC-xpath-31-20170321/#doc-xpath31-ReverseAxis

the preceding-sibling axis contains the context node's preceding siblings, those children of the context node's parent that occur before the context node in document order;

I don't think it specifically states that the order should be reversed.

@kou
Copy link
Member

kou commented May 2, 2025

But, the response order is reversed from nokogiri and libxml, python(lxml).

All of them are bindings of libxml2. So it's natural that all of them have the same behavior. :-)

Do you think the rexml responses is in the correct order? 🤔

Yes.

match returns a "node-set" that is unordered.

https://www.w3.org/TR/1999/REC-xpath-19991116/#section-Introduction

node-set (an unordered collection of nodes without duplicates)

FYI: Most implementations use XPath 1.0 not XPath 2.0, 3.1, ... REXML also uses XPath 1.0.

@naitoh
Copy link
Contributor

naitoh commented May 2, 2025

But, the response order is reversed from nokogiri and libxml, python(lxml).

All of them are bindings of libxml2. So it's natural that all of them have the same behavior. :-)

Oh!
I see.

Do you think the rexml responses is in the correct order? 🤔

Yes.

match returns a "node-set" that is unordered.

https://www.w3.org/TR/1999/REC-xpath-19991116/#section-Introduction

node-set (an unordered collection of nodes without duplicates)

FYI: Most implementations use XPath 1.0 not XPath 2.0, 3.1, ... REXML also uses XPath 1.0.

Thanks.
I see.

@tompng
Can you update this PR's description?

@tompng
Copy link
Member Author

tompng commented May 2, 2025

@naitoh Updated 👍

@naitoh naitoh merged commit de6f40e into ruby:master May 3, 2025
67 checks passed
@naitoh
Copy link
Contributor

naitoh commented May 3, 2025

Thanks!

@tompng tompng deleted the fix_xpath_reverse_sort branch May 3, 2025 05:16
naitoh added a commit to naitoh/rexml that referenced this pull request May 4, 2025
… for multiple node

## Why?
See: ruby#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>
```
naitoh added a commit to naitoh/rexml that referenced this pull request May 5, 2025
… for multiple node

## Why?
See: ruby#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>
```
naitoh added a commit to naitoh/rexml that referenced this pull request May 5, 2025
… for multiple node

## Why?
See: ruby#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/following-sibling:*[1] => ["w", "x", "y", "z"]
```xml
<div>
  <div>
    <a/> <-- self -->
    <w/> <-- //a/following-sibling:*[1] -->
  </div>
  <a/> <-- self -->
  <x/> <-- //a/following-sibling:*[1] -->
  <a/> <-- self -->
  <y/> <-- //a/following-sibling:*[1] -->
  <a/> <-- self -->
  <z/> <-- //a/following-sibling:*[1] -->
</div>
```
naitoh added a commit to naitoh/rexml that referenced this pull request May 6, 2025
… for multiple node

## Why?
See: ruby#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/following-sibling:*[1] => ["w", "x", "y", "z"]
```xml
<div>
  <div>
    <a/> <-- self -->
    <w/> <-- //a/following-sibling:*[1] -->
  </div>
  <a/> <-- self -->
  <x/> <-- //a/following-sibling:*[1] -->
  <a/> <-- self -->
  <y/> <-- //a/following-sibling:*[1] -->
  <a/> <-- self -->
  <z/> <-- //a/following-sibling:*[1] -->
</div>
```
naitoh added a commit to naitoh/rexml that referenced this pull request May 6, 2025
…ing, preceding-sibling

## Why?
See: ruby#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/following-sibling:*[1] => ["w", "x", "y", "z"]
```xml
<div>
  <div>
    <a/> <-- self -->
    <w/> <-- //a/following-sibling:*[1] -->
  </div>
  <a/> <-- self -->
  <x/> <-- //a/following-sibling:*[1] -->
  <a/> <-- self -->
  <y/> <-- //a/following-sibling:*[1] -->
  <a/> <-- self -->
  <z/> <-- //a/following-sibling:*[1] -->
</div>
```
naitoh added a commit to naitoh/rexml that referenced this pull request May 6, 2025
…ing, preceding-sibling

## Why?
See: ruby#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/following-sibling:*[1] => ["w", "x", "y", "z"]
```xml
<div>
  <div>
    <a/> <-- self -->
    <w/> <-- //a/following-sibling:*[1] -->
  </div>
  <a/> <-- self -->
  <x/> <-- //a/following-sibling:*[1] -->
  <a/> <-- self -->
  <y/> <-- //a/following-sibling:*[1] -->
  <a/> <-- self -->
  <z/> <-- //a/following-sibling:*[1] -->
</div>
```
naitoh added a commit to naitoh/rexml that referenced this pull request May 6, 2025
…ing, preceding-sibling

## Why?
See: ruby#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/following-sibling:*[1] => ["w", "x", "y", "z"]
```xml
<div>
  <div>
    <a/> <-- self -->
    <w/> <-- //a/following-sibling:*[1] -->
  </div>
  <a/> <-- self -->
  <x/> <-- //a/following-sibling:*[1] -->
  <a/> <-- self -->
  <y/> <-- //a/following-sibling:*[1] -->
  <a/> <-- self -->
  <z/> <-- //a/following-sibling:*[1] -->
</div>
```
kou pushed a commit that referenced this pull request May 6, 2025
…ing, preceding-sibling (#255)

## Why?
See: #251 (comment)

## Expected values

- 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/following-sibling:*[1] => ["w", "x", "y", "z"]
```xml
<div>
  <div>
    <a/> <-- self -->
    <w/> <-- //a/following-sibling:*[1] -->
  </div>
  <a/> <-- self -->
  <x/> <-- //a/following-sibling:*[1] -->
  <a/> <-- self -->
  <y/> <-- //a/following-sibling:*[1] -->
  <a/> <-- self -->
  <z/> <-- //a/following-sibling:*[1] -->
</div>
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants