­­­­ 

 

Javascript and XML Guide

 

 

Documentation home

 

Javascript and XML 1

XML and XMLList Javascript Object. 2

Literal XML 4

Navigating XML 5

XPath. 6

Iterating XML 7

Constructing XML using Templates 8

Modifying XML 9

XML and Code-assist (Intellisense) 9

E4X and Ebase XML Resources 10

Accessing an XML Document and its values 10

Setting XML Document on an XML Resource. 11

 

 

See also: Javscript Scripting Menu, Javascript Editor, API Javadoc

 

E4X is an ECMA (Javascript) standard. It provides an API for creating and processing XML documents using Javascript.

 

This document provides an introduction to E4X (ECMAScript for XML). ECMA-262 (Javascript 1.3) was standardized in December 1999. ECMA-357 (E4X) was standardized in June 2004. E4X is an extension to Javascript. Further information regarding the E4X specification can be found here. Previous knowledge of XML and Javascript is assumed when reading this document.

 

Javascript and XML

 

The E4X API consists of 4 native XML Javascript objects. The Global object is an extension to the ECMA Script Global object.

 

See table below for more information on the basic XML Javascript types:

 

Javascript Object

Description

XML

An XML base object. This can represent a document or element.

XMLList

Consists of multiple XML elements of the same name.

Namespace

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.

QName

QName objects are used to 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, this qualified name matches any Namespace.

Global

Adds an additional method XMLName(value) to Global.

 

 

To instantiate an object is the same as instantiating any other Javascript object:

 

//new xml object

var x = new XML();

 

//new date object

var d = new Date();

 

//new array

var a = new Array();

 

All XML objects are an extension of Javascript Object.

 

XML and XMLList Javascript Object.

E4X also provides many Java DOM-like capabilities. The methods of the XML object include the following methods. Objects marked with a * are also available on XMLList objects.

 

Methods of the XML object

Meaning

addNamespace(namespace)

Adds the namespace to the in-scope namespaces of the element.

appendChild(child)

Adds child as a new child of the element, after all other children.

attribute(attributeName) *

Returns the attribute of with the requested name.

attributes() *

Returns the attributes of this element.

child(propertyName) *

Returns the child element with the given propertyName, or if propertyName is an integer, returns the child in that position.

childIndex()

Returns the index of this child among its siblings.

children() *

Returns all the children of this object.

comments() *

Returns all the comments that are children of this XML object.

contains(value) *

Compares this element with the value, primarily provided to enable an XML element and an XML list to be used interchangeably.

copy() *

Returns a deep copy of the element. The parent property of the copy will be set to null.

descendants([name]) *

Returns the descendant elements (children, grandchildren, etc.). If a name is provided, only elements with that name are returned.

elements([name]) *

Returns the child elements. If a name is provided, only elements with that name are returned.

hasComplexContent() *

Returns true for elements with child elements, otherwise false.

hasSimpleContent() *

Returns true for attributes, text nodes, or elements without child elements, otherwise false.

inScopeNamespaces()

Returns an array of Namespace objects representing the namespaces in scope for this object.

insertChildAfter(child1, child2)

Inserts child2 immediately after child1 in the XML object's children list.

insertChildBefore(child1, child2)

Inserts child2 immediately prior to child1 in the XML object's children list.

length() *

Returns 1 for XML objects (allowing an XML object to be treated like an XML List with a single item.)

localName()

Returns the local name of this object.

name()

Returns the qualified name of this object.

namespace([prefix])

Returns the namespace associated with this object, or if a prefix is specified, an in-scope namespace with that prefix.

namespaceDeclarations()

An array of Namespace objects representing the namespace declarations associated with this object.

nodeKind()

A string representing the kind of object this is (e.g. "element").

normalize() *

Merge adjacent text nodes and eliminate empty ones.

parent() *

The parent of this object. For an XML List object, this returns undefined unless all the items of the list have the same parent.

processingInstructions([name]) *

A list of all processing instructions that are children of this element. If a name is provided, only processing instructions matching this name will be returned.

prependChild(value)

Add a new child to an element, prior to all other children.

removeNamespace(namespace)

Removes a namespace from the in-scope namespaces of the element.

replace(propertyName, value)

Replace a child with a new one.

setChildren(value)

Replace the children of the object with the value (typically an XML List).

setLocalName(name)

Sets the local name of the XML object to the requested value.

setName(name)

Sets the name of the XML object to the requested value (possibly qualified).

setNamespace(ns)

Sets the namespace of the XML object to the requested value.

text() *

Concatenation of all text node children.

toString() *

For elements without element children, returns the values of the text node children. For elements with element children, returns same as toXMLString. For other kinds of objects, the value of the object.

toXMLString() *

Serializes this XML object as parse-able XML.

valueOf() *

Returns this XML object.

 

 

Literal XML

 

E4X introduces a new type of “XML” object which holds an XML element. These objects are created by writing XML directly or by creating a new XML object:

 

//write XML directly using Literal XML

var customer = <customer id="A1101">

                  <firstName>Fred</firstName>

                  <lastNameName>Fred</lastName>

              </customer>

 

//write XML using new XML()

