] > 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

first

XQuery for JSON, JSON for XQuery

Jonathan Robie <jonathan.robie@emc.org>

The XQuery Vision in 2000

head foot
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

head foot
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

head foot
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

head foot
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

head foot
  • 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.

  • JSONiq: XQuery for JSON

    head foot
  • A query language 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: JSON for XQuery

    head foot

    JSON is often much simpler for intermediate results in a query, passing parameters to functions, returning results from functions..

  • XML is the only complex data structure in XQuery

  • XML does not have references

    Example: returning full-text results

  • XML makes the programmer think harder

  • XML makes optimization harder

    Document order, namespace handling, whitespace handling, identity, axes ...

  • JSONiq in a nutshell

    head foot
  • 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)

    head foot
  • 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.

  • Adding JSON to XDM

    head foot

    A Grouping Query in JSONiq (Data)

    head foot
  • 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

    head foot
  • 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)

    head foot
  • 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

    head foot
  • 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

    head foot
  • 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

    head foot
    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

    head foot

    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

    head foot
    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 and XQuery: quo vadis?

    head foot
  • XSLT developed a maps proposal that didn't satisfy our use cases

    ... and the XQuery people gave no feedback for a long time ...

  • JSONiq developed use cases that were not accepted, then developed their own language

  • XSL and XQuery have now developed a set of use cases and initial requirements from both proposals

  • At least two implementations of JSONiq are under development.

  • jsoniq.org

    head foot

    Available at http://jsoniq.org:

  • Language Specification

  • Use Cases

  • XQ++ BNF

  • XQ-- BNF