JavaScript
  Home arrow JavaScript arrow Page 2 - More on JavaScript and XML
Dev Articles Forums 
ADO.NET  
Apache  
ASP  
ASP.NET  
C#  
C++  
ColdFusion  
COM/COM+  
Delphi-Kylix  
Design Usability  
Development Cycles  
DHTML  
Embedded Tools  
Flash  
Graphic Design  
HTML  
IIS  
Interviews  
Java  
JavaScript  
MySQL  
Oracle  
Photoshop  
PHP  
Reviews  
Ruby-on-Rails  
SQL  
SQL Server  
Style Sheets  
VB.Net  
Visual Basic  
Web Authoring  
Web Services  
Web Standards  
XML  
Mobile Linux 
App Generation ROI 
IBM® developerWorks 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Write For Us Get Paid 
Request Media Kit
Contact Us 
Site Map 
Privacy Policy 
Support 
 USERNAME
 
 PASSWORD
 
 
  >>> SIGN UP!  
  Lost Password? 
JAVASCRIPT

More on JavaScript and XML
By: O'Reilly Media
  • Search For More Articles!
  • Disclaimer
  • Author Terms
  • Rating: 4 stars4 stars4 stars4 stars4 stars / 2
    2007-08-16

    Table of Contents:
  • More on JavaScript and XML
  • 21.6 Expanding HTML Templates with XML Data
  • 21.7 XML and Web Services
  • 21.8 E4X:ECMAScript for XML

  • Rate this Article: Poor Best 
      ADD THIS ARTICLE TO:
      Del.ici.ous Digg
      Blink Simpy
      Google Spurl
      Y! MyWeb Furl
    Email Me Similar Content When Posted
    Add Developer Shed Article Feed To Your Site
    Email Article To Friend
    Print Version Of Article
    PDF Version Of Article
     
     
    ADVERTISEMENT


    More on JavaScript and XML - 21.6 Expanding HTML Templates with XML Data


    (Page 2 of 4 )

    One key feature of IE’s XML data islands is that they can be used with an automatic templating facility in which data from a data island is automatically inserted into HTML elements. These HTML templates are defined in IE by adding datasrc and datafld (“fld” is short for “field”) attributes to the elements.

    This section applies the XML techniques seen earlier in the chapter and uses XPath and the DOM to create an improved templating facility that works in IE and Firefox. A template is any HTML element with a datasource attribute. The value of this attribute should be the ID of an XML data island or the URL of an external XML doc ument. The template element should also have a foreach attribute. The value of this attribute is an XPath expression that evaluates to the list of nodes from which XML data will be extracted. For each XML node returned by the foreach expression, an expanded copy of the template is inserted into the HTML document. The template is expanded by finding all elements within it that have a data attribute. This attribute is another XPath expression to be evaluated in the context of a node returned by the foreach expression. This data expression is evaluated with XML.getNode() , and the text contained by the returned node is used as the content of the HTML element on which the data attribute was defined.

    This description becomes much clearer with a concrete example. Example 21-12 is a simple HTML document that includes an XML data island and a template that uses it. It has an onload() event handler that expands the template.

    Example 21-12. An XML data island and HTML template

    <html>
    <!-- Load our XML utilities for data islands and templates -->
    <head><script src="xml.js"></script></head> <!-- Expand all templates on document load
    -->
    <body onload="XML.expandTemplates()">

    <!-- This is an XML data island with our data -->
    <xml id="data" style="display:none"> <!-- hidden with CSS -->
     
    <contacts>
        <contact name="Able Baker"><email>able@example.com</email></contact>
        <contact name="Careful Dodger"><email>dodger@example.com </email></contact>
        <contact name="Eager Framer"><email>framer@example.com </email></contact>
      </contacts>
    </xml>

    <!-- These are just regular HTML elements
    -->
    <table> <tr><th>Name</th><th>Address</th></tr>
    <!-- This is a template. Data comes from the data island with id "data". -->
    <!-- The template will be expanded and copied once for each <contact> tag -->
    <tr datasource="#data" foreach="//contact"> <!-- The "name" attribute of the <contact> is inserted into this element -->
    <td data="@name"></td>
    <!-- The content of the <email> child of the <contact> goes in here -->
    <td data="email"></td>
    </tr> <!-- end of the template -->
    </table>
    </body>
    </html>

    A critical piece of Example 21-12 is the onload event handler, which calls a function named XML.expandTemplates() . Example 21-13 shows the implementation of this function. The code is fairly platform-independent, relying on basic Level 1 DOM functionality and on the XPath utility functions XML.getNode() and XML.getNodes() defined in Example 21-10.

    Example 21-13. Expanding HTML templates

    /*
     
    * Expand any templates at or beneath element e.
     
    * If any of the templates use XPath expressions with namespaces, pass
     
    * a prefix-to-URL mapping as the second argument as with XML.XPathExpression()
     *
     
    * If e is not supplied, document.body is used instead. A common
     
    * use case is to call this function with no arguments in response to an
     * onload event handler. This automatically expands all templates.
     */
    XML.expandTemplates = function(e, namespaces) {
        // Fix up arguments a bit.
        if (!e) e = document.body;
        else if (typeof e == "string") e = document.getElementById(e);
        if (!namespaces) namespaces = null; // undefined does not work

        // An HTML element is a template if it has a "datasource" attribute.
        // Recursively find and expand all templates. Note that we don't
        // allow templates within templates.
        if (e.getAttribute("datasource")) {
           
    // If it is a template, expand it.
           
    XML.expandTemplate(e, namespaces);
        }
        else {
           
    // Otherwise, recurse on each of the children. We make a static
            // copy of the children first so that expanding a template doesn't
            // mess up our iteration.
            var kids = []; // To hold copy of child elements
            for(var i = 0; i < e.childNodes.length; i++) {
               
    var c = e.childNodes[i];
                if (c.nodeType == 1) kids.push(e.childNodes[i]);
            }

            // Now recurse on each child element
            for(var i = 0; i < kids.length; i++)
                XML.expandTemplates(kids[i], namespaces);
        }
    };

    /**
     
    * Expand a single specified template.
     * If the XPath expressions in the template use namespaces, the second
     
    *argument must specify a prefix-to-URL mapping
     */
    XML.expandTemplate = function(template, namespaces) {
        if (typeof template=="string") template=document.getElementById(template);
        if (!namespaces) namespaces = null; // Undefined does not work

        // The first thing we need to know about a template is where the
        // data comes from.
        var datasource = template.getAttribute("datasource");

        // If the datasource attribute begins with '#', it is the name of
        // an XML data island. Otherwise, it is the URL of an external XML file.
        var datadoc;
        if (datasource.charAt(0) == '#') // Get data island
           
    datadoc = XML.getDataIsland(datasource.substring(1));
        else                 // Or load external document
            datadoc = XML.load(datasource);

        // Now figure out which nodes in the datasource will be used to
        // provide the data. If the template has a foreach attribute,
        // we use it as an XPath expression to get a list of nodes. Otherwise,
        // we use all child elements of the document element.
        var datanodes;
        var foreach = template.getAttribute("foreach");
        if (foreach) datanodes = XML.getNodes(datadoc, foreach, namespaces);
        else {
           
    // If there is no "foreach" attribute, use the element
            // children of the documentElement
            datanodes = [];
            for(var c=datadoc.documentElement.firstChild; c!=null; c=c.nextSibling)
               
    if (c.nodeType == 1) datanodes.push(c);
        }

        // Remove the template element from its parent,
        // but remember the parent, and also the nextSibling of the template.
        var container = template.parentNode;
        var insertionPoint = template.nextSibling;
        template = container.removeChild(template);

        // For each element of the datanodes array, we'll insert a copy of
        // the template back into the container. Before doing this, though, we
        // expand any child in the copy that has a "data" attribute.
       
    for(var i = 0; i < datanodes.length; i++) {
            var copy = template.cloneNode(true);                     // Copy template
            expand(copy, datanodes[i], namespaces);                // Expand copy
            container.insertBefore(copy, insertionPoint);            // Insert copy
        }

        // This nested function finds any child elements of e that have a data
        // attribute. It treats that attribute as an XPath expression and
        // evaluates it in the context of datanode. It takes the text value of
        // the XPath result and makes it the content of the HTML node being
        // expanded. All other content is deleted.
        function expand(e, datanode, namespaces) {
           
    for(var c = e.firstChild; c != null; c = c.nextSibling) {
                if (c.nodeType != 1) continue;  // elements only
                var dataexpr = c.getAttribute("data");
                if (dataexpr) {
                    // Evaluate XPath expression in context.
                    var n = XML.getNode(datanode, dataexpr, namespaces);
                    // Delete any content of the element
                    c.innerHTML = "";
                    // And insert the text content of the XPath result
                    c.appendChild(document.createTextNode(getText(n)));
                }
                // If we don't expand the element, recurse on it.
                else expand(c, datanode, namespaces);
            }
        }

        // This nested function extracts the text from a DOM node, recursing
        // if necessary.
        function getText(n) {
           
    switch(n.nodeType) {
           
    case 1: /* element */
               
    var s = "";
               
    for(var c = n.firstChild; c != null; c = c.nextSibling)
                   
    s += getText(c);
               
    return s;
           
    case 2: /* attribute*/
           
    case 3: /* text */
           
    case 4: /* cdata */
               
    return n.nodeValue;
            default:
                return "";
            }
        }

    };

    More JavaScript Articles
    More By O'Reilly Media


       · This article is an excerpt from the book "JavaScript: The Definitive Guide, Fifth...
     

    Buy this book now. This article is excerpted from chapter 21 of JavaScript: The Definitive Guide, Fifth Edition, written by David Flanagan (O'Reilly; ISBN: 0596101996). Check it out today at your favorite bookstore. Buy this book now.

    JAVASCRIPT ARTICLES

    - Using jQuery to Preload Images with CSS and ...
    - Using Client-Side Scripting to Preload Image...
    - Removing Non-Semantic Markup when Preloading...
    - Using the Display CSS Property to Preload Im...
    - Preloading Images with CSS and JavaScript
    - Scaling and Moving Web Page Elements with th...
    - Fading, Hiding and Sliding HTML Elements wit...
    - Toggling CSS Properties with the GX JavaScri...
    - Cancel, Queue and Pause Animations with the ...
    - Producing Elastic Effects with the GX JavaSc...
    - Moving Divs Diagonally with the GX JavaScrip...
    - Moving Elements Vertically and Horizontally ...
    - Making Bouncing Effects in Parallel with the...
    - Creating Bouncing Effects with the GX JavaSc...
    - Manipulating Background Colors with the GX J...







    © 2003-2010 by Developer Shed. All rights reserved. DS Cluster 12 Hosted by Hostway
    For more Enterprise Application Development news, visit eWeek