<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class="">Start with a function that gets the children of an item:<div class=""><br class=""></div><div class="">declare variable $children := function($item) {return $xml / item[@refid = $item / @id ]};</div><div class=""><br class=""></div><div class="">Decide where to start:</div><div class=""><br class=""></div><div class="">declare variable $root := $xml / item[1];</div><div class=""><br class=""></div><div class="">Now process the items recursively:</div><div class=""><br class=""></div><div class="">declare function local:process-item($item, $get-children) {</div><div class="">  <section> {</div><div class="">     $item / (@*,  $get-children($item) / process-item(.))</div><div class="">  }</section></div><div class="">};</div><div class=""><br class=""></div><div class="">and put it together like this:</div><div class=""><br class=""></div><div class="">local:process-item($root, $children);</div><div class=""><br class=""></div><div class="">I've deliberately written it this way using XQuery 3.1 higher-order functions to keep the recursion logic separate from the details of how you find the logical children of an item. But in XQuery 1.0 the same logic would work using a fixed function instead of a dynamic one.</div><div class=""><br class=""></div><div class="">A version that detects cycles in the data is a little bit trickier, but still quite doable.</div><div class=""><br class=""></div><div class="">Michael Kay</div><div class="">Saxonica<br class=""><div><br class=""><blockquote type="cite" class=""><div class="">On 21 Dec 2019, at 18:14, Andreas Mixich <<a href="mailto:mixich.andreas@gmail.com" class="">mixich.andreas@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class="">Hi,<div class=""><br class=""></div><div class="">I feel like I try to get a hold on a piece of wet soap with this...</div><div class=""><br class=""></div><div class="">Background: Atom Syndication has an extension[1], which allows threading of entries. These entries are ordered in a flat sequence, one by one.</div><div class="">As a result we end up with an Atom feed, that has a bunch of entries, where each entry could have a reference to the ID of another entry, which would then be it's parent.</div><div class="">No nesting is done.</div><div class=""><br class=""></div><div class="">A simplified input could look like this:</div><div class=""><br class=""></div><div class=""><font face="monospace" class="">declare variable $local:example :=  </font></div><div class=""><font face="monospace" class="">let $xml := <xml><br class="">  <item id="e1" /><br class="">  <item id="e2" refid="e1" /><br class="">  <item id="e3" refid="e2" /><br class="">  <item id="e4" refid="e2" /><br class="">  <item id="e5" refid="e4" /></font></div><div class=""><font face="monospace" class="">  <item id="e6" /><br class=""></xml><br class=""></font><div class=""><br class=""></div><div class="">The task I want to accomplish is to create an output <i class="">tree</i> of <i class="">nested</i> sections, resembling the natural flow of replies:</div><div class=""><br class=""></div><div class=""><font face="monospace" class=""><result><br class="">  <section id="e1"></font></div><div class=""><font face="monospace" class="">    <section id="e2" refid="e1"></font></div><div class=""><font face="monospace" class="">      <section id="e3" refid="e2" /></font></div><div class=""><font face="monospace" class="">      <section id="e4" refid="e2"></font></div><div class=""><font face="monospace" class="">        <section id="e5" refid="e4" /></font></div><div class=""><font face="monospace" class="">      </section></font></div><div class=""><font face="monospace" class="">    </section></font></div><div class=""><font face="monospace" class="">  </section></font></div><div class=""><font face="monospace" class="">  <section id="e6" /></font></div><div class=""><font face="monospace" class=""></result></font><br class=""></div><div class=""><br class=""></div><div class="">One of the many queries I tried is:</div><div class=""><br class=""></div><div class=""><font face="monospace" class="">declare function local:rec($data) {<br class="">  if (empty($data))<br class="">  then ()<br class="">  else (<br class="">         let $current := head($data)<br class="">         let $children := tail($data)[@refid = $current/@id]<br class="">         return (<br class="">                  <section id="{$current/@id}"><br class="">                  { <br class="">                    $current/*<br class="">(:                  , prof:dump("current: " || $current/@id/data() || " children: " || $children/@id/data() => string-join())</font></div><div class=""><font face="monospace" class="">:)<br class="">                  , for $child in $children<br class="">                    return local:rec($children)<br class="">                  }<br class="">                  </section><br class="">                  , local:rec(tail($data))<br class="">                )<br class="">       )<br class="">};<br class=""><br class=""></font></div><div class=""><font face="monospace" class=""><result> </font></div><div class=""><span style="font-family:monospace" class="">  { local:rec($local:example/</span><span style="font-family:monospace" class="">item) } </span></div><div class=""><span style="font-family:monospace" class=""></result></span></div><div class=""><br class=""></div><div class="">Of course, this has not yet any logic, to keep out the already processed items (besides other issues). </div><div class="">When I tried that, however, by removing them from the return sequence, I found no way to break out </div><div class="">of scope and have that modified return sequence go back to the next recursion.</div><div class=""><br class=""></div><div class="">Previous example results in this, btw.:</div><div class=""><br class=""></div><div class=""><font face="monospace" class=""><section id="e1"><br class="">  <section id="e2"/><br class=""></section><br class=""><section id="e2"><br class="">  <section id="e3"/><br class="">  <section id="e4"/><br class="">  <section id="e3"/><br class="">  <section id="e4"/><br class=""></section><br class=""><section id="e3"/><br class=""><section id="e4"><br class="">  <section id="e5"/><br class=""></section><br class=""><section id="e5"/><br class=""><section id="e6"/></font><br class=""></div><div class=""><font face="monospace" class=""><br class=""></font></div><div class=""><font face="arial, sans-serif" class="">I can't believe, that there is no super easy way to do it. Any help would be greatly appreciated!</font></div><div class=""><br class=""></div>-- <br class=""><div dir="ltr" data-smartmail="gmail_signature" class="">Minden jót, all the best, Alles Gute,<br class="">Andreas Mixich</div></div></div>
_______________________________________________<br class=""><a href="mailto:talk@x-query.com" class="">talk@x-query.com</a><br class="">http://x-query.com/mailman/listinfo/talk</div></blockquote></div><br class=""></div></body></html>