xquery: search across variable set of nodes
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 searc开发者_运维技巧h 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>
for your Question 1 - u could try with fn:data() to escape all user input values from Xml specific thing.
for your Question 2 - if your using any Xml database try to leverage Database Search APIs than Xpath. if not you need to come up with some defined abstract xquery search layer which can form the XPath grammer rather than following through xpath directly.
精彩评论