devxlogo

E4X Adds Direct XML Support to JavaScript

E4X Adds Direct XML Support to JavaScript

he Web has undergone some major changes during past few years. What started purely as static HTML pages now includes dynamic pages with personalization, improved performance, and new technologies such as AJAX, DHTML, XML, CSS, etc. Still, HTML and JavaScript remain the backbone of Web technology today; all this new Web technology and development revolve mainly around them.

JavaScript itself has evolved along with the Web. Its origins trace back to 1995 when Netscape introduced LiveScript?the first programming language to make Web pages interactive?in its Netscape Navigator version 2.0b1 release. Netscape integrated LiveScript into the browser, enabling it to interpret LiveScript commands directly without having to compile code or employ a plug-in to run the code. Later, Netscape renamed LiveScript to JavaScript and in 1996 handed it over to an international standards body called ECMA (European Computer Manufacturers Association). ECMA took responsibility for the subsequent development and standardizing of the language, which it officially renamed ECMAScript, although it remains popularly known as JavaScript (in browsers) and ActionScript (in Macromedia’s Flash player).

Meanwhile, XML has become an integral part of Web development. To best utilize its power, developers must effectively create, navigate, and manipulate XML data. While innovative new programming models are designed specifically for this (e.g., XSLT, XQuery, the DOM), they are unfamiliar to many software developers. At the same time, the learning curves for these technologies are very high, so XML-based projects can require high-priced specialists for both development and maintenance.

Web developers in particular need to do a lot of coding to parse and update XML, especially when they use it with JavaScript because providing cross-browser support requires even more coding. ECMAScript for XML (E4X), a new extension to ECMAScript, eases this process. E4X (ECMA-357 Standard) adds direct support for XML to JavaScript and simplifies XML scripting. Think of it as JavaScript for XML. It is designed to provide a simple, familiar, general-purpose XML programming model that shortens and flattens the XML learning curve by leveraging the existing skills and knowledge of the JavaScript developer.

This article explains E4X and its objective, lays out its usage with syntax and code snippets, and outlines its advantages and limitations.

The Objective of E4X
With E4X, you can define an XML document as a JavaScript object. To quote the E4X specification page:

“E4X adds native XML datatypes to the ECMAScript language, extends the semantics of familiar ECMAScript operators for manipulating XML objects, and adds a small set of new operators for common XML operations, such as searching and filtering. It also adds support for XML literals, namespaces, qualified names, and other mechanisms to facilitate XML processing.”

The following are some of the specific benefits of using E4X:

  1. Simplify the ability of Web developers to use the power of XML by using their existing skills and knowledge, and reusing familiar concepts, operators, and syntax (i.e., E4X makes XML very simple to use.)
  2. Standardize the syntax and semantics of a general-purpose, cross-platform, vendor-neutral set of programming language extensions by adding native XML support in ECMAScript
  3. Reduce code complexity, time to market, and revision cycles
  4. Improve performance and maintainability
  5. Decrease coupling between code and external data (in form of XML)
  6. Integrate well with other languages designed for manipulating XML, such as XPath, XSLT, and XQuery (For example, E4X should be able to invoke complementary languages when additional expressive power is needed without compromising the simplicity of the E4X language itself.)

Understanding the Usage of E4X
Before digging deeper into E4X, see how E4X can make a difference in your XML handling. Table 1 provides examples of two XML parsing approaches: one using DOM, the other E4X.

The format of the sample.xml in Table 1 is as follows:

     List of authors and Articles               Rahul Gupta                    Jon      

The output from both approaches is the same (see Figure 1).

Figure 1. The Output from XML Parsing Approaches (With and Without E4X) Is the Same

E4X offers a cleaner and easier way to retrieve values from XML within JavaScript, wouldn’t you say? All because E4X is meant specifically for providing XML support. Without E4X, you have to use an XML library/component, and those work differently in different browser.

E4X also provides all types of language constructs, such as statement loops, operators, namespaces, objects, keywords, etc. In order to use it in your pages, you just add the parameter e4x=1 in the script tag as follows:

Or

Context Keywords
E4X adds three context keywords (each, XML, namespace). Context keywords take on a specific meaning when used in specified contexts where identifiers are not permitted by the syntactic grammar.

