XML.com: XML From the Inside Out
oreilly.comSafari Bookshelf.Conferences.

advertisement

Introducing E4X
by Kurt Cagle | Pages: 1, 2, 3, 4

Assigning to E4X Objects

One of the coolest aspects of E4X is the power exposed by assignments. Indeed, you can use assignment to quickly build XML structures from scratch, change values on the fly and add and remove new content quickly.

Consider, for instance, the nascent phone book discussed here. The following shows how you can create a new phone book with a single entry:

var phoneBook = <phoneBook/>;
phoneBook.phoneEntry = new XMLList();
var phoneEntry = <phoneEntry/>;
phoneEntry.name = "Jeane Tomasic";
phoneEntry.phoneNumber = "123-4567";
phoneBook.phoneEntry += phoneEntry;
print(phoneBook);
=><phoneBook>
   <phoneEntry>
        <name>Jeane Tomasic</name>
        <phoneNumber>123-4567</phoneNumber>
   </phoneEntry>
<phoneBook>

The second statement—phoneBook.phoneEntry = new XMLList();—indicates that any time phoneBook.phoneEntry is used as an L-Value (is on the left side of an assignment statement) it should be treated as a list (for reasons to be covered momentarily). The next three lines create an individual entry. When an XML() object has a new name (such as .name or .phoneNumber) appended to it, that name will be treated as a new element with that name, holding the value calculated from the right side of the equation. This is similar to the way that objects (as hashes) work, but in the case of objects, what are created are hash keys and values rather than elements and text children as is the case for E4X.

The statement phoneBook.phoneEntry += phoneEntry is, frankly, just cool. It adds the new phoneEntry object thus created to the phoneEntry list. Note that the element name of the added object MUST correspond to the name of the list or this throws an exception. However, in some cases, you may have multiple types of items being added to a given element. In this case you can use a wild card character as the list name, with no need to declare the entity.

var html = <html/>;
html.head.title = "A new XML Document";
html.head.style = <style type="text/css"><![CDATA[
h1 {font-weight:bold;}
     ]]></style>;
html.body.* = new XMLList();
html.body.h1 = "A new XML Document";
html.body.* += <p>This is the first paragraph.</p>;
html.body.* += <p>This is the second paragraph.</p>;
var ul = <ul/>;
ul.* = new XMLList();
ul.* += <li>This is item 1</li>;
ul.* += <li>This is item 2</li>;
html.body.* += ul;
print(html);
=>
<html>
    <head>
        <title>A new XML Document</title>
        <style type="text/css">
            h1 {
                font-weight:bold;
            }</style>
    </head>
    <body>
        <h1>A new XML Document</h1>
        <p>This is the first paragraph.</p>
        <p>This is the second paragraph.</p>
        <ul>
            <li>This is item 1</li>
            <li>This is item 2</li>
        </ul>
    </body>
</html>

This sequence makes a quick web page, doing a few rather subtle tricks to do so. The first is the implicit creation of nodes; the statement html.head.title = "A new XML Document" first checks to see if a <head> element is defined. Since one isn't, the E4X core automatically creates it before making the <title> child element to it. In the next statement, a CDATA block is used to add content that will not be parsed (avoiding the parsing of the CSS rule contained within the <style> element).

The statement html.body.* = new XMLList(); tells the E4X object that if new items are added to the * object (a wild card) these should be assumed to be added as a child to the list contained by the <body> element. This can be overridden explicitly (the <h1> statement does just this), but normally when objects are added via the += operator, they will then be added to the list in the order assigned. Thus, html.body.* += <p>This is the first paragraph.</p> adds a new paragraph to the body, the next statement adds a second paragraph to the body and so forth. The <ul> statement represents this same principle in miniature, and shows how you can add pieces to a larger structure without having to carry around the reference node.

The benefit of this approach is somewhat limited if you're just building an XML or XHTML structure - it's probably more efficient to just use a regular XML editor. However, this approach can come into its own when you're trying to combine XML and JavaScript. For instance, suppose that you had an object version of the phone book and you wanted to create a table showing the names and numbers of each person in the book. You can combine the above approach with JSON iteration to quickly create the table:

var _phoneBook= {phoneEntry:[
        {name:"Joe Schwartz",phoneNumber:"342-2351"}, 
        {name:"Aleria Delamare",phoneNumber:"342-7721"}, 
        {name:"Susan Sto Helit",phoneNumber:"315-2987"}, 
        {name:"Kyle Martin",phoneNumber:"342-7219"}
     ]};
var table = <table/>;
table.tr = new XMLList();
table.tr.th= new XMLList();
table.tr.th += <th>Name</th>;
table.tr.th += <th>Phone Number</th>;
for each (var entry in _phoneBook.phoneEntry){
     table.tr += <tr>
         <td>{entry.name}</td>
         <td>{entry.phoneNumber}</td>
       </tr>
     }
print(table);
=>
<table>
    <tr>
        <th>Name</th>
        <th>Phone Number</th>
    </tr>
    <tr>
        <td>Joe Schwartz</td>
        <td>342-2351</td>
    </tr>
    <tr>
        <td>Aleria Delamare</td>
        <td>342-7721</td>
    </tr>
    <tr>
        <td>Susan Sto Helit</td>
        <td>315-2987</td>
    </tr>
    <tr>
        <td>Kyle Martin</td>
        <td>342-7219</td>
    </tr>
</table>

Once created, the table can then be added into an existing element via the innerHTML property.

It's also possible to remove an item from an existing E4X object via the delete command. For instance, to remove the third item (Susan Sto Helit) from the table you just created, you simply use the command:

delete table.tr[3]

though a warning here is in order, unlike other XML technologies such as XPath, E4X is zero based, so that table.tr[3] is actually the fourth row in the table, but the first row is the header, bumping the index up one. If you wanted to exclude the header row, you'd use table.tr.(td)[3], as discussed below.

Pages: 1, 2, 3, 4

Next Pagearrow