xQuery: test for two specific children with 'and'

advertisements

Assume I have the following snippet

<persName>
    <forename>Gaius</forename>
    <surname>Iulius</surname>
    <addName>Caesar</addName>
</persName>

I need a result like [surname], [forename] where the comma should only be present if necessary.

In XSLT, I'd simply use

<xsl:value-of select="surname" />
<xsl:if test="surname and forename"><xsl:text>, </xsl:text></xsl:if>
<xsl:value-of select="forename" />

Now I naively thought I could transfer this to XQuery – and failed. I was slightly puzzled that

if ($node/forename) then "1" else "0"
if ($node/surname) then "1" else "0"
if ($node/surname and $node/forename) then "1" else "0"

will give 1, 1, 0, respectively. I worked around this by counting the number of children in one of these cases but I'm still puzzled why this is the way it is.

Tanks for any input!


Edit: here's the code I've been using:

declare function habe:shortName($node) {
    <span>{
        if ($node/tei:name) then $node/tei:name
        else
            let $tr := if ($node/tei:surname and count($node/tei:forename)>0) then ", " else ""
            return concat($node/tei:surname, $tr, $node/tei:forename)
    }</span>
};

which, when given the above snippet, returned IuliusGaius.

I then tried the three tests above and got the stated result.

I'm doing this on eXist – maybe their implementation is faulty?


Edit: Thanks to @MichaelKay and @joewiz for hinting at misleading typos!


One solution to your original problem (adding a ', ' if both forename and surname exist) is to use string-join($strs as xs:string*, $joiner as xs:string) instead of concat($string as xs:string[...]):

let $name :=
    <persName>
        <forename>Gaius</forename>
        <surname>Iulius</surname>
        <addName>Caesar</addName>
    </persName>
return string-join(($name/surname, $name/forename), ', ')

This returns Iulius, Gaius.

You can also check for presence of nodes directly in boolean expressions:

let $name :=
    <persName>
        <forename>Gaius</forename>
        <surname>Iulius</surname>
        <addName>Caesar</addName>
    </persName>
return (
  $name/surname and $name/forename,
  $name/surname and $name/foo
)

This returns true false.