Statements
The default XML namespace of the global scope has the initial value of no namespace. You can define its scope also. For example, if you define it within a function call, the value set will not be accessible outside the function. To deal with XML with namespaces easily, you can declare a default namespace for the current scope (e.g., function scope or global scope) using the newly introduced statement, as follows:

 default xml namespace = expression;

The above statement should evaluate to a string with a URI or to a namespace object. The result is that all elements created in the current scope will be in the default namespace, provided they have no prefix in their name. The following code snippet shows the uri value when the default namespace is both defined and not defined:

  var xmlElement1 = 

Hello how are you

; // shows ''; alert(xmlElement1.name().uri); // set default namespace default xml namespace = 'http://www.w3.org/1999/xhtml'; var xmlElement2 =

Hello how are you

; // shows 'http://www.w3.org/1999/xhtml'; alert(xmlElement2.name().uri);

The for-in statement evaluates an expression and iterates through each property of the resulting XML object. When the expression evaluates to an XML object, the for-in statement converts the XML object to an XMLList and iterates over the resulting XMLList. The following snippet shows the usage of a for-in loop statement:

var xmlElement =                     Rahul Gupta                    Jon                   ;//show  Rahul Gupta, freelance, Jon, employedfor (var childElement in xmlElement.author)  {     alert("Element No ["+childElement +"] = " + xmlElement.author[childElement]);     for (var childAttribute in xmlElement.author[childElement].@type)        alert("Attribute No ["+childAttribute +"] = " + xmlElement.author[childElement].@type);  }

The for-each-in statement iterates through each property of the resulting XMLList object in order. The following code snippet shows the usage of for-each-in statement:

var xmlElement =  Rahul GuptaJon;//shows  Rahul Gupta, freelance, Jon, employedfor each (var xmlElements in xmlElement.author) {    alert( " Element = "+ xmlElements);    for each (var xmlAttributes in xmlElements.@type)    alert( " Attribute = "+ xmlAttributes.toXMLString()); }

The for-each-in statement behaves differently from the for-in statement. In particular, it assigns the loop variable over the range of the object rather than the domain of the object. For example, the for-each-in statement binds the loop variable to the property values of the given object rather than the property names.

Identifiers and Punctuators
Table 2 lists E4X identifiers and punctuators with descriptions and accompanying examples.

Identifiers Sign/Represented By Description Example
Attribute Identifiers @ An attribute identifier is used to identify the name of a XML attribute. It evaluates to a value of type AttributeName. The preceding "@" character distinguishes an XML attribute from an XML element with the same name.
var xmlElement = 
Rahul Gupta
;
// shows 'freelance'
alert(xmlElement.author.@type);
Qualified Identifiers :: A qualified identifier is used to identify values defined within a specific namespace. They may be used to access, manipulate, and create namespace-qualified XML elements and attribute names.
var xmlElement3 =  

Google

var xhtml = new Namespace('http://www.w3.org/1999/xhtml');
var xhtmlElements = xmlElement3.xhtml::*;

//shows 1 - for body
alert(xhtmlElements.length());
Wildcard Identifiers * A wildcard identifier is used to identify any name. It may be used for matching namespaces, properties of XML objects, or XML attributes.
var xmlElement = 
Rahul
Jon
;
//shows all elements and Attributes
for each (var xmlElements in xmlElement.*) {
alert("Element="+ xmlElements);
for each (var xmlAttributes in xmlElements.@*)
alert("Attribute="+
xmlAttributes.toXMLString());
}
Descendent Accessor .. A descendent accessor supports the XML descendent (Child, grandchild, great-grandchild) accessor.
var xmlElement =

Rahul Gupta
Jon
;
// shows 'freelanceemployed'
alert(xmlElement..@type);
Table 2. E4X Identifiers and Punctuators

Operators
Table 3 lists E4X operators with descriptions and accompanying examples.

