XQuery/HTML Table View

MotivationEdit

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 XHTML TableEdit

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.

declare base-uri "http://www.w3.org/1999/xhtml";
 
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>
 };

This could then be used to view selected nodes:

   local:sequence-to-table(//Emp)

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";

Execute

Sequence as CSVEdit

A similar approach can be used to export the sequence as CSV. Here the header Content-Disposition is set so the Browser will allow the generated file to be opened directly in Excel.

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 $x := response:set-header('Content-Disposition','inline;filename=empdept.csv') 
return local:sequence-to-csv(//Emp)

Execute

Last modified on 26 September 2009, at 18:17