How to use XPath to select Cartesian Product set of non null sibling nodes?

懵懂的女人 提交于 2019-12-10 23:29:21

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!