Possible bug in XPath option Find/Replace: using not()

Having trouble installing <oXygen/>? Got a bug to report? Post it all here.
dnl
Posts: 14
Joined: Tue Aug 28, 2018 3:51 pm

Possible bug in XPath option Find/Replace: using not()

Post by dnl » Fri Mar 26, 2021 2:23 pm

I am puzzled by the following behaviour in Oxygen 23.0:

* Find/Replace a string
* Use XPath option: *[not(local-name() eq 'element_name')]

-> It also shows matches in element_name (which is wrong).

When I use the expression without not(), the predicate gets evaluated OK:

* Find/Replace a string
* Use XPath option: *[local-name() eq 'element_name']

-> It shows me only text in element_name.

Is this a bug? It does not make sense at all to me...

adrian
Posts: 2717
Joined: Tue May 17, 2005 4:01 pm

Re: Possible bug in XPath option Find/Replace: using not()

Post by adrian » Fri Mar 26, 2021 6:10 pm

Hi,

Note that the context of the XPath used in the Find/Replace dialog is the document root, not the cursor position. Oxygen only evaluates the expression once, because the context is the same.
So, the problem with *[not(local-name() eq 'element_name')] is that it matches any element other than element name. The root element is probably not named element_name, so it matches that. If it matches the root element, it will search all its contents, even the parts within element_name, so that's why nothing gets filtered. This means negative matching conditions don't work at all, if they allow the root or an ancestor to match, the same goes for descendants.
So the expression you're looking for is a little more complicated:

Code: Select all

//*[not(descendant-or-self::*[local-name() eq 'element_name'] or ancestor::*[local-name() eq 'element_name'])]
This selects all elements that don't have a descendant that is named or themselves are named element_name (this excludes the root element) and don't have ancestors that are named element_name (the children).
Note that this creates a very shallow XPath tree result, so if you're actually looking for something from an ancestor element of element_name, it will not find it.

PS: When in doubt over an XPath expression test it out in the XPath toolbar or XPath/XQuery Builder view. But remember that the context of the Find/Replace dialog is the document root, so start with '/'.

Regards,
Adrian
Adrian Buza
<oXygen/> XML Editor, Schema Editor and XSLT Editor/Debugger
http://www.oxygenxml.com

dnl
Posts: 14
Joined: Tue Aug 28, 2018 3:51 pm

Re: Possible bug in XPath option Find/Replace: using not()

Post by dnl » Fri Mar 26, 2021 7:03 pm

Thanks for the clarification, Adrian. That makes sense.

But perhaps you could make this more clear in the documentation and/or find/replace window what the context is.

I find it somewhat irritating behaviour:

* if you open Find/Replace and hit "Find", your context is the current cursor position
* if you hit "Find all", your context (as expected) is the document root

This does not get reflected with the XPath filter.
So in a normal search your context is the cursor position, but when you enter an Xpath, you then have two contexts: the cursor position (for the Find button) and the document root (for the XPath)!

If you know this, you can work with it, but in my opinion it should be better documented :)

adrian
Posts: 2717
Joined: Tue May 17, 2005 4:01 pm

Re: Possible bug in XPath option Find/Replace: using not()

Post by adrian » Fri Mar 26, 2021 8:22 pm

Hi,

The XML context of the XPath evaluation is always the document root (so it's at document level), it's not affected by cursor position.
I've logged a documentation issue to clarify the XML context for the XPath filter evaluation. Although, it would probably be best to also mention it in the UI.
I find it somewhat irritating behaviour:

* if you open Find/Replace and hit "Find", your context is the current cursor position
* if you hit "Find all", your context (as expected) is the document root
I believe you're referring to the search scope.
The default search scope is the entire document. The XPath filter restricts the search scope to the result of the XPath evaluation.
"Find All" and "Replace all" work on the entire search scope (entire document or entire XPath result, if that's specified) and start searching at the beginning of the said scope.
The other find actions, while working within the same scope, they all start searching at the cursor position (or from the start of the first region within the scope after the cursor position). With "Wrap around" enabled, the Find action, after reaching the the end of the scope, continues searching from the start of the scope.

Regards,
Adrian
Adrian Buza
<oXygen/> XML Editor, Schema Editor and XSLT Editor/Debugger
http://www.oxygenxml.com

Post Reply