XQuery - output series of HTML elements with separ

2019-08-08 19:05发布

问题:

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.

回答1:

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.