xqueryexist-dbxquery-3.0

XQuery - output series of HTML elements with separator


In XQuery 3.1 I am constructing an HTML table. In one <td> element I'm outputting a series of <a ref="">.

So, currently this simple for:

 <td>
   {
     for $b in collection($globalvar:URIdata)/tei:TEI/tei:text//tei:seg[@type="dep_event" 
                           and @corresp = $a/data(@corresp)
                           and @xml:id != $a/data(@xml:id)] 

     order by $b/data(@xml:id)

     return <a href="{concat($globalvar:URLdoc,$b/ancestor::tei:TEI/tei:text/@xml:id)}">{$b/data(@xml:id)}</a>                        
    }
 </td>

Outputs this:

     <td>
      <a href="http://localhost:8081/exist/apps/deheresi/doc/MS609-0006">MS609-0006-8</a>
      <a href="http://localhost:8081/exist/apps/deheresi/doc/MS609-0419">MS609-0419-5</a>
      <a href="http://localhost:8081/exist/apps/deheresi/doc/MS609-0613">MS609-0613-4</a>
    </td>

But I'd like it to output the list of <a href=""> separated by commas:

     <td>
      <a href="http://localhost:8081/exist/apps/deheresi/doc/MS609-0006">MS609-0006-8</a>, 
      <a href="http://localhost:8081/exist/apps/deheresi/doc/MS609-0419">MS609-0419-5</a>, 
      <a href="http://localhost:8081/exist/apps/deheresi/doc/MS609-0613">MS609-0613-4</a>
    </td>

EDIT: below works...but does not output the results in desired order and I cannot get order by $b/data(@xml:id) to work with it due to an "cardinality" problem (that did not pop up in the original).

    let $coll := collection($globalvar:URIdata)/tei:TEI/tei:text//tei:seg[@type="dep_event" 
                     and @corresp = $a/data(@corresp)
                     and @xml:id != $a/data(@xml:id)] 

     let $last := count($coll)

     for $b at $position in $coll 

     return (<a href="{concat($globalvar:URLdoc,$b/ancestor::tei:TEI/tei:text/@xml:id)}">{$b/data(@xml:id)}</a>,
           if ($position ne $last) then ', ' else '')

Many thanks in advance for any advice.


Solution

  • I am not sure whether there is a common idiom in XQuery to do that but I think using

     for $b in collection($globalvar:URIdata)/tei:TEI/tei:text//tei:seg[@type="dep_event" 
                           and @corresp = $a/data(@corresp)
                           and @xml:id != $a/data(@xml:id)] 
    
     order by $b/data(@xml:id)
     count $p
     let $a := <a href="{concat($globalvar:URLdoc,$b/ancestor::tei:TEI/tei:text/@xml:id)}">{$b/data(@xml:id)}</a>
     return 
       if ($p > 1)
       then (',', $a)
       else $a
    

    is a possible way, much aline the old XSLT approach to have <xsl:for-each select="$nodes"><xsl:if test="position() > 1">,</xsl:if><xsl:copy-of select="."/></xsl:for-each>. Closer to that you could also try

     (
     for $b in collection($globalvar:URIdata)/tei:TEI/tei:text//tei:seg[@type="dep_event" 
                           and @corresp = $a/data(@corresp)
                           and @xml:id != $a/data(@xml:id)] 
    
     order by $b/data(@xml:id)
    
     return <a href="{concat($globalvar:URLdoc,$b/ancestor::tei:TEI/tei:text/@xml:id)}">{$b/data(@xml:id)}</a>
     ) ! (if (position() > 1) then (',', .) else .)  
    

    That could also be written as

     (
     for $b in collection($globalvar:URIdata)/tei:TEI/tei:text//tei:seg[@type="dep_event" 
                           and @corresp = $a/data(@corresp)
                           and @xml:id != $a/data(@xml:id)] 
    
     order by $b/data(@xml:id)
    
     return <a href="{concat($globalvar:URLdoc,$b/ancestor::tei:TEI/tei:text/@xml:id)}">{$b/data(@xml:id)}</a>
     ) ! (if (position() > 1) then ',' else (), .) 
    

    a bit closer to your second attempt.