Reputation: 15
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
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