]
>
  
    Installation
    
  
  hello mum");
  doc.close();
}
// find current slide based upon location
// first find target anchor and then look
// for associated div element enclosing it
// finally map that to slide number
function findSlideNumber(uri)
{
   // first get anchor from page location
   var i = uri.indexOf("#");
   // check if anchor is entire page
   if (i < 0)
      return 0;  // yes
   var anchor = unescape(uri.substr(i+1));
   // now use anchor as XML ID to find target
   var target = document.getElementById(anchor);
   if (!target)
   {
      // does anchor look like "(2)" for slide 2 ??
      // where first slide is (1)
      var re = /\((\d)+\)/;
      if (anchor.match(re))
      {
         var num = parseInt(anchor.substring(1, anchor.length-1));
         if (num > slides.length)
            num = 1;
         if (--num < 0)
            num = 0;
         return num;
      }
      // accept [2] for backwards compatibility
      re = /\[(\d)+\]/;
      if (anchor.match(re))
      {
         var num = parseInt(anchor.substring(1, anchor.length-1));
         if (num > slides.length)
            num = 1;
         if (--num < 0)
            num = 0;
         return num;
      }
      // oh dear unknown anchor
      return 0;
   }
   // search for enclosing slide
   while (true)
   {
      // browser coerces html elements to uppercase!
      if (target.nodeName.toLowerCase() == "div" &&
            hasClass(target, "slide"))
      {
         // found the slide element
         break;
      }
      // otherwise try parent element if any
      target = target.parentNode;
      if (!target)
      {
         return 0;   // no luck!
      }
   };
   for (i = 0; i < slides.length; ++i)
   {
      if (slides[i] == target)
         return i;  // success
   }
   // oh dear still no luck
   return 0;
}
// find slide name from first h1 element
// default to document title + slide number
function slideName(index)
{
   var name = null;
   var slide = slides[index];
   var heading = findHeading(slide);
   if (heading)
     name = extractText(heading);
   if (!name)
     name = title + "(" + (index + 1) + ")";
   name.replace(/\&/g, "&");
   name.replace(/\/g, ">");
   return name;
}
// find first h1 element in DOM tree
function findHeading(node)
{  if (!node || node.nodeType != 1)
    return null;
  if (node.nodeName == "H1" || node.nodeName == "h1")
    return node;
  var child = node.firstChild;
  while (child)
  {
    node = findHeading(child);
    if (node)
      return node;
    child = child.nextSibling;
  }
  return null;
}
// recursively extract text from DOM tree
function extractText(node)
{
  if (!node)
    return "";
  // text nodes
  if (node.nodeType == 3)
    return node.nodeValue;
  // elements
  if (node.nodeType == 1)
  {
    node = node.firstChild;
    var text = "";
    while (node)
    {
      text = text + extractText(node);
      node = node.nextSibling;
    }
    return text;
  }
  return "";
}
// find copyright text from meta element
function findCopyright()
{
   var name, content;
   var meta = document.getElementsByTagName("meta");
   for (var i = 0; i < meta.length; ++i)
   {
      name = meta[i].getAttribute("name");
      content = meta[i].getAttribute("content");
      if (name == "copyright")
         return content;
   }
   return null;
}
function findSizeAdjust()
{
   var name, content, offset;
   var meta = document.getElementsByTagName("meta");
   for (var i = 0; i < meta.length; ++i)
   {
      name = meta[i].getAttribute("name");
      content = meta[i].getAttribute("content");
      if (name == "font-size-adjustment")
         return 1 * content;
   }
   return 1;
}
function addToolbar()
{
   var slideCounter, page;
   var toolbar = createElement("div");
   toolbar.setAttribute("class", "toolbar");
   if (ns_pos) // a reasonably behaved browser
   {
      var right = document.createElement("div");
      right.setAttribute("style", "float: right; text-align: right");
      slideCounter = document.createElement("div")
      slideCounter.innerHTML = "slide".localize() + " n/m";
      right.appendChild(slideCounter);
      toolbar.appendChild(right);
      var left = document.createElement("div");
      left.setAttribute("style", "text-align: left");
      // global end of slide indicator
      eos = document.createElement("span");
      eos.innerHTML = "* ";
      left.appendChild(eos);
      var help = document.createElement("a");
      help.setAttribute("href", helpPage);
      help.setAttribute("title", helpText.localize());
      help.innerHTML = "   ".localize();
      left.appendChild(help);
      helpAnchor = help;  // save for focus hack
      var gap1 = document.createTextNode(" ");
      left.appendChild(gap1);
      var contents = document.createElement("a");
      contents.setAttribute("href", "javascript:toggleTableOfContents()");
      contents.setAttribute("title", "table of contents".localize());
      contents.innerHTML = "Table of Contents ".localize();
      left.appendChild(contents);
      var gap2 = document.createTextNode("..............................................");
      left.appendChild(gap2);
      var start = document.createElement("a");
      start.setAttribute("href", "javascript:firstSlide()");
      start.setAttribute("title", "restart presentation".localize());
         start.innerHTML = " ".localize();
//    start.setAttribute("href", "javascript:printSlides()");
//    start.setAttribute("title", "print all slides".localize());
//    start.innerHTML = "print!".localize();
      left.appendChild(start);
      //      var identity = document.createTextNode("");
      //      left.appendChild(identity);
      var copyright = findCopyright();
      if (copyright)
      {
         var span = document.createElement("span");
         span.innerHTML = copyright;
         span.style.color = "black";
         span.style.marginLeft = "4em";
         left.appendChild(span);
      }
      toolbar.appendChild(left);
   }
   else // IE so need to work around its poor CSS support
   {
      toolbar.style.position = (ie7 ? "fixed" : "absolute");
      toolbar.style.zIndex = "200";
      toolbar.style.width = "99.9%";
      toolbar.style.height = "1.2em";
      toolbar.style.top = "auto";
      toolbar.style.bottom = "0";
      toolbar.style.left = "0";
      toolbar.style.right = "0";
      toolbar.style.textAlign = "left";
      toolbar.style.fontSize = "60%";
      toolbar.style.color = "red";
      toolbar.borderWidth = 0;
      toolbar.style.background = "rgb(240,240,240)";
      // would like to have help text left aligned
      // and page counter right aligned, floating
      // div's don't work, so instead use nested
      // absolutely positioned div's.
      var sp = document.createElement("span");
      sp.innerHTML = "  * ";
      toolbar.appendChild(sp);
      eos = sp;  // end of slide indicator
      var help = document.createElement("a");
      help.setAttribute("href", helpPage);
      help.setAttribute("title", helpText.localize());
      help.innerHTML = "help?".localize();
      toolbar.appendChild(help);
      helpAnchor = help;  // save for focus hack
      var gap1 = document.createTextNode(" ");
      toolbar.appendChild(gap1);
      var contents = document.createElement("a");
      contents.setAttribute("href", "javascript:toggleTableOfContents()");
      contents.setAttribute("title", "table of contents".localize());
      contents.innerHTML = "contents?".localize();
      toolbar.appendChild(contents);
      var gap2 = document.createTextNode(" ");
      toolbar.appendChild(gap2);
      var start = document.createElement("a");
      start.setAttribute("href", "javascript:firstSlide()");
      start.setAttribute("title", "restart presentation".localize());
      start.innerHTML = "restart?".localize();
//    start.setAttribute("href", "javascript:printSlides()");
//    start.setAttribute("title", "print all slides".localize());
//    start.innerHTML = "print!".localize();
      toolbar.appendChild(start);
      var copyright = findCopyright();
      if (copyright)
      {
         var span = document.createElement("span");
         span.innerHTML = copyright;
         span.style.color = "black";
         span.style.marginLeft = "2em";
         toolbar.appendChild(span);
      }
      slideCounter = document.createElement("div")
      slideCounter.style.position = "absolute";
      slideCounter.style.width = "auto"; //"20%";
      slideCounter.style.height = "1.2em";
      slideCounter.style.top = "auto";
      slideCounter.style.bottom = 0;
      slideCounter.style.right = "0";
      slideCounter.style.textAlign = "right";
      slideCounter.style.color = "red";
      slideCounter.style.background = "rgb(240,240,240)";
      slideCounter.innerHTML = "slide".localize() + " n/m";
      toolbar.appendChild(slideCounter);
   }
   // ensure that click isn't passed through to the page
   toolbar.onclick = stopPropagation;
   document.body.appendChild(toolbar);
   slideNumElement = slideCounter;
   setEosStatus(false);
   return toolbar;
}
function isShownToc()
{
  if (toc && toc.style.visible == "visible")
    return true;
  return false;
}
function showTableOfContents()
{
  if (toc)
  {
    if (toc.style.visibility != "visible")
    {
      toc.style.visibility = "visible";
      toc.style.display = "block";
      toc.focus();
      if (ie7 && slidenum == 0)
        setTimeout("ieHack()", 100);
    }
    else
      hideTableOfContents();
  }
}
function hideTableOfContents()
{
  if (toc && toc.style.visibility != "hidden")
  {
    toc.style.visibility = "hidden";
    toc.style.display = "none";
    try
    {
       if (!opera)
         helpAnchor.focus();
    }
    catch (e)
    {
    }
  }
}
function toggleTableOfContents()
{
  if (toc)
  {
     if (toc.style.visible != "visible")
       showTableOfContents();
     else
       hideTableOfContents();
  }
}
// called on clicking toc entry
function gotoEntry(e)
{
   var target;
   if (!e)
      var e = window.event;
   if (e.target)
      target = e.target;
   else if (e.srcElement)
      target = e.srcElement;
   // work around Safari bug
   if (target.nodeType == 3)
      target = target.parentNode;
   if (target && target.nodeType == 1)
   {
     var uri = target.getAttribute("href");
     if (uri)
     {
        //alert("going to " + uri);
        var slide = slides[slidenum];
        hideSlide(slide);
        slidenum = findSlideNumber(uri);
        slide = slides[slidenum];
        lastShown = null;
        setLocation();
        setVisibilityAllIncremental("hidden");
        setEosStatus(!nextIncrementalItem(lastShown));
        showSlide(slide);
        //target.focus();
        try
        {
           if (!opera)
             helpAnchor.focus();
        }
        catch (e)
        {
        }
     }
   }
   hideTableOfContents(e);
   if (ie7) ieHack();
   stopPropagation(e);
   return cancel(e);
}
// called onkeydown for toc entry
function gotoTocEntry(event)
{
  var key;
  if (!event)
    var event = window.event;
  // kludge around NS/IE differences 
  if (window.event)
    key = window.event.keyCode;
  else if (event.which)
    key = event.which;
  else
    return true; // Yikes! unknown browser
  // ignore event if key value is zero
  // as for alt on Opera and Konqueror
  if (!key)
     return true;
  // check for concurrent control/command/alt key
  // but are these only present on mouse events?
  if (event.ctrlKey || event.altKey)
     return true;
  if (key == 13)
  {
    var uri = this.getAttribute("href");
    if (uri)
    {
      //alert("going to " + uri);
      var slide = slides[slidenum];
      hideSlide(slide);
      slidenum = findSlideNumber(uri);
      slide = slides[slidenum];
      lastShown = null;
      setLocation();
      setVisibilityAllIncremental("hidden");
      setEosStatus(!nextIncrementalItem(lastShown));
      showSlide(slide);
      //target.focus();
      try
      {
         if (!opera)
           helpAnchor.focus();
      }
      catch (e)
      {
      }
    }
    hideTableOfContents();
    if (ie7) ieHack();
    return cancel(event);
  }
  if (key == 40 && this.next)
  {
    this.next.focus();
    return cancel(event);
  }
  if (key == 38 && this.previous)
  {
    this.previous.focus();
    return cancel(event);
  }
  return true;
}
function isTitleSlide(slide)
{
   return hasClass(slide, "title");
}
// create div element with links to each slide
function tableOfContents()
{
  var toc = document.createElement("div");
  addClass(toc, "toc");
  //toc.setAttribute("tabindex", "0");
  var heading = document.createElement("div");
  addClass(heading, "toc-heading");
  heading.innerHTML = "Table of Contents".localize();
  heading.style.textAlign = "center";
  heading.style.width = "100%";
  heading.style.margin = "0";
  heading.style.marginBottom = "1em";
  heading.style.borderBottomStyle = "solid";
  heading.style.borderBottomColor = "rgb(180,180,180)";
  heading.style.borderBottomWidth = "1px";
  toc.appendChild(heading);
  var previous = null;
  for (var i = 0; i < slides.length; ++i)
  {
    var title = hasClass(slides[i], "title");
    var num = document.createTextNode((i + 1) + ". ");
    toc.appendChild(num);
    var a = document.createElement("a");
    a.setAttribute("href", "#(" + (i+1) + ")");
    if (title)
      addClass(a, "titleslide");
    var name = document.createTextNode(slideName(i));
    a.appendChild(name);
    a.onclick = gotoEntry;
    a.onkeydown = gotoTocEntry;
    a.previous = previous;
    if (previous)
      previous.next = a;
    toc.appendChild(a);
    if (i == 0)
      toc.first = a;
    if (i < slides.length - 1)
    {
      var br = document.createElement("br");
      toc.appendChild(br);
    }
    previous = a;
  }
  toc.focus = function () {
    if (this.first)
      this.first.focus();
  }
  toc.onmouseup = mouseButtonUp;
  toc.onclick = function (e) {
    e||(e=window.event);
    if (selectedTextLen <= 0)
       hideTableOfContents();
    stopPropagation(e);
    
    if (e.cancel != undefined)
      e.cancel = true;
      
    if (e.returnValue != undefined)
      e.returnValue = false;
      
    return false;
  };
  toc.style.position = "absolute";
  toc.style.zIndex = "300";
  toc.style.width = "60%";
  toc.style.maxWidth = "30em";
  toc.style.height = "30em";
  toc.style.overflow = "auto";
  toc.style.top = "auto";
  toc.style.right = "auto";
  toc.style.left = "4em";
  toc.style.bottom = "4em";
  toc.style.padding = "1em";
  toc.style.background = "rgb(240,240,240)";
  toc.style.borderStyle = "solid";
  toc.style.borderWidth = "2px";
  toc.style.fontSize = "60%";
  document.body.insertBefore(toc, document.body.firstChild);
  return toc;
}
function replaceByNonBreakingSpace(str)
{
   for (var i = 0; i < str.length; ++i)
      str[i] = 160;
}
function initOutliner()
{
  var items = document.getElementsByTagName("LI");
  for (var i = 0; i < items.length; ++i)
  {
     var target = items[i];
     if (!hasClass(target.parentNode, "outline"))
        continue;
     target.onclick = outlineClick;
     if (!ns_pos)
     {
        target.onmouseover = hoverOutline;
        target.onmouseout = unhoverOutline;
     }
     if (foldable(target))
     {
       target.foldable = true;
       target.onfocus = function () {outline = this;};
       target.onblur = function () {outline = null;};
       if (!target.getAttribute("tabindex"))
         target.setAttribute("tabindex", "0");
       if (hasClass(target, "expand"))
         unfold(target);
       else
         fold(target);
     }
     else
     {
       addClass(target, "nofold");
       target.visible = true;
       target.foldable = false;
     }
  }
}
function foldable(item)
{
   if (!item || item.nodeType != 1)
      return false;
   var node = item.firstChild;
   while (node)
   {
     if (node.nodeType == 1 && isBlock(node))
       return true;
      node = node.nextSibling;
   }
   return false;
}
function fold(item)
{
  if (item)
  {
    removeClass(item, "unfolded");
    addClass(item, "folded");
  }
  var node = item ? item.firstChild : null;
  while (node)
  {
    if (node.nodeType == 1 && isBlock(node)) // element
    {
      // note that getElementStyle won't work for Safari 1.3
      node.display = getElementStyle(node, "display", "display");
      node.style.display = "none";
      node.style.visibility = "hidden";
    }
    node = node.nextSibling;
  }
  item.visible = false;
}
function unfold(item)
{
   if (item)
   {
     addClass(item, "unfolded");
     removeClass(item, "folded");
   }
  var node = item ? item.firstChild : null;
  while (node)
  {
    if (node.nodeType == 1 && isBlock(node)) // element
    {
      // with fallback for Safari, see above
      node.style.display = (node.display ? node.display : "block");
      node.style.visibility = "visible";
    }
    node = node.nextSibling;
  }
  item.visible = true;
}
function outlineClick(e)
{
   var rightclick = false;
   var target;
   if (!e)
      var e = window.event;
   if (e.target)
      target = e.target;
   else if (e.srcElement)
      target = e.srcElement;
   // work around Safari bug
   if (target.nodeType == 3)
      target = target.parentNode;
   while (target && target.visible == undefined)
      target = target.parentNode;
   if (!target)
      return true;
   if (e.which)
      rightclick = (e.which == 3);
   else if (e.button)
      rightclick = (e.button == 2);
   if (!rightclick && target.visible != undefined)
   {
      if (target.foldable)
      {
         if (target.visible)
           fold(target);
         else
           unfold(target);
      }
      stopPropagation(e);
      e.cancel = true;
      e.returnValue = false;
   }
   return false;
}
function hoverOutline(e)
{
   var target;
   if (!e)
      var e = window.event;
   if (e.target)
      target = e.target;
   else if (e.srcElement)
      target = e.srcElement;
   // work around Safari bug
   if (target.nodeType == 3)
      target = target.parentNode;
   while (target && target.visible == undefined)
      target = target.parentNode;
   if (target && target.foldable)
      target.style.cursor = "pointer";
   return true;
}
function unhoverOutline(e)
{
   var target;
   if (!e)
      var e = window.event;
   if (e.target)
      target = e.target;
   else if (e.srcElement)
      target = e.srcElement;
   // work around Safari bug
   if (target.nodeType == 3)
      target = target.parentNode;
   while (target && target.visible == undefined)
      target = target.parentNode;
   if (target)
     target.style.cursor = "default";
   return true;
}
function stopPropagation(e)
{
   if (window.event)
   {
      window.event.cancelBubble = true;
      //window.event.returnValue = false;
   }
   else if (e)
   {
      e.cancelBubble = true;
      e.stopPropagation();
      //e.preventDefault();
   }
}
/* can't rely on display since we set that to none to hide things */
function isBlock(elem)
{
   var tag = elem.nodeName;
   return tag == "OL" || tag == "UL" || tag == "P" ||
          tag == "LI" || tag == "TABLE" || tag == "PRE" ||
          tag == "H1" || tag == "H2" || tag == "H3" ||
          tag == "H4" || tag == "H5" || tag == "H6" ||
          tag == "BLOCKQUOTE" || tag == "ADDRESS"; 
}
function getElementStyle(elem, IEStyleProp, CSSStyleProp)
{
   if (elem.currentStyle)
   {
      return elem.currentStyle[IEStyleProp];
   }
   else if (window.getComputedStyle)
   {
      var compStyle = window.getComputedStyle(elem, "");
      return compStyle.getPropertyValue(CSSStyleProp);
   }
   return "";
}
// works with text/html and text/xhtml+xml with thanks to Simon Willison
function createElement(element)
{
   if (typeof document.createElementNS != 'undefined')
   {
      return document.createElementNS('http://www.w3.org/1999/xhtml', element);
   }
   if (typeof document.createElement != 'undefined')
   {
      return document.createElement(element);
   }
   return false;
}
// designed to work with both text/html and text/xhtml+xml
function getElementsByTagName(name)
{
   if (typeof document.getElementsByTagNameNS != 'undefined')
   {
      return document.getElementsByTagNameNS('http://www.w3.org/1999/xhtml', name);
   }
   if (typeof document.getElementsByTagName != 'undefined')
   {
      return document.getElementsByTagName(name);
   }
   return null;
}
/*
// clean alternative to innerHTML method, but on IE6
// it doesn't work with named entities like  
// which need to be replaced by numeric entities
function insertText(element, text)
{
   try
   {
     element.textContent = text;  // DOM3 only
   }
   catch (e)
   {
      if (element.firstChild)
      {
         // remove current children
         while (element.firstChild)
            element.removeChild(element.firstChild);
      }
      element.appendChild(document.createTextNode(text));
   }
}
// as above, but as method of all element nodes
// doesn't work in IE6 which doesn't allow you to
// add methods to the HTMLElement prototype
if (HTMLElement != undefined)
{
  HTMLElement.prototype.insertText = function(text) {
    var element = this;
    try
    {
      element.textContent = text;  // DOM3 only
    }
    catch (e)
    {
      if (element.firstChild)
      {
         // remove current children
         while (element.firstChild)
           element.removeChild(element.firstChild);
      }
      element.appendChild(document.createTextNode(text));
    }
  };
}
*/
function getSelectedText()
{
  try
  {
    if (window.getSelection)
      return window.getSelection().toString();
    if (document.getSelection)
      return document.getSelection().toString();
    if (document.selection)
      return document.selection.createRange().text;
  }
  catch (e)
  {
    return "";
  }
  return "";
}
//]]>
  
  
  
    JSONiq
    
    
   
  
    The XQuery Vision in 2000
    
    
    
  The World Wide Web promises to transform human society by making
  virtually all types of information instantly available
  everywhere. Two prerequisites for this promise to be realized are
  a universal markup language and a universal query
  language. The power and flexibility of XML make it the
  leading candidate for a universal markup language.
    
    Don Chamberlin, Jonathan Robie, Daniela Florescu, 2000
    www.almaden.ibm.com/cs/people/chamberlin/quilt_lncs.pdf
   
  
    The XQuery Vision in 2000
    
    
    
      XML provides a way to label information from diverse data
      sources including structured and semi-structured documents,
      relational databases, and object repositories.
    
    
       The Extensible Markup Language, XML, is having a profoundly
       unifying effect on diverse forms of information. For the first
       time, XML provides an information interchange format that is
       editable, easily parsed, and capable of representing nearly any
       kind of structured or semi-structured information.
    
    Don Chamberlin, Jonathan Robie, Daniela Florescu, 2000
     www.almaden.ibm.com/cs/people/chamberlin/quilt_lncs.pdf
   
  
    The JSON Vision
    
    
    
    
      Unfortunately, XML is not well suited to data-interchange, much
      as a wrench is not well-suited to driving nails. It carries a lot of baggage, and it doesn't match
      the data model of most programming languages. When most
      programmers saw XML for the first time, they were shocked at how
      ugly and inefficient it was. It turns out that that first
      reaction was the correct one. There is another
      text notation that has all of the advantages of XML, but is much
      better suited to data-interchange. That notation is
      JavaScript Object Notation (JSON).
    
    Douglas Crockford
    http://www.json.org/xml.html
   
  
    The JSON Vision
    
    
    
    
       JSON is a better data exchange format. XML is a better document
       exchange format. Use the right tool for the right job.
    
    Douglas Crockford
    http://www.json.org/xml.html
   
  
    JSON, XML, and Semi-Structured Data
    
    
      
	
	  The good news and the bad news:
	  Semi-structured data is wildly successful.
	  There are at least two markup languages.
	
	
	  JSON is replacing or supplementing XML in many
	  new environments, APIs, and applications.
	
	
	  XML remains the best choice for documents, when schemas are needed, for existing standards.
	
	
	  XML ecosystem is ubiquitous and mature, JSON tools are evolving.
	
      
   
  
    What is JSONiq?
    
    
    
      "XQuery for JSON"
      XQuery is well suited for hierarchical semi-structured data. Many implementations exist, and can easily be adapted to add JSON support.
      Goal: A powerful query language for JSON, without the complexity of XML.
      JSONiq XQ--
      The fat-free XQuery — drop XML, use JSON instead.
      
      Goal: A data integration query language that can query and create JSON, XML, or HTML.
      JSONiq XQ++
      The fatter XQuery that can also do JSON.
    
   
  
    JSONiq in a nutshell
    
    
    
      Adds JSON constructs to XQuery Data Model
      Object and Array Constructors
      
