I have implemented a tree structure query mechanism using sql and an entity value attribute based database design.
I wanted to see the performance of the same functionality with an XQuery based approach, assuming it would be possible to use XQuery for the task.
The simplified form of my tree (XLM document) is as follows:
There are different types of nodes, but the only attribute that I'm using in the query is the archetype_node_id attribute of the node. The test query I've attempted to write aims to select the Evaluation node (on the right) with 2 element nodes. The query implementation requires two key capabilities from the language used: the ability to support structural definitions (with boolean operators), and the ability to define constraints for attributes of nodes (xml attributes in this case).
With XQuery, I have two problems 1) I can't seem to manage to declare references to all nodes of interest, that is any node I'm interested in in the graph 2) I can't figure out how to return the matches, since the matches for the right hand side of this tree would have one composition with an evaluation which in turn has two elements.
Here is my first, naive attempt using FLWR:
for $composition in doc("composition-visit.xml")//element()
let $evaluation := (
for $evalsneeded in $composition//element()
let $elementat02 :=
(for $el02 in $evalsneeded//element()
where $el02/@archetype_node_id = 'at0002'
and exists($evalsneeded//$el02)
return $el02
),
$elementat03 :=
(for $el03 in $evalsneeded//element()
where $el03/@archetype_node_id = 'at0003'
and exists($evalsneeded//$el03)
return $el03
)
where $evalsneeded/@archetype_node_id = 'openEHR-EHR-EVALUATION.goal.v1'
and
exists ($evalsneeded//$elementat02)
and
exists ($evalsneeded//$elementat03)
return $evalsneeded)
where $composition/@archetype_node_id = 'openEHR-EHR-COMPOSITION.encounter.v1'
and exists($composition//$evaluation)
return $evaluation/@archetype_node_id/string(.)
My problem is I end up pushing evaluation and element nodes to subqueries, since filtering based on their attribute values and location does not work if I introduce them as global variables in the main FLOWR body.
I am even more clueless when it comes to returning the results, but I did not want to ask a separate question for that.
Ideally, when I enforce an AND constraint for an Evaluation having elements both with at0002 and at0003 codes, I should get the right hand side of the tree, and if I use an OR constraint for the same elements, I should get the whole tree.
Is this doable with XQuery? It works as a test of the existence of the structure I'm looking for in the tree, but I also want to access individual nodes.
Update: here is my second attempt. This one actually opens the door to what I've been trying to do, but I'm not sure if this is the right way of doing this in XQuery. Should I ask another question for improving this approach? :
<result>
{
for $composition in doc("composition-visit.xml")//element()
where $composition/@archetype_node_id = 'openEHR-EHR-COMPOSITION.encounter.v1'
return <composition>
<name>{$composition/name/value/string(.)}</name>
<evaluation>{for $eval in $composition//element()
let $el1 := (for $el1_in_eval in $eval//element()
where $el1_in_eval/@archetype_node_id = 'at0002'
return $el1_in_eval ),
$el2 := (for $el2_in_eval in $eval//element()
where $el2_in_eval/@archetype_node_id = 'at0003'
return $el2_in_eval )
where $eval/@archetype_node_id = 'openEHR-EHR-EVALUATION.goal.v1'
and
(exists($el1)
and
exists($el2)
)
return <eval>
<name>{$eval/name/value/string(.)}</name>
<element1>{for $element1 in $eval//element()
where $element1/@archetype_node_id = 'at0002'
return $element1}</element1>
<element2>{for $element2 in $eval//element()
where $element2/@archetype_node_id = 'at0003'
return $element2}</element2>
</eval>
}</evaluation>
</composition>
}
</result>
Basically, I enforce the parent/child relations with let statements, and use return to get values of corresponding matches for let, which in turn may do the same down the tree.