var order = new XML(<order id="1111"><part id="12345" quantity="2"/></order>);

 

The XML Object can be constructed with:

 

 

//Example:

var xml = new XML(<customer><name>Fred</name></customer>);

 

 

//Example:

var xml = new XML('<customer><name>Fred</name></customer>');

 

 

//Example:

var w3c = resources.MY_XML.getDocument('XML_DOCUMENT');

var xml = new XML(w3c);

 

There are certain rules that apply when writing Literal XML:

 

To create an XML element containing multiple elements with the same name, an XMLList object is created. These can be created by writing the XML object directly by wrapping the XML within <> and </> tags or creating a new XMLList object.

 

//write XMLList directly

var parts =   <>

    <part id="AA101" quantity="1"/>

    <part id="BB102" quantity="2"/>

    <part id="CC103" quantity="1"/>

              </>

 

//or write XML using new XMLList()

var parts = new XMLList("<part id='AA101' quantity='1'/><part id='BB102' quantity='2'/><part id='CC103' quantity='1'/>");

 

The XMLList Object can be constructed with:

 

 

//Example:

var xml = new XMLList(<><name>Fred</name><name>Rachel</name></>);

 

 

//Example:

var xml = new XMLList('<name>Fred</name><name>Rachel</name>');

 

Navigating XML

 

Once an XML object is instantiated, properties and methods can accessed, for example, its name and namespace, children, attributes and text content using the familiar Javascript dot operator or by using the E4X API.

 

//create customer

var c = <customer number="1721">

            <name>

                  <first>John</first>

      <last>Smith</last>

            </name>

      <phone type="mobile">888-555-1212</phone>

      <phone type="office">888-555-2121</phone>

  </customer>;

//Create name var

var name = c.name.first + " " + c.name.last;

//get customer number attribute

var num = c.@number;

//find first phone number.

var firstphone = c.phone[0];

 

A child element can be accessed by name as a property of the parent. If there is more than one child with that name, an XML List is returned, which can be further qualified by an index or other qualifier. A child attribute can be accessed by name using the "@" prefix, or with the attribute() method.

 

The text value of an element with a primitive value (no element children) or of an attribute can be obtained explicitly as a string by the toString() method, but in most circumstances the toString() method will be called automatically when a string value is needed. For a complex element (one with children), toString() returns the XML syntax representation of the element. To obtain the XML syntax representation of a node explicitly (including elements with primitive values), use the toXMLString() method.

 

c.name.toString()

'<name><first>John</first><last>Smith</last></name>'

c.name.toXMLString()

'<name><first>John</first><last>Smith</last></name>'

c.@number.toString()

'1721'

c.@number.toXMLString()

'1721'

c.phone[0].toString()

'888-555-1212'

c.phone[0].toXMLString()

'<phone type="mobile">888-555-1212</phone>'

 

XPath

A useful construct in XPath is the predicate notation (e.g. "customer/phone[@type='mobile']") to filter a node list. E4X has a similar construct:

 

c.phone.(@type == "mobile")

 

In this notation the XML List of elements matching c.phone is filtered to those with a type attribute with the value "mobile". If no elements match, the result is an empty XML list, best checked for empty using ".length() == 0".

 

The following summary provides some XPath equivalents for common XML navigation operations:

 

XPath

Meaning

E4X Equivalent

