Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 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

like image 885
sony Avatar asked Nov 30 '25 14:11

sony


1 Answers

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>
like image 178
Dimitre Novatchev Avatar answered Dec 03 '25 08:12

Dimitre Novatchev



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!