{
  "name" : "Sarah",
  "age" : 13,
  "gender" : "female",
  "friends" : [ "Jim", "Mary", "Jennifer"]
}
      
      
      Member Accessors
      
$sarah("friends")(1)
      
      
    
   
  
    JSONiq in a nutshell (2)
    
    
    
      
	Composes with XQuery expressions
	
let $sarah := collection("users")[.("name") = "Sarah"]
return {
  "name" : "Amanda",
  "age" : $sarah("age") + 1,
  "gender" : "female",
  "friends" : $sarah("friends")
}
	
	Wherever a value can occur, an expression can also occur — the composability SQL never had.
      
    
   
 
  
    A Grouping Query in JSONiq (Data)
    
    
    
      
	Data — collection("sales"):
	{ "product" : "broiler", "store number" : 1, "quantity" : 20  },
{ "product" : "toaster", "store number" : 2, "quantity" : 100 },
{ "product" : "toaster", "store number" : 2, "quantity" : 50 },
{ "product" : "toaster", "store number" : 3, "quantity" : 50 },
{ "product" : "blender", "store number" : 3, "quantity" : 100 },
{ "product" : "blender", "store number" : 3, "quantity" : 150 },
{ "product" : "socks", "store number" : 1, "quantity" : 500 },
{ "product" : "socks", "store number" : 2, "quantity" : 10 },
{ "product" : "shirt", "store number" : 3, "quantity" : 10 }
	
    
    Group sales by product, across stores.
   
 
    A Grouping Query in JSONiq
    
    
    
      
	Query: group sales by product, across stores.
        {
  for $sales in collection("sales")
  let $pname := $sales("product")
  group by $pname
  return $pname : sum(for $s in $sales return $s("quantity"))
}   
	
	
	  Result:
	  {
  "blender" : 250,
  "broiler" : 20,
  "shirt" : 10,
  "socks" : 510,
  "toaster" : 200
}  	  
	
    
   
 
    More complex grouping (Data)
    
    
    
      Group sales by state, category, product
        
	Data — collection("products"):
        { "name" : "broiler", "category" : "kitchen", "price" : 100, "cost" : 70 },
{ "name" : "toaster", "category" : "kitchen", "price" : 30, "cost" : 10 },
{ "name" : "blender", "category" : "kitchen", "price" : 50, "cost" : 25 },
{ "name" : "socks", "category" : "clothes", "price" : 5, "cost" : 2 },
{ "name" : "shirt", "category" : "clothes", "price" : 10, "cost" : 3 }
      
      
        Data — collection("stores"):
        { "store number" : 1, "state" : CA },
{ "store number" : 2, "state" : CA },
{ "store number" : 3, "state" : MA },
{ "store number" : 4, "state" : MA }
        
      
    
  
 
    More complex grouping
    
    
    
        
	Query: Group sales by state, category, product
	{
  for $store in collection("stores")
  let $state := $store("state")
  group by $state
  return
     $state : {
       for $product in collection("products")
       let $category := $product("category")
       group by $category
       return
         $category : {
            for $sales in collection("sales")
            where $sales("store number") = $store("store number")
              and $sales("product") = $product("name")
            let $pname := $sales("product")
            group by $pname
            return $pname : sum( for $s in $sales return $s("quantity") )
         }
      }
}	
      
    
  
 
    More complex grouping
    
    
    
      
	Query synopsis:
	{
  $state : {
     $category : {
         $pname : sum( for $s in $sales return $s("quantity") )
     }
  }
}	
      
        
	Result:
	{
  "CA" : {
      "clothes" : {
         "socks" :  510
      },
      "kitchen" : {
         "broiler" : 20,
         "toaster" : 150
      }
  },
  "MA" : {
      "clothes" : {
         "shirt" : 10
       },
      "kitchen" : {
         "blender" : 250,
         "toaster" : 50
      }
  }
}
  
 
    Views of Relational Data
    
    
    
    | 
    userid
     | 
    ticker
     | 
    shares
     | 
