FIRguy
FIRguy

Reputation: 15

XQUERY: Querying the output of query multiple times with different parameters

I have a lot of XML files and I need to output the file names based on user-defined input from the command line.

Here is a simple example of XQuery which captures the essence of the problem.

File1.xml

<?xml version="1.0" encoding="utf-8"?>
<Description>  
  <FileName>File1</FileName>
  <Persons>
    <Person>
      <Name>Anna</Name>
      <Age>25</Age>
    </Person>
    <Person>
      <Name>Marco</Name>
      <Age>25</Age>
    </Person>
    <Person>
      <Name>Mary</Name>
      <Age>13</Age>
    </Person>
  </Persons>
</Description>

File2.xml

<?xml version="1.0" encoding="utf-8"?>
<Description>
  <FileName>File2</FileName>
  <Persons>
    <Person>
      <Name>Anna</Name>
      <Age>25</Age>
    </Person>
    <Person>
      <Name>Marco</Name>
      <Age>11</Age>
    </Person>
  </Persons>
</Description>

For example, the user needs to get the name of the file which contains persons: Anna of age 25 and Marco of age 25. I wrote a dirty solution. I am wondering if it can be done in generic form for an arbitrary number of input pairs (Name, Age).

Here, the inputs are hardcoded in search.xq.

search.xq

(: person and age are user defined inputs of arbitrary length :)
let $person:= ('Anna', 'Marco')
let $age:= (25, 25)

(: Output needs to be name of file which have person (Anna, 25) and (Marco,25):)
return collection('db')/Description/Persons/Person[(Name=$person[1] and Age=$age[1])]/../Person[(Name=$person[2] and Age=$age[2])]/../../FileName

output:

<FileName>File1</FileName>

Thanks in advance.

Upvotes: 0

Views: 95

Answers (1)

Christian Gr&#252;n
Christian Gr&#252;n

Reputation: 6219

Here is a possible solution (which assumes that your XQuery processor allows you to pass on maps as user-defined input):

declare variable external $INPUT := map {
  'Anna': 25,
  'Marco': 25
};

for $description in collection('db')/Description
where every $test in map:for-each($INPUT, function($name, $age) {
  exists($description/Persons/Person[Name = $name and Age = $age])
}) satisfies $test
return $description/FileName

The second alternative is closer to your original solution. Names and ages are bound to separate variables:

declare variable $NAMES external := ('Anna', 'Marco');
declare variable $AGES external := (25, 25);

for $description in collection('db')/Description
where every $test in for-each-pair($NAMES, $AGES, function($name, $age) {
  exists($description/Persons/Person[Name = $name and Age = $age])
}) satisfies $test
return $description/FileName

Upvotes: 2

Related Questions