Page 1 of 1

Exclude node during searches

Posted: Fri Dec 06, 2013 10:12 am
by jorusso
I'm in DITA and my goal is to search for text that is not inside a particular element. For example I want to search for "ABC Corp." that is not inside <codeblock>. I should be able to specify any of the following Xpath statements:
  • //*[(name()!='codeblock')]
    //*[not(self::codeblock)]
    //*[not(codeblock)]
All of these give the expected results in the XPath field on the toolbar. However, none of them work when I use them in the XPath field in the Find dialog box.

What am I doing wrong?

Re: Exclude node during searches

Posted: Sat Dec 07, 2013 3:47 pm
by Jamil
I had never used the XPath input on the find dialog. It could very well be an issue with it.

What you could do instead is write an XQuery to show you what you are looking for. The Saxon extensions for it can show the line numbers of the XML document.

Re: Exclude node during searches

Posted: Mon Dec 09, 2013 9:34 pm
by jorusso
Thanks, Jamil.

I've been looking for an excuse to study XQuary, anyway!
So having a real-world need is perfect. :shock:

Re: Exclude node during searches

Posted: Fri Dec 13, 2013 4:42 pm
by adrian
Hello,

The problem with the XPath expressions you're using is that even though they exclude the codeblock element, they don't exclude any of codeblock's parent elements. Find will search in the most extensive range selected by the XPath (it merges the XPath results), which in all cases for your expressions includes the root element and everything in it.
So, in short the expressions you are using don't filter what you want.

If you want to search only within text that is not inside <codeblock>, you could specify that clearly in the XPath expression:

Code: Select all

//text()[not(ancestor::codeblock)]
Or if you want to also search across multiple (text) nodes (e.g. text with markup) you can use in the XPath field:

Code: Select all

//*[not(descendant-or-self::codeblock)]|//text()[not(ancestor::codeblock)]
XQuery is pretty powerful, but you'll still need XPath there as well.

Regards,
Adrian

Re: Exclude node during searches

Posted: Thu Feb 13, 2014 2:26 am
by jorusso
Adrian,

Thanks for the helpful reply! Sorry it took so long to reply, I forgot to log back in to check for a reply.

Can you offer any recommendations on learning XPath? I've done the W3 tutorial and know just enough to get myself in trouble!

-joe

Re: Exclude node during searches

Posted: Thu Feb 13, 2014 6:51 pm
by adrian
Hi,

Unfortunately most online tutorials are for the beginner level, so they overlap a lot.
You could also give zvon.org a try:
http://zvon.org/comp/r/tut-XPath_1.html

As usual, experience is the best teacher, so you should try various things on your own. When something doesn't work as you expect it, search the web for answers.

Regards,
Adrian

Re: Exclude node during searches

Posted: Thu Jun 07, 2018 2:28 am
by shudson310
Here's a related question:

We want to find:

Code: Select all

<wintitle>some text</wintitle>
and replace with:

Code: Select all

<wintitle keyref="someKey" />
We've tried restricting the XPath to:

Code: Select all

//*[not(descendant-or-self::alt|descendant-or-self::title|descendant-or-self::shortdesc|descendant-or-self::draft-comment)]|//text()[not(ancestor::alt|ancestor::title|ancestor::shortdesc|ancestor::draft-comment)]
Unfortunately, we are still getting results within shortdesc, so the exclusion doesn't appear to work. I think this is due to the fact that we are trying to modify an element node and turn it into a keyref.

Any suggestions on how to search/replace across files with the exclusions we're trying to achieve?

Re: Exclude node during searches

Posted: Thu Jun 07, 2018 11:17 am
by adrian
Hi,

There is a mistake in my XPath (from 4 years ago) that covers elements and text (for text with markup). It should be:

Code: Select all

//*[not(descendant-or-self::codeblock|ancestor::codeblock)]|//text()[not(ancestor::codeblock)]
This way it won't accept
So, try this one (note that you don't need the //text if you're searching markup):

Code: Select all

//*[not(descendant-or-self::alt|descendant-or-self::title|descendant-or-self::shortdesc|descendant-or-self::draft-comment|ancestor::alt|ancestor::title|ancestor::shortdesc|ancestor::draft-comment)]
Regards,
Adrian

Re: Exclude node during searches

Posted: Thu Jun 07, 2018 3:40 pm
by shudson310
That worked perfectly. Thanks for the quick, expert help!