Operator Sign/Represented By Description Example
Delete Operator "delete" keyword This operator is for deleting XML properties and XML attributes from XML objects and XMLLists.
var xmlElement = 
Rahul Gupta
;
delete xmlElement.author.@books;
// will not show "java" attribute
for each (var xmlAttributes in xmlElement..@*)
alert("Attribute="+
xmlAttributes.toXMLString());
Typeof Operator "typeof" keyword This operator is for determining the types of XML and XMLList objects.
var xmlElement =
Rahul Kumar Gupta;
// show "xml"
alert(typeof(xmlElement));
Addition Operator + Depending on its arguments, this operator is for performing string concatenation, XML and XMLList concatenation, or numeric addition.
var xmlElement = 
Java
JSP
;
totPrice= +xmlElement.book[0].@price +
+xmlElement.book[1].@price;
// show "250"
alert(totPrice);
Equality Operator == This operator is for enabling equality comparisons (including E4X objects like QName and Namespace objects, and the types XML and XMLList).
var xmlElement1 =  price="100">Java;
var xmlElement2 = price="150">Java;
// shows "false"
alert( (xmlElement1 == xmlElement2));
Assignment Operator = This operator is used to modify, replace, and insert properties and XML attributes in an XML object. It has two types:
  1. XML Assignment
  2. XMLList Assignment