|---|
| 
    W0342
     | 
    DIS
     | 
    153212312
     | 
| 
    M0535
     | 
    DIS
     | 
    10
     | 
| 
    M0535
     | 
    AIG
     | 
    23412
     | 
    [
    { "userid" : "W0342", "ticker" : "DIS", "shares" : 153212312 },
    { "userid" : "M0535", "ticker" : "DIS", "shares" : 10 },
    { "userid" : "M0535", "ticker" : "AIG", "shares" : 23412 }
]    
    JSON is better than XML for this - XML is more complex for humans and for query optimizers.
  
 
    Converting JSON <=> XML <=> HTML
    JSON:
    {
  "col labels" : ["singular", "plural"],
  "row labels" : ["1p", "2p", "3p"],
  "data" :
     [
        ["spinne", "spinnen"],
        ["spinnst", "spinnt"],
        ["spinnt", "spinnen"]
     ]
}
    Query:
    
   (: Column headings :)
  {
     |   | ,
     for $th in values(json("table.json")("col labels"))
     return { $th } | 
  }
  
  {  (: Data for each row :)
     for $r at $i in values(json("table.json")("data"))
     return
        
         {
           | { values(json("table.json")("row labels")[$i]) } | ,
           for $c in $r
           return { $c } | 
         }
        
  }
]]>
    
  
 
    Sample Use Cases
    
    
    
    Some of the use cases at http://jsoniq.org:
    
	Joins
	Grouping
	Windowing and Events
	Updates
	JSON views in middleware
	Data transformations
	Convert XML to JSON
	Convert JSON to XML
	Convert either to HTML
    
  
 
    Python API
    
    
from jsoniq import Connection
connection = Connection("probono", "94306")
connection.set(sasl_mechs="GSSAPI", ssl="true", ssl_cert_alias="cert1")
try:
  connection.open()
  dbase = connection.risotto
  collection = dbase.developers
  a = {"name": {"last": "brantner", "first": "matthias" }, "role": "wizard" }
  b = {"name": {"last": "westmann", "first": "till" }, "role": "demigod" }
  collection.insert(a)
  collection.insert(b)
  q = """
     for $d in collection("developers")
     where $d("role") = "wizard"
     return $d
  """
# A simple query.
#
# query() prepares a query and executes it
  cursor = dbase.query(q)
  for c in cursor:
      json.dumps(c)
# A prepared query that binds variables
  q = """
     for $d in collection("developers")
     where $d("role") = $role
     return $d
  """
  query = dbase.prepare(q)
  query.bind(role="wizard")
  cursor = query.execute()
  for c in cursor:
    json.dumps(c)
# Inspecting free variables and bindings
  q = """
     for $d in collection("developers")
     where $d("role") = $role
     return $d
  """
  query = dbase.prepare(q)
  for f in query.free(): # returns all free variables
      if f:isbound:
        print f.name(), f.value()
      else
        print f.name(), " is not bound!"
        query.bind(f.name(), "comedian")
# The API expects an implementation to be smart enough to keep track
# of all open databases for a connection, all open queries for a
# database, etc., and to close them appropriately.
except ConnectionError,c:
  print c
finally:
  connection.close()
  
 
    jsoniq.org
    
    
   
    Available at http://jsoniq.org:
    
      Language Specification
      Use Cases
      XQ++ BNF
      XQ-- BNF
      Early state ... things are still changing ... more to come ...