Xpath | operator inside the path - xpath

I have an xpath as follows:
.//*[text()='Name:']/../child::select | .//*[text()='Name:']/../child::span
However for me it's not very compact nor elegant, I'd prefer something along the lines of:
.//*[text()='Name:']/../child::(select|span)
But the above solution does not work.
The idea is that the text (e.g. 'Name:' is passed as an argument to a function, and it returns the node that might be of type either select or span.
Would appreciate help greatly.

You can use the | operator with self:
.//*[text()='Name:']/../child::*[self::span | self::select]
The child:: is the default, so it could be shortened to
.//*[text()='Name:']/../*[self::span | self::select]

Related

LogQL - label_format conditionally format a label

I have a log stream from where I am extracting a set of fields to be set as either labels or metric values. The stream is not in a standard format so I am extracting the fields with regexp pipeline command, as below.
(...)
| regexp "(?P<api>\\w+)\\sAPI"
| regexp "\\[performed\\.(?P<action>\\w+)"
| regexp "duration\\s\\[(?P<duration_ms>\\d+)"
| regexp "response \\[(?P<response>.*?)\\]"
The problem is that the api captured field, on some interaction, is not being populated, and I wanted to update those cases so that a default value was set - For presentation purposes.
I've tried using the native LogLQ's contains and hasPrefix template commands as the documentation suggests they can be used with if else blocks. The documentation is not clear on how to build those blocks inside the label_format or the line_format pipeline commands. But depending on the approach it either returns a format error or does not do anything.
An working example would be appreciated.
Thank you.
Note: Tried to tag this as a LogQL topic but not enough reputation to do so.
I believe I have gotten something working with line_format:
{environment=~"$environment",level=~"$level"} | json | line_format "{{ if hasSuffix `Exception` .thrown_name }} Exception occurred! {{end}} {{.message}}" |~ "(?i)$grep"
The documentation for back ticks was difficult to find, and the order for method arguments is also a bit different. Hopefully this helps?
With #AnthonyA's reply I was able to, after extracting a field, modify its value using the label_format template function.
(..)
| regexp "response \\[(?P<response>.*?)\\]"
(..)
| label_format api=`{{ if hasPrefix "Error" .response }}ERROR{{else}}{{.response}}{{end}}`
(..)
This way the field's value is replaced by ERROR if it starts with "Error" and keeping its original value otherwise.

Syntax of a language in BNF, how to indicate the "other similar" options

I'm tryting to write a small language syntax using BNF style. I came to an option like this:
option ::= 'option1' | 'option2' | 'read' | 'write' | etc
The first four options are as example of what values the option can have, but I can't enumerate all of them and nor I can group them. Instead, I thought to use something like etc, but I don't know if a syntax can have it. Any idea how these options can be shown, what to write instead of etc?
Thank you!

Select element and its descendants

I'm trying to select an folder and its descendants from a JCR with XPath. I can select the folder easily enough:
//content/documents/folder-name
I can select its descendants too:
//content/documents/folder-name//*
However, I can't figure out how to get both. I've tried several things. These select nothing:
//content/documents/folder-name | //content/documents/folder-name//*
//content/documents/folder-name(. | *)
//content/documents/folder-name/(. | *)
//content/documents/folder-name/descendant-or-self
//content/documents/folder-name/descendant-or-self::node()
These both throw a javax.jcr.query.InvalidQueryException:
//content/documents/folder-name[. | *]
//content/documents/folder-name/[. | *]
Obviously I'm terrible at XPath. Please help.
Edit: I was using the // prefix because I didn't realize I could use /jcr:root/content instead. I have the same problem with that, however.
You can combine two XPaths using the union operator:
xpath1 | xpath2
However, your first XPath,
//content/documents/folder-name
does select the folder-name element(s), which includes the descendants of the element.
If you want the folder-name elements to be first in a list, followed by their descendants, you could combine as follows:
//content/documents/folder-name | //content/documents/folder-name//*
//content/documents/folder-name/descendant-or-self::node() looks correct to me (without seeing your XML input), though //content/documents/folder-name/descendant-or-self::* is probably better.
Certainly if //content/documents/folder-name selects something then ``//content/documents/folder-name/descendant-or-self::*` should also select something.
In XPath 2.0 you can do //content/documents/folder-name/(.|descendant::*) but although it's shorter, it seems clumsier to me than using the descendant-or-self axis.

Xpath expression with OR

I'd like to know if there is a way to verify multiple strings on a Xpath. This is the one I'm using now:
/td[2][text()[contains(.,'Word1')]]
I'd like to do something like this:
/td[2][text()[contains(.,'Word1' OR 'Word2' OR 'Word3')]]
Is that possible?
Updated answer:
I believe, the problem why you are experiencing is case-sensitivity, try writing or in lower-case:
//td[text()[contains(.,'Word1') or contains(.,'Word2') or contains(.,'Word3')]]
If it doesn't help, you can use Union approach:
/td[2][text()[contains(.,'Word1')]] | /td[2][text()[contains(.,'Word2')]] | /td[2][text()[contains(.,'Word3')]]
yes it's possible:
/td[2][text()[contains(.,'Word1') OR contains(.,'Word2') OR contains(.,'Word3')]]
Yes - you just need separate contains() calls:
[contains(., 'Word1') OR contains(., 'Word2') OR contains(., 'Word3')]
As you have it currently, a boolean being passed as the second parameter to contains, rather than a string.
With XPath 2.0 or 3.0 you could also use:
A Quantified Expression to loop over a sequence of words and test if any of the words are contained
//td[2][text()[some $word in ('Word1', 'Word2', 'Word3') satisfies contains(., $word)]]
The matches() function and specify your list of words in a regex:
//td[2][text()[matches(., 'Word1|Word2|Word3')]]

combine two xpath expretion with the same prefix

I'm trying to find some way to merge the result of two xpath queries with the same prefix.
Say: /inventory/product/itemNumber | /inventory/product/itemName
I'm looking for something like /inventory/product/(itemNumber | itemName) (the order of the output is irreverent for me).
Basically, I'm trying to find a way not to write the long prefix twice.
Thanx!
The way to accomplish this is the following:
/inventory/product/*[self::itemNumber or self::itemName]

Resources