XQuery/HTML Table View

Motivation

edit

When we have an XML file with uniform tabular structure, with no repeated or compound children, a generic table view is handy. We can use the XML element names as the column headers.

Sequence as HTML Table

edit

Here is a function which achieves this. It takes a sequence of elements and creates an HTML table, one row per node in the sequence. It uses a little introspection with the name() function to get the names of the children of the first node to form the column headings. For each node, the children is accessed by node name so that there is no requirement that all elements are present or in the same order as in the first node.

xquery version "1.0";

declare function local:sequence-to-table($seq) {

(: assumes all items in $seq have the same simple element structure determined by the structure of the first item :)
  <table border="1">
     <thead>
        <tr>
        {for $node in $seq[1]/*
         return <th>{name($node)}</th>
        }
        </tr>
     </thead>
      {for $row in $seq
       return
         <tr>
            {for $node in $seq[1]/*
             let $data := string($row/*[name(.)=name($node)])
             return <td>{$data}</td> 
        } 
         </tr>
      }
   </table>
 };

Example

edit

Given XML with a uniform tabular structure

the following script will create the HTML table:

xquery version "1.0";

declare option exist:serialize "method=xhtml media-type=text/html";

local:sequence-to-table ( ) {.. };

let $data := doc("furniture.xml")/*
return local:sequence-to-table($data/*)

Execute

Discussion

edit

This approach is ideal if you know that the first node in a dataset has all the elements for all the columns in the table.

This approach is used in the later Database example to display computed sequences.

The following line must be added if you are using strict XHTML. This puts all the HTML tags (<table>, <htead>, <th>, <tbody>, <tr> and <td>) in the correct namespace.

declare base-uri "http://www.w3.org/1999/xhtml";

Sequence as CSV

edit

A similar approach can be used to export the sequence as CSV.

xquery version "1.0";
declare option exist:serialize "method=text media-type=text/text";
declare variable  $sep := ',';
declare variable  $eol := '&#10;';

declare function local:sequence-to-csv($seq) as xs:string {
(: returns a  multi-line string of comma delimited strings  :)

string-join(
  (string-join($seq[1]/*/name(.),$sep),
   for $row in $seq
       return
         string-join(
          for $node in $seq[1]/*
          let $data := string($row/*[name(.)=name($node)])
          return
               if (contains($data,$sep))
               then concat('"',$data,'"')
               else $data
           , $sep)
   ),$eol )
};

let $xml := doc("furniture.xml")/*
return local:sequence-to-csv($xml/*)


Execute

Discussion

edit

To save the file directly from the browser to a named file for loading intol a spreadsheet, add  :

let $header := response:set-header("content-disposition","attachment; filename=furniture.csv")