I don't fully understand the behaviour I'm seeing when using XPath union operator.
Having the following XML
<root>
<foo>hello</foo>
<bar>world</bar>
</root>
We get these results for different XPath expressions
(/root/foo | /root/bar)[1] -> hello
(/root/foo | /root/bar)[last()] -> world
(substring(/root/foo, 2, 4) | /root/bar)[1] -> ello
(substring(/root/foo, 2, 4) | /root/bar)[last()] -> world
So far, they are intuitive results but...
(/root/foo | substring(/root/bar, 2, 4))[1] -> orld (expected hello)
(/root/foo | substring(/root/bar, 2, 4))[last()] -> hello (expected orld)
Is there a reason for results presented? Are these compliant with XPath 2.0 spec?
TIBCO BusinessWorks is XPath 1.0 compliant only. Some XPath 2.0 functions are supported.
(source: FAQ1-7BXZE5 on http://support.tibco.com)
To answer your two questions:
"Is there a reason for results presented?"
Yes. XPath 1.0 union results are unpredictable. A good rule: One should not rely on Union order in BusinessWorks, even for simple cases.
"Are these compliant with XPath 2.0 spec?"
The results are not compliant with XPath 2.0 specification but your queries are evaluated with an XPath 1.0 engine.
No, the last two results are not compliant with the spec. It's a type error if an operand to the union operator is a string rather than a node, which is the case in your last two examples.
Related
XPathError
message: "Invalid expression.
(string-join(/form/Data/MProcess/Process/Id/string(), ','))
I thought the problem was Process Id was not returning string so I tried string() and text() but they did not work. I can't find the solution.
Here is an example process id: aee865d1-7253-489c-8d53-2a0d580639d0
string-join() is an XPath 2.0 function, and many early XPath processors were never upgraded to 2.0. Check what XPath processor you are using and what language level it supports, and upgrade if you can.
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.
Is it possible to find same-name siblings (SNS) using SQL2, SQL, XPath or QueryBuilder in Adobe CQ5/Adobe Experience Manager. We are trying to prepare the instance for upgrade to AEM 6.X and as already known jackrabbit oak has disabled the support for SNS, which makes the upgrade without solving this problem impossible. The repository could be traversed recursively, but this is too slow and I'm looking for better options using queries. SNS are defined as follows:
/a/b/c
/a/b/c[2]
/a/b/c[3]
/a/b[2]/c[2]
/a/b/c[3]
I would prefer SQL2, but any other option is also possible.
Note that no functions or xslt are possible, because we are not talking about xml documents, but for java content repository (JCR).
In XQuery 1.0 or XPath 3.0 the same-name siblings of the context node can be found as
let $n := node-name(.)
return (preceding-sibling::* | following-sibling::*)[node-name(.) = $n]
or as
let $n := node-name(.)
return ../*[node-name(.) = $n] except .
(the "except ." can be omitted if you want to include the original element in the result).
I don't think that a pure XPath 1.0 solution is possible, because of the absence of range variables, but with XPath 1.0 within XSLT 1.0 you can do
(preceding-sibling::* | following-sibling::*)
[local-name(.) = local-name(current()) and
namespace-uri(.) = namespace-uri(current())]
I learned that every Xpath expression is also a valid Xquery expression. I'm using Oxygen 16.1 with this sample XML:
<actors>
<actor filmcount="4" sex="m" id="15">Anderson, Jeff</actor>
<actor filmcount="9" sex="m" id="38">Bishop, Kevin</actor>
</actors>
My expression is:
//actor/#id
When I evaluate this expression in Oxygen with Xpath 3.0, I get exactly what I expect:
15
38
However, when I evaluate this expression with Xquery 3.0 (also 1.0), I get the message: "Your query returned an empty sequence.
Can anyone provide any insight as to why this is, and how I can write the equivalent Xquery statement to get what the Xpath statement did above?
Other XQuery implementations do support this query
If you want to validate that your query (as corrected per discussion in comments) does in fact work with other XQuery implementations when entered exactly as given in the question, you can run it as follows (tested in BaseX):
declare context item := document { <actors>
<actor filmcount="4" sex="m" id="15">Anderson, Jeff</actor>
<actor filmcount="9" sex="m" id="38">Bishop, Kevin</actor>
</actors> };
//actor/#id
Oxygen XQuery needs some extra help
Oxygen XML doesn't support serializing attributes, and consequently discards them from a result sequence when that sequence would otherwise be provided to the user.
Thus, you can work around this with a query such as the following:
//actor/#id/string(.)
data(//actor/#id)
Below applies to a historical version of the question.
Frankly, I would not expect //actors/#id to return anything against that data with any valid XPath or XQuery engine, ever.
The reason is that there's only one place you're recursing -- one // -- and that's looking for actors. The single / between the actors and the #id means that they need to be directly connected, but that's not the case in the data you give here -- there's an actor element between them.
Thus, you need to fix your query. There are numerous queries you could write that would find the data you wanted in this document -- knowing which one is appropriate would require more information than you've provided:
//actor/#id - Find actor elements anywhere, and take their id attribute values.
//actors/actor/#id - Find actors elements anywhere; look for actor elements directly under them, and take the id attribute of such actor elements.
//actors//#id - Find all id attributes in subtrees of actors elements.
//#id - Find id attributes anywhere in the document.
...etc.
I'm working with CALS tables which has multiple colspec elements with tgroup element as a parent.
In xpath 2.0 the following works:
colspec/substring-before( #colwidth , '*' )
In xpath 1.0 it complains: Unexpected token - "substring-before( #colwid"
There has to be a way to accomplish this. I need to sum the number values before the asterisk so that I can convert the relative column widths to percentages. At this point in the day I can't even think of an inelegant solution.
In xpath 1.0 it complains: Unexpected
token - "substring-before( #colwid"
That's because right term of / step operator can't be a function call in XPath 1.0 (This is a feature of XPath 2.0!).
You have to develop a recursive template.