var xmlElement = 
Java
JSP
;
xmlElement.book[1].@price = 165;
// shows "165"
alert(xmlElement.book[1].@price);
Compound Assignment op= E4X benefits from the compound assignment operator "+=". It is used for inserting the XML objects specified by the AssignmentExpression just after the XML objects specified by the LeftHandSideExpression in the context of their parent.
var xmlElement =  
Java
JSP
;
xmlElement.book[0] += price="200">EJB;
//shows JAVA. EJB JSP
for each (var xmlElements in xmlElement.*)
alert("Element="+ xmlElements);
XML Filtering Predicate Operator xml(list)Object.(filtering predicate expression) This operator is used to apply a condition to filter out certain elements in a child node or descendent accessor.
var xmlElement=  
Rahul
EJB
JSP
;
//show EJB
for each (var xmlElements in xmlElement.*) {
if(xmlElements.@price == '200')
alert(xmlElements);
Table 3. E4X Operators

E4X Objects
E4X adds four native objects to ECMAScript:

  • Namespace
  • QName
  • XML
  • XMLList

In addition, E4X adds new properties to the global object. It adds native XML support to the language, meaning in addition to types like Number, String, Boolean, and Object, there is the XML type for representing XML elements, attributes, comments, processing-instructions, or text nodes, and the XMLList type for representing a list of XML objects. Both XML and XMLList are new fundamental data types for representing XML objects and lists of XML objects.

The XML type is an ordered collection of properties with a name, a set of XML attributes, a set of in-scope namespaces, and a parent. The following is an example of an XML object referring to one root node:

An XML initializer is an expression written in a form of a literal that describes the initialization of an XML object. It may specify a XML element, a XML comment, a XML PI, or a CDATA section using ordinary XML syntax. The following sample code shows one:

// an XML object representing a author with a name and agevar author =  Rahul Gupta    freelance;//on XML Object representing two authors var publishing =   Rahul Gupta     Jon ;

The XMLList type is an ordered collection of properties. A value of type XMLList represents a XML document, an XML fragment, or an arbitrary collection of XML objects. This is an example of an XMLList that refers to multiple nodes:

A XMLList initializer is an expression describing the initialization of an XMLList object. It describes an ordered list of XML properties using an anonymous XML element syntax. XMLList initializers begin with the character sequence "" and end with the character sequence ">". The following snippet shows a way to initialize the XMLList object in E4X code:

var xmlIstObj = Rahul Gupta  freelance>; var authorlistObt =      Rahul Gupta     Jon >; 

The main difference between the two is that with XML you are dealing with one specific object that can contain n number of child nodes while with XMLList you are dealing with a collection of one or more XML objects.

To simplify the programmer's task, E4X intentionally blurs the distinction between a single XML object and an XMLList containing only one value. To that end, E4X extends the ECMAScript's function call semantics such that all methods available for values of type XML are also available for XMLLists of size one.

Table 4 lists E4X methods and properties with descriptions and accompanying examples.

Methods/Properties Available
in XML
Available
in XML List
Description
addNamespace(..) Y   The addNamespace method adds a namespace declaration to the in-scope namespaces for an XML object and returns the XML object.
appendChild(..) Y   The appendChild method appends the given child to the end of an XML object's properties and returns the XML object.
Alternatives:
  1. Use the insertChildBefore method with the first parameter value as null.
  2. Use a compound operator.

attribute(..) Y Y The attribute method takes the names of the attributes to look for.
Alternative: xml.@attributeName OR xml.['@attributeName']
attributes(..) Y Y The attributes method returns a XMLList containing the XML attributes.
Alternative: xml.@* OR xml ['@*']
child(..) Y Y The child property takes the child property name to look for.
Alternative: xml.ChildPropertyName OR xml['ChildPropertyName']
childIndex(..) Y   The childIndex method returns a number representing the ordinal position of an XML object within the context of its parent. When xmlobject has no parent, the special number value NaN (not a number) is returned.
children(..) Y Y The children method returns a XMLList containing all the child properties.
Alternative: use wild card *
comments (..) Y Y The comments method returns an XMLList containing the properties that represent XML comments. Make sure that you have the XML.ignoreComments = false; setting before creating XMLobject.
contains(..) Y Y The contains method takes one argument: the value to check for in xmlobject/XmlList.
copy(..) Y Y The copy method returns a deep copy of this XML object/XmlList. You can make a copy of either all or part of XML object/XmlList.
descendants (..) Y Y The descendants method returns an XMLList with thedescendants matching the passed name argument or with all descendants, if no argument is passed.
Alternative: Use the descendants operator (..)
elements(..) Y Y The elements method takes on a parameter and returns an XMLList with all matching child elements or with all child elements if no argument was passed.
Alternative:
  xml.childElementName  xml ['childElementName']
hasOwnProperty(..) Y Y The hasOwnProperty method returns a Boolean value indicating whether the object/List has the property specified by parameter.
hasComplexContent(..) Y Y The hasComplexContent method returns a Boolean value indicating whether the XML object/XMLList contains complex content (i.e., an XML element that has child elements).
hasSimpleContent(..) Y Y The hasSimpleContent method returns a Boolean value indicating whether the XML object/list contains simple content (i.e., a text node, attribute node) or represents an XML element that has no child elements.
Note: The existence of attributes, comments, processing instructions, and text nodes within an XML object/list is not significant for determining if it has simple content.
isScopeNamespaces(..) Y   The isScopeNamespaces method returns an array of Namespace objects representing the namespaces that are in scope for this XML object.
insertChildAfter(...) Y   The insertChildAfter method takes two arguments (p1 and p2), an existing child (p1) to insert after and the new child (p2) to be inserted. If p is null, it inserts p2 before all the children of an XML object. If p1 does not exist in this XML object, it returns without modifying the XML object.
insertChildBefore(..) Y   The insertChildBefore method takes two arguments (p1 and p2), an existing child (p1) to insert before and the new child (p2) to be inserted. If p1 is null, it inserts p2 after all children in the XML object. If p1 does not exist in the XML object, it returns without modifying the XML object.
length(..) Y Y The length method returns the number of XMLObjects the XMLList contains.
Note: For XmlObject, it always returns 1.This is to make a distinction between an XML object and an XMLList object containing exactly one value.
localName(..) Y   The localName method returns the local name portion of the qualified name of the XML object.
Note: Text nodes and comment nodes do not have a name, thus for these kinds of XML objects, null is returned.
name(..) Y   The name method returns the qualified name associated with the XML object or null if the object has no name (as for text nodes and comment nodes).
namespace(..) Y   The namespace method takes one optional parameter (p1). If p1 is not specified, it returns the namespace associated with the qualified name of the XML object. Otherwise, it looks for a matching namespace in the in-scope namespace of the XML object and returns it.
namespaceDeclarations(..) Y   The namespaceDeclarations method returns an array of Namespace objects representing the namespace declarations associated with the XML object in the context of its parent.
nodeKind(..) Y   The nodeKind method returns a string representing the type of node the XMLObject is. The possible values are element, attribute, text, comment, and processing-instruction.
normalize(..) Y Y The normalize method returns XMLObject after joining adjacent text nodes and eliminating empty text nodes.
parent(..) Y Y The parent method returns the parent of this XML object, or null if there is no parent.
Note: The parent of the attribute is an element to which the attribute is attached.
processingInstructions(..) Y Y The processingInstructions method takes one parameter, the PI name to look for, and returns the XMLList with all the matching PI child nodes.
Note: If no parameter is defined, then the wild card name '*' is used to match all PI.
prependChild(..) Y   The prependChild method inserts a specified child as the first child in xmlObject.
Alternatives:
1. Use the insertChildAfter method with the first parameter value as null.
2. Use a compound operator.
propertyIsEnumerable(..) Y Y The propertyIsEnumerable method determines whether the specified property will be included in the set of properties iterated over when the XML object is used in a for-in statement. The method returns true when ToString(P) is "0"; otherwise false.
removeNamespaces(..) Y   The removeNamespaces method removes the namespace from the in-scope namespaces of the XML object.
replace(..) Y   The replace method takes two parameters (p1 and p2) and replaces the XML properties of the XML object specified by propertyName (p1) with value (p2) and returns this XML object.
Note: The propertyName parameter may be a numeric property name, an unqualified name for a set of XML elements, a qualified name for a set of XML elements, or the properties wildcard "*".
setChildren(..) Y   The setChildren method takes two parameter (p1 and p2). It replaces the XML properties (p1) of the XML object with a new set of XML properties from value (p2). Value may be a single XML object or an XMLList. SetChildren returns this XML object.
setLocalName(..) Y   The setLocalName method changes the local name of this XMLObject with the name passed in.
setName(..) Y   The setName method changes the QName of the XMLObject with the name passed in. The parameter can be a string or a QName object.
setNamespace(..) Y   The setNamespace method changes the namespace associated with the name of the XML object to the new specified namespace.
text(..) Y Y The text method returns an XMLList containing all XML properties of the XML object that represent XML text nodes.
toString(..) Y Y The toString method returns a convenient string representation of the XMLList/XmlObject.
Note: If you are looking for complete serialization of all XML objects in the XMLList, use toXMLString.
toXMLString(..) Y Y The toXMLString method returns an XML-encoded string representation of the XMLList/XMLObject. It always includes the start tag, attributes, and end tag of the XML object regardless of its content. Global settings such as XML.prettyPrinting and XML.prettyIndent format and indent the resultant string.
valueOf(..) Y Y The valueOf method simply returns the XML object/XML list it is called on.
Table 4. E4X Methods and Properties

QNames (Qualified Names) represent qualified names of XML elements and attributes. Each QName object has a local name of type string and a namespace URI of type string or null. When the namespace URI is null, the qualified name matches any namespace. A QName object can be created by using the following:

QName ( ) or QName ( Name ) or QName (Namespace,  Name )              var Qnamevar = new QName('http://www.w3.org/1999/xhtml', 'author');

An XML object representing an element or attribute has an internal name property, which is a QName object having two properties, localName and uri. You can get the QName of any XMLObject by using the name(..) method. Table 5 lists QName methods and properties with their descriptions and accompanying examples.

Methods/Properties Description Example
localName The value of the localName property is a value of type string. When the value of the localName property is "*", it represents a wildcard that matches any name.
QNameVar =
QName("http://www.w3.org/1999/xhtml","author");
//shows author
alert(QNameVar.localName);
uri The value of the uri property is null or a value of type string identifying the namespace of the QName. When the value of the uri property is the empty string, this QName is said to be in no namespace.
QNameVar =
QName("http://www.w3.org/1999/xhtml","author");
//shows http://www.w3.org/1999/xhtml
alert(QNameVar.uri);
Table 5. QName Methods and Properties

Namespace objects represent XML namespaces and provide an association between a namespace prefix and a unique resource identifier (URI). The prefix is either the undefined value or a string value that may be used to reference the namespace within the lexical representation of an XML value.

You can create a Namespace object using either of the following:

Namespace ( )  or   Namespace ( uriValue ) or Namespace ( prefixValue, uriValue )       var namespaceVar = new Namespace("author",'http://www.w3.org/1999/xhtml');

Table 6 lists namespace methods and properties with their descriptions and accompanying examples.

 Methods/Properties  Description Example
prefix The value of the prefix property is either the undefined value or a string value.
var xmlElement = 

xmlns:xhtml="http://www.w3.org/1999/xhtml">Hello how are you.

;
var namespace = xmlElement.namespace();
//shows 'xhtml'
alert(xmlElement.namespace().prefix);
uri The value of the uri property is a string value. When the value of the uri property is the empty string, the Namespace represents the unnamed namespace in no namespace.
  var xmlElement = 

Hello how are you

;
// shows ''
alert(xmlElement.name().uri);
Table 6. Namespace Methods and Properties

When no namespace is defined for an element/XML, the uri property has as its value an empty string. Otherwise, the uri property has as its value the namespace URI. The following code shows the usage of the uri method:

 var xmlElement = 

Hello how are you

; // shows '' alert(xmlElement.name().uri); xmlElement =

Hello how are you.

; // shows 'http://www.w3.org/1999/xhtml alert(xmlElement.name().uri);

Global Methods and Properties
Table 7 lists namespace global methods and properties with their descriptions and accompanying examples.

Methods/Properties Description Example
ignoreComments If ignoreComments is true, XML comments are ignored when constructing new XML objects.

Default -true

  XML.ignoreComments = false;
var xmlElement = Rahul Gupta ;
for each (var xmlElements in xmlElement.*)
alert(" Element = "+ xmlElements);
ignoreProcessingInstructions If ignoreProcessingInstructions is true, XML-processing instructions are ignored when constructing new XML objects.

Default -true

XML.ignoreProcessingInstructions= false;
var xmlElement =

Rahul Gupta
;
for each (var xmlElements in xmlElement.*)
alert(" Element = "+ xmlElements);
ignoreWhiteSpace If ignoreWhitespace is true, insignificant whitespace characters are ignored when processing or constructing new XML objects. Whitespace characters are defined to be space (u0020), carriage return (u000D), line feed (u000A), and tab (u0009).

Default -true

  XML.ignoreWhitespace = false;
var xmlElement =

Rahul Gupta
;
alert(xmlElement.toString());
prettyIndent Child nodes will be indented relative to their parent node by the number of spaces specified by prettyIndent. This is effective only when prettyPrinting is true.

Default -2

  alert(xmlElement.toXMLString());

XML.prettyPrinting=true;
XML.prettyIndent = 4;
var xmlElement =
XML.prettyPrinting=false;
prettyPrinting If prettyPrinting is true, the ToString and ToXMLString operators will normalize whitespace characters between certain tags to achieve a uniform appearance.

Default -true

   var xmlElement = Rahul Gupta 
Jon
;

alert(xmlElement.toXMLString());

XML.prettyPrinting=true;
XML.prettyIndent = 4;
var xmlElement =
Rahul Gupta
Jon
;
alert(xmlElement.toXMLString());
isXMLName(..) IsXMLName is used to determine whether it is a valid XML name that can be used as an element or attribute name.
//shows false
alert(isXMLName("?xml"));
//shows true
alert(isXMLName("author"));
Table 7. Namespace Global Methods and Properties

Advantages and Limitations of E4X
One more ECMAScript technique for handling XML is object mapping. You can map XML data onto a set of ECMAScript objects, manipulate those objects directly, and then map them back to XML. This approach has the advantage of allowing ECMAScript programmers to use their existing knowledge, but it has some problems. For example, an ECMA native object can't preserve the order of the original XML data. As E4X evolves, this approach will mature and become standardized. Table 8 summarizes the advantages and limitations of E4X.

Area Description
Browser Support As of now (Nov. 2006), Mozilla, FireFox 1.1 +, and Safari provide limited support. IE7 doesn't support E4X, but it is becoming standard so in future all browser should support it.
Code Size In general, the size of the code you produce when using E4X for a requirement tends to be smaller than the code generated with other XML-related technologies.
Learning Curve The learning curve is very low, as it is an extension to JavaScript.
Cost Both development and maintenance costs are lower than other related technologies such as XSLT, XML queries, or DOM routines.
Performance E4X is lighter weight than similar technologies so it has better performance.
Table 8. Advantages and Limitations of E4X
The author wishes to thank his colleagues Mr. Saurabh Bhatnagar, Tarun Gera, and Sumit Gupta for their valuable contributions as reviewers for this article.
devxblackblue

About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist