问题
First time poster here, so please don't hesitate to let me know if I've done something wrong.
I'm using Altova Stylevision to print out form documents, and I need to print a copy of the form for each unique set of two node collections. Below is a sample XML to better explain what I'm asking for.
<form>
<Animals>
<Animal>
<AName>Boomer</AName>
<AAddress>House</AAddress>
</Animal>
<Animal>
<AName>Growl</AName>
<AAddress>Street</AAddress>
</Animal>
<Animal>
<AName>Incognito</AName>
<AAddress>Nowhere</AAddress>
</Animal>
</Animals>
<People>
<Person>
<PName>Willy</PName>
<PAddress>123 Common Lane</PAddress>
</Person>
<Person>
<PName>Wonka</PName>
<PAddress>Chocolate Factory</PAddress>
</Person>
</People>
</form>
I'd like to produce 6 unique values (the Cartesian Product) from the above sample, containing every combination of <Animal>
and <Person>
where neither of them are null. So, the output for this example would be like (just showing the grouping, need all child nodes instead of just names):
([Boomer, Willy], [Boomer, Wonka], [Growl, Willy], [Growl, Wonka], [Incognito, Willy], [Incognito, Wonka])
EDIT: I'm trying to get the nodes, not just the <Name>
element value. Because I'm wrapping the whole StyleVision form in this template, the scope should be at the <Animal>
and <Person>
level. This way, in the form I can just say /AName, /PName,
and get one value for /AName
and /PName
on each copy of the form. It should act as 6 instances of an element node, each one representing a unique combination of both <Person>
and <Animal>
.
I looked into the for # in # return
syntax but I cannot figure out how to return the unique set. Below is what I've tried so far:
for $a in form/Animals/Animal, $p in form/People/Person return ($a, $p)
and
form/Animals/Animal | form/People/Person
Can anyone point me in the right direction?
Thanks!
回答1:
Update
Your for
expression is correct, you just need to add an element constructor to get the result you need:
for $animal in $x/Animals/Animal,
$person in $x/People/Person
return element union { $animal, $person }
The element name (union
in the example) can be anything that you want.
These original code samples will generate the result strings from the question.
It's a little hard to read, but this will do what you want:
concat("(",
concat(string-join(
for $animal in /form/Animals/Animal/Name,
$person in /form/People/Person/Name
return concat("[", concat(string-join(($animal, $person), ", "), "]")), ", "), ")"))
If you can use an XPath/XQuery 3.0 processor, you can use the ||
concatenation operator instead of the concat
function calls, which is (somewhat) more readable:
"(" ||
string-join(
for $animal in /form/Animals/Animal/Name,
$person in /form/People/Person/Name
return "[" || string-join(($animal, $person), ", ") || "]"
, ", ")
|| ")"
来源:https://stackoverflow.com/questions/20687193/how-to-use-xpath-to-select-cartesian-product-set-of-non-null-sibling-nodes