I am using BaseX XML Database. Consider an xml document in the database like so:
<entries>
<book-entry>
<book>Book 1</book>
<author>Author 1 ABC</author>
<title>Title 1</title>
</book-entry>
<car-entry>
<car>Car 1</car>
<model>Model 1</model>
<price>Price 1 ABC</price>
</car-entry>
</entries>
I am trying to perform a search with different options such as : search across books only, cars only, both books and cars.
I am trying to use an xml variable in my xquery to return search results based on the required search type.
Example variable values:
- <types><type>book-entry</type></types>
: search across book-entries only
- <types><type>car-entry</type></types>
: search across car-entries only
- <types><type>book-entry</type><type>car-entry</type></types>
: search across book-entries and car-entries
XQuery Sample:
declare variable $doc_name as xs:string external; (: name of xml document :)
declare variable $search_types as xs:anyAtomicType external; (: one of the example variable values shown above :)
declare variable $search_key as xs:string external; (: eg: ABC :)
for $entry in doc($doc_name)/entries[*[exists($search_types/types/type/text() = node-name(.)) and .//text() contains text $search_key]]
return $entry
The above query returns both car and book entries which contain a text child node ABC although I pass <types><type>car-entry</type></types>
to $search_types.
How do I restrict the search using an xml variable ? Is there a better way of doing this? Also, the xquery must return both cars and entries if the xml variable has child nodes of both the types.
Thanks, Sony
for $entry in doc($doc_name)/entries [*[exists($search_types/types/type/text() = node-name(.)) and .//text() contains text $search_key ] ] return $entry
Must be:
for $entry in doc($doc_name)/entries/*
[exists($search_types/types/type/text() = node-name(.))
and
.//text() contains text $search_key]
return $entry
Or, alternatively, this simple XPath expression may be used:
/*/*[name() eq $vSearchTypes/types/type
and
.//text()[contains(., $vSearchKey)]
]
Finally, this XQuery expression:
let $vSearchTypes :=
<types>
<type>book-entry</type>
</types>,
$vSearchKey := 'ABC'
return
/*/*[name(.) eq $vSearchTypes/type
and
.//text()[contains(., $vSearchKey)]
]
when applied on the provided XML document:
<entries>
<book-entry>
<book>Book 1</book>
<author>Author 1 ABC</author>
<title>Title 1</title>
</book-entry>
<car-entry>
<car>Car 1</car>
<model>Model 1</model>
<price>Price 1 ABC</price>
</car-entry>
</entries>
produces the wanted, correct result:
<book-entry>
<book>Book 1</book>
<author>Author 1 ABC</author>
<title>Title 1</title>
</book-entry>