element/*

Select all children of element

element.*

element/@*

Select all attributes of element

element.@*

element//descendent

Select all descendants (children, grandchildren, etc.) of element

element..descendent

.. or parent::element

Select the parent of element

element.parent()

xmlns:foo="..."

element/foo:bar

Select the foo:bar child of element where foo is the prefix of a declared namespace

var foo = new Namespace(...);

element.foo::bar

name(element)

Return the full name (including prefix if any) of element

element.name()

local-name(element)

Return the local name of element

element.localName()

namespace-uri(element)

Return the namespace uri (if any) of element

element.namespace()

element/namespace::*

Return the collection of namespaces as an Array of Namespace objects (E4X) or a node set of Namespaces nodes (XPath)

element.inScopeNamespaces()

element/processing-instructions(name)

Return the processing instruction children of element with the specified name (if omitted, all are returned).

element.processingInstructions(name)

string(element)

Return the concatenated text nodes of this element and all its descendants

stringValue(element);

 

stringValue.visible = false;

function stringValue(node)

{

    var value = "";

    if (node.hasSimpleContent())

    {

        value = node.toString();

    }

    else

    {

      for each (var c in node.children())

      {

        value += stringValue(c);

      }

    }

    return value;

}

Iterating XML

To iterate through the matching elements:

//create customer

var c = <customer number="1721">

    <name>

        <first>John</first>

        <last>Smith</last>

    </name>

    <phone type="mobile">888-555-1212</phone>

    <phone type="office">888-555-2121</phone>

</customer> ;

 

for (var i = 0; i < customer.phone.length(); i++){

   log(customer.phone[i].toString());

}

 

This is using identical syntax to that used to access numbered items in an array. Despite these similarities to regular arrays, XMLList does not support Array methods such as forEach, and Array generics such as Array.forEach() are not compatible with XMLList objects.

We can also use the for….each statement introduced in Javascript 1.6 as part of Javascript's E4X support:

 

for each (var phone in customer.phone) {

    log(phone);

}

Constructing XML using Templates

Besides the literal use of XML as a value, or parsing XML text into an XML value, E4X provides a templating mechanism to construct complex XML structures from variable and expression values. Within text content, curly braces can be used to insert a value into the XML:

 

var nextId = 1234;

var first = "John";

var last = "Smith";

var c = <customer number={nextId++}>

          <name>

            <first>{first}</first>

            <last>{last}</last>

          </name>

        </customer>;

 

Attribute values can be determined by replacing the whole attribute value (including quotes!) with an expression. Curly braces within quotes will be treated literally.

 

Element and attribute names can be evaluated too:

 

var phonetype = "mobile";

var identifiertype = "id";

var c = <{phonetype} {identifiertype}={nextId++} />888-555-2112</{phonetype}>;

 

XML lists can be created by using the addition operator on individual XML elements:

 

var employees = <employee name="Joe"/> +

                <employee name="Arun"/> +

                <employee name="Betty"/>;

 

Modifying XML

The value of an element or attribute can be changed by assigning a new value to it:

 

c.@number = 1235;
c.phone.(@type='mobile') = "650-555-1234";

 

Deleting an XML element or attribute from a structure is accomplished with the delete operator:

 

delete c.phone.(@type='office');

 

To add a child, one can use the += operator to insert a new element at a particular location:

 

c.phone += <phone type='home'>650-555-1414</phone>; // append new phone child.

c.phone[0] += <phone type='home'>650-555-1414</phone>; // insert new phone child after the first phone child.

 

XML and Code-assist (Intellisense)

 

The code-assist in the Javascript editor supports the completions for the 5 main XML objects described above. Details for the full API can be found in the ECMA-357 document.

 

If a variable is assigned using XML directly, then this is assumed to be of type XML as this is the most generic XML type.

 

 

 

 

E4X and Ebase XML Resources

It is possible to access an XML document directly through the XML Resource API Javadoc using the following two methods:

 

 

These methods provide a convenient way to get or set a document within an XML resource and provide an alternative to the use of field mappings.

 

Accessing an XML Document and its values

In the example below, an XML document is read from a file and then the data is extracted directly from the XML resource.

Consider reading the following XML structure from a file:

 

<?xml version="1.0" encoding="UTF-8"?>

<customer>

  <contact>

    <name>Joe Blogs</name>

    <age>78</age>

    <telephone>077-799-8756</telephone>

  </contact>

</customer>

 

The following Javascript code reads the XML Document and extracts the name, age and telephone elements from the XML.

 

importPackage(com.ebasetech.xi.api);

importPackage(com.ebasetech.xi.services);

 

//read the XML Document

resources.XML_EXAMPLE.read();

//get the XML Document from the XML resource and assign to variable - customer

var customer = resources.XML_EXAMPLE.getDocument("MY_DOC");

//create a new Javascript XML type

var xmlCustomer = new XML(customer);

//get the name, age and telephone values from the Customer XML type

var name = xmlCustomer.contact.name;

var age = xmlCustomer.contact.age;

var telephone = xmlCustomer.contact.telephone;

//assign to fields

fields.NAME.value = name;

fields.AGE.value = age;

fields.TELEPHONE.value = telephone;

 

Note that the getDocument(documentName) returns a Java W3C Document (org.w3c.Document). If you are familiar with this Java API, it is also possible to use this directly instead of constructing a Javascript XML Object. Details of the org.w3c.Document API is outside the scope of this document.

 

Setting XML Document on an XML Resource

 

In the example below, an XML document is added to an XML Resource and written to a file without using field mappings to the XML resource.

Consider writing the following XML structure to a file:

 

<?xml version="1.0" encoding="UTF-8"?>

  <purchaseOrder>

    <item>

<name>Hairspray</name>

<price>0.99</price>

<quantity>3</quantity>

    </item>

    <item>

<name>Shampoo</name>

<price>1.99</price>

<quantity>1</quantity>

    </item>

</purchaseOrder>

 

The following Javascript code shows how to create an XML Document within a Script and set the XML document on the XML resource.

 

//create a new purchase order

var purchaseOrder = <purchaseOrder/>;

//iterate rows

var rows = tables.PURCHASE_ORDERS.rows;

 

//create row index

var index = 0;

while(rows.next())

{

//append new item to purchaseOrder

      var item = purchaseOrder.appendChild(<item/>).item;

     

      var name = tables.PURCHASE_ORDERS.ITEM.value;

      var price = tables.PURCHASE_ORDERS.PRICE.value;

      var quantity = tables.PURCHASE_ORDERS.QUANTITY.value;

           

      item[index].appendChild(<name>{name}</name>);

      item[index].appendChild(<price>{price}</price>);

      item[index].appendChild(<quantity>{quantity}</quantity>);

      index++; //increment row index

}

//set the purchase order document

resources.XML_EXAMPLE.setDocument("MY_DOC", purchaseOrder);

//write the document

resources.XML_EXAMPLE.write();