Jackrabbit - Select node with maximum property value - xpath

Let's say I have several file nodes with a property called foo. In Jackrabbit the xpath query I use to find those nodes by a property value is as follows:
/jcr:root/content/*[jcr:uuid='9b3d22fc-2354-49a6-afd0-9b672ae5a553']//file[foo = 10] order by #score
An oversimplified and raw representation of my repository as XML would look like this:
<content>
<formNode jcrUuid="9b3d22fc-2354-49a6-afd0-9b672ae5a553">
<year>
<month>
<day>
<hour>
<min>
<file foo="4"></file>
<file foo="10"></file>
</min>
</hour>
</day>
<day>
<hour>
<min>
<file foo="10"></file>
</min>
<min>
<file foo="5"></file>
</min>
</hour>
<hour>
<min>
<file foo="6"></file>
</min>
</hour>
</day>
</month>
</year>
</formNode>
</content>
Now. How can I find all the file nodes with the maximum value of foo? Does anyone know how to do this either by using xpath or JCR_SQL2?
I've tried the following queries without success:
Returns all the file nodes under the provided jcr:uuid
/jcr:root/content/*[jcr:uuid='9b3d22fc-2354-49a6-afd0-9b672ae5a553']//file[not(../file/foo > foo)] order by #score
Throws an Exception
jcr:root/content/*[jcr:uuid='9b3d22fc-2354-49a6-afd0-9b672ae5a553']//file[not(//file/foo > foo)] order by #score
Exception:
javax.jcr.query.InvalidQueryException: Unsupported root level query node: org.apache.jackrabbit.spi.commons.query.RelationQueryNode#8fedc
I've also tried the function fn:max. But AFAIK this is a XPATH 2.0 feature, which is not supported by JackRabbit 2.2.13, and I'm forced to use this version of JackRabbit.

Related

Select children but exclude specific one

I have this XML structure:
<?version="1.0" encoding="ISO-8859-1" ?>
<feed xmlns="http://www.w3.org/2005/Atom" >
<companyinfo>
<addresses>
<address type="mailing" >
<city>NEW YORK</city>
</address>
<address type="business" >
<city>NEW YORK</city>
</address>
<node1>node1</node1>
<node2>node2</node2>
<node3>nod3</node3>
</addresses>
</companyinfo>
</feed>
I want to select all children of <companyinfo> but exclude addresses from the result. Meaning my selection becomes all the <nodeX>.
After reading around and looking at related threads this and this, I came up with the following:
//companyinfo[not(addresses)] # does not work
//companyinfo/*[not(addresses)] # does not work
Am I misunderstanding how not(expr) works?
Am I actually trying to select companyinfo IF addresses node is not present?
Your xml is invalid, but if you fix it (and the typo), this expression, though convoluted,
//*[local-name()="companyinfo"]//*[local-name()="addresses"]//*[not(ancestor-or-self::*[local-name()="address"])]
should output
node1
node2
node3

XPath 1.0 return node with two conditons

My current XPath returns ancestor-or-self nodes matching criteria.
//*[contains(., '"& v_search &"')]/ancestor-or-self::*/*[local-name()='name' and #locale='en']
Now I want to implement addition feature to return following-sibling from the matching nodes. I have changed my XPath as below. But it doesn't return ancestor-or-self plus sibling in result.
//*[contains(., '"& v_search &"')]/ancestor-or-self::*/following-sibling::*/*[local-name()='name' and #locale='en']
here v_search is a variable that can be replaced by any string for testing.
My xml is like :-
<root xmlns="https://jlkjsdlfjl/">
<name>Accounts</name>
<property name="included" type="hidden">true</property>
<locales>
<locale>en</locale>
<locale>de</locale>
</locales>
<defaultLocale>en</defaultLocale>
<searchspace>
<name locale="en">Accounts</name>
<name locale="de">Accounts</name>
<lastChanged>2014-03-05T18:47:30</lastChanged>
<lastChangedBy>userx</lastChangedBy>
<property name="included" type="hidden">true</property>
<searchspace>
<name locale="en">Database L</name>
<name locale="zw">Database L</name>
<searchSubject status="valid">
<name locale="en">SName1</name>
<name locale="zw">qskxyz</name>
<searchItem>
<name locale="en">IName1</name>
<name locale="zw">qixyz</name>
<hello>v_search</hello>
</searchItem>
<searchItem>
<name locale="en">IName2</name>
<name locale="zw">abc</name>
v_search
</searchItem>
<searchItem>
<name locale="en">IName3</name>
<name locale="zw">def</name>
<hello>something else</hello>
</searchItem>
</searchSubject>
</searchspace>
</searchspace>
<searchspace>
<name locale="en">Names</name>
<lastChanged>2016-01-12T12:42:46</lastChanged>
<searchspace>
<name locale="en">Database Layer</name>
<name locale="zw">Database Layer</name>
<searchSubject status="valid">
<name locale="en">SName2</name>
<searchItem>
<name locale="en">IName4</name>
<hello>...Hi there..</hello>
</searchItem>
</searchSubject>
</searchspace>
</searchspace>
</root>
v_search is sample keyword, I want to return sibling of lowest matching nodes.
i.e. sibling of self from ancestor-or-self.
The easiest way might be to introduce 2nd expression that will return 'following-sibling' of the matched element. You can combine the 2nd expression with the existing one using union (|) operator as follow (wrapped for readability) :
//*[contains(., 'v_search')]
/ancestor-or-self::*
/*[local-name()='name' and #locale='en']
|
//*[text()[contains(.,'v_search')]]
/following-sibling::*
/*[local-name()='name' and #locale='en']
Brief test : http://www.xpathtester.com/xpath/294a1ef49d30eb6abecf2f024cfcd318

Summary table with xForms

I have an xml like the following:
<table1>
<row>
<person>person1</person>
<value>10</value>
</row>
<row>
<person>person2</person>
<value>20</value>
</row>
<row>
<person>person1</person>
<value>5</value>
</row>
</table1>
<summaryTable>
<row>
<person>person1</person>
<value_total/>
</row>
<row>
<person>person2</person>
<value_total/>
</row>
</summaryTable>
With XForms 1 (there is no option to switch to XForms 2), using framework betterform, I want to calculate the values in the summary table, by doing the SUM of the rows in 'table1' that have the same person name. To do that I have the following binds:
<xf:bind id="bind_table1"
nodeset="table1" repeatableElement="row">
<xf:bind id="bind_head_table1" nodeset="head" />
<xf:bind id="bind_row_table1" nodeset="row">
<xf:bind id="bind_person" nodeset="person" type="xf:string" />
<xf:bind id="bind_value" nodeset="value" type="xf:integer" />
</xf:bind>
</xf:bind>
<xf:bind id="bind_summaryTable"
nodeset="summaryTable"
repeatableElement="row">
<xf:bind id="bind_head_summaryTable" nodeset="head" />
<xf:bind id="bind_row_summaryTable" nodeset="row">
<xf:bind id="bind_person_name" nodeset="person_name" type="xf:string" readonly="true"/>
<xf:bind id="bind_value_total" nodeset="value_total" type="xf:integer" readonly="true" calculate="SUM(//table1/row[person/text() = ../person_name/text()]/value)"/>
</xf:bind>
</xf:bind>
What I want to have at the end is the value_total for person1 = 15 and value_total for person2 = 20, but using this 'calculate' expression I'm getting 'NaN'. If I replace the calculate expression to compare with a literal String like:
<xf:bind id="bind_value_total" nodeset="value_total" type="xf:integer" readonly="true" calculate="SUM(//table1/row[person/text() = 'person1']/value)"/>
then I get as value_total 15 (the sum is correctly done). So it seems that the error is in the comparison expression person/text() = ../person_name/text() . Does someone have an idea about how should be the correct expression?
Thanks
Try the context() function in the calculate attribute to refer to the current node, like this:
<xf:bind nodeset="summaryTable/row/value_total" calculate="sum(//table1/row[person/text() = context()/../person/text()]/value)"/>
The context function gives you the current context node. If your bind references a nodeset with multiple nodes, it will be evaluated one time for every node, and that node is what context() returns.
It works for me with XSLTForms, maybe your version of betterForm supports it.

xpath expression to compare and evaluate value based on condition

<School>
<Child_One>
<Subject>
<name>computers</name>
<marks>55</marks>
<name>mathematics</name>
<marks>44</marks>
</Subject>
<Child_One>
<Child_Two>
<name>computers</name>
<marks>66</marks>
<name>mathematics</name>
<marks>77</marks>
</Child_Two>
</School>
Can anybody help me to find the Child_One subject name, in which he got highest marks
Thanks
First of all a few formatting things:
Your XML is not quite well formatted. It should have the same start and end tags
I believe the Subject element should look different then posted
When posting a input XML, don't use backticks, but indent the XML with 4 spaces to format it well on Stackoverflow
I used and changed the input XML to this:
<?xml version="1.0" encoding="UTF-8"?>
<School>
<Child_One>
<Subject>
<name>computers</name>
<marks>55</marks>
</Subject>
<Subject>
<name>mathematics</name>
<marks>44</marks>
</Subject>
</Child_One>
<Child_Two>
<Subject>
<name>computers</name>
<marks>66</marks>
</Subject>
<Subject>
<name>mathematics</name>
<marks>77</marks>
</Subject>
</Child_Two>
</School>
With XPath 2.0 you can use the following the find the max value:
/School/Child_One/Subject[marks = max(/School/Child_One/Subject/marks)]/name
With XPath 1.0 you can use the following (replace < with > to find minimum):
/School/Child_One/Subject[not(marks < /School/Child_One/Subject/marks)][1]/name

traversing ruby map issues

I'm pulling the following XML from mediawiki API
<?xml version="1.0"?>
<api>
<query>
<pages>
<page pageid="309311" ns="0" title="Chenonetta jubata">
<images>
<im ns="6" title="File:Australian Wood Duck.jpg" />
<im ns="6" title="File:Australian Wood Duck Female.JPG" />
<im ns="6" title="File:Australian Wood Duck Male.JPG" />
...
</images>
</page>
</pages>
</query>
</api>
and reading it into a Ruby map using xmlSimple. The data which I'm really trying to get is the image names from the images section but when I attempt to go past the query level with
x= result['query']['pages']
puts x
I'm getting the following error:
in `[]': can't convert String into Integer (TypeError)
what am I doing wrong?
Thanks,
m
I used Nokogiri in the end which allows xpath notation to traverse the xml tree.
e.g.
licenseinfo = results3.xpath("//api/query/pages/page/categories/cl/#title")

Resources