1
votes

I have following xml:

<test>
    <TestStruktur>
        <TestReference>ID_text_random_uuid</TestReference>
        <TestReference>ID_test_random_uuid</TestReference>
        <Name>Some name</Name>
    </TestStruktur>
    <TestStruktur>
        <TestReference>ID_test_random_uuid</TestReference>
        <TestReference>ID_text_random_uuid</TestReference>
        <Name>Some name</Name>
    </TestStruktur>
</test>

I need to search for TestReference elements and check if values contain test string and then return value from the <Name> element. I've created xquery that does it but it returns two values because the statement is true for two nodes. Of course this is only a sample xml. I can have a lot of TestStruktur nodes and even more TestReference nodes

Here's my xquery:

declare function local:test($doc as node()) as xs:string {
    for $test2 in $doc//test/TestStruktur
        for $test in $test2/TestReference
        return
            if(contains($test, 'test')) then 
                data($test2/Name)
            else ()
};

for $doc in collection('Testing')
return local:test($doc)

Is there any way to, for example, break loop when if statement is true?

2

2 Answers

2
votes

You can limit the returned results to the first node:

(for $test2 in $doc//test/TestStruktur
 for $test in $test2/TestReference
 where contains($test, 'test')
 return data($test2/Name)
)[position() = 1]

This solution may look expensive at first glance, but many XQuery implementation stop looping as soon as the first result has been found.

1
votes

You just filter for the first result:

declare function local:test($doc as node()) as xs:string {
  (
    for $test2 in $doc//test/TestStruktur
        for $test in $test2/TestReference
        return
            if(contains($test, 'test')) then 
                data($test2/Name)
            else ()
  )[1]
};

The predicate might be a case for a quantifier:

declare function local:test($doc as node()) as xs:string
{
  (
    for $test2 in $doc//test/TestStruktur
    where some $test in $test2/TestReference satisfies contains($test, 'test')
    return $test2/Name
  )
  [1]
};

But it could as well be done in a single path expression:

declare function local:test($doc as node()) as xs:string
{
  ($doc//test/TestStruktur[TestReference[contains(., 'test')]]/Name)[1]
};

All of the above are equivalent. Note that the result type might better be xs:string?, to provide for the case of no 'test' being found.