see [1] for the full set of executable scripts and timing comparisons.

Here's an XQuery solution to the FizzBuzz problem posed in David Patterson's blog.. who wrote an XSLT solution.

Chris Wallace wrote this solution to David's configurable version of the problem:

let $config :=
<fizzbuzz>
<range min="1" max="100"/>
<test>
   <mod value="3" test="0">Fizz</mod>
   <mod value="5" test="0">Buzz</mod>
</test>
</fizzbuzz>

return 
 string-join(
   for $i in ($config/range/@min to $config/range/@max)
   let $s :=  
       for $mod in $config/test/mod
       return
         if ($i mod $mod/@value = $mod/@test)
         then string($mod)
         else ()
   return
     if (exists($s))
     then string-join($s,' ')
     else string($i),
   "
"
 )

Execute

The parameterisation of the algorithm was in the original problem as proposed by David Patterson. Simpler solutions are possible if the parameters are fixed.

Here is a solution from Jim Fuller:

for $n in (1 to 100)
let $fizz := if ($n mod 3) then () else "fizz"
let $buzz := if ($n mod 5) then () else "buzz"
return
  if ($fizz or $buzz) then concat($fizz,$buzz) else $n

Execute

Here is a short and simple solution by Dimitre Novatchev -- note that there isn't any explicit if ... then ... else. (Also, this can be shortened to 3 lines if the $fizz and $buzz variables are eliminated):

for $n in (1 to 100),
    $fizz in not($n mod 3),
    $buzz in not($n mod 5)
 return  
    concat("fizz"[$fizz], "buzz"[$buzz], $n[not($fizz or $buzz)]) 

Execute

One may notice that the above solution doesn't use any XQuery features that aren't also in XPath -- therefore this is a pure XPath 2.0 solution.

Another solution by Dimitre, which might be faster as it doesn't use any mod operator at all:

      for $k in 1 to 100 idiv 15 +1,
          $start in 15*($k -1) +1,
          $end in min((100, $start + 14))
          return
            let $results :=
                      ($start, $start+1,
                      'fizz',
                      $start+3,
                      'buzz', 'fizz',
                      $start+6, $start+7, 
                      'fizz',
                      'buzz',
                      $start+10,
                      'fizz',
                      $start+12, $start+13,
                      'fizzbuzz')
               return
                      subsequence($results, 1, $end -$start +1)

Execute

Again, the above solution doesn't use any XQuery features that aren't also in XPath 3.0 -- therefore this is a pure XPath 3.0 solution.


Here is a solution from Dino Fancellu, pure XPath 3.0:

(1 to 30)!(if (. mod 15=0) then "fizzbuzz" else if (. mod 3 = 0) then "fizz" else if (. mod 5 = 0) then "buzz" else .)

Here is a solution by Benito van der Zander, pure XPath 3.0 without if:


for $i in 1 to 100 return (("fizz"[$i mod 3=0] || "buzz"[$i mod 5=0])[.],$i)[1]