XML (object extension)

Categories:Objects

Overview

Summary

An extended XML class to fix some SpiderMonkey implementation bugs, and add some useful methods to the XML core.

Contents

Concept

Although JSFL's support of E4X is pretty good, there's a bug where the Spidermonkey JavaScript engine cannot reference an XML node's native methods such as attribute() or name(), inside a filter expression, and Flash will throw a a Reference Error if you try to do so:

var nodes = xml.(attribute('id') == 'someId'); // broken
ReferenceError: attribute is not defined	

However, there is a workaround to this, which is to namespace methods inside filter expressions with the keyword function:: :

var nodes = xml.(function::attribute('id') == 'someId'); // works

This workaround is great for simple filter expressions, but xJSFL goes further with its support for XML and XMLList management and manipulation.

New XML and XMLList methods

Luckily, it's possible to extend the native XML and XMLList prototype objects with new methods. xJSFL adds:

Callbacks

These methods accept as their first argument a callback, which is written in a manner similar to the usual filter, but as a Function with a Boolean (true/false) return value:

var nodes = xml.find( function(node, index, nodes){ return node.@id == 'someId' } );

All three methods will always pass the following parameters to the callback function: node, index and nodes, which you can use in your callbacks as you see fit.

Note that the index parameter is the index of the current node being processed in relation to all of the the total nodes being processed. In the case of immediate children, this will be the same as the child index, however in the case of descendant nodes it won't.

Expressions

As xJSFL is designed around the workflow of an everyday Flasher, you also have the option to use CSS-style expressions in order to filter or select nodes, instead of a more verbose callback:

var nodes = xml.find('#someId');

You'll notice that this expression is actually even shorter than normal filtering! All three methods (find, remove & filter) support the following basic expressions:

'node'        // node name
'#id'         // ids
'.class'      // classes
'@attr'       // attribute exists
'@attr=value' // attribute matches

Example code

All example code on this page will use the following XML fragment for testing:

var xml =
<xml>
    <a id="a" vowel="true"/>
    <b id="b" />
    <c id="c" class="test" />
    <d id="d" class="test">
        <e id="e" vowel="true">
            <f id="f" class="test" />
        </e>
    </d>
</xml>

XML

find(callback, descendents)

Find nodes according to a callback or expression

Parameters:

  • callback Function A callback function of the format function(node, index, array) that should return a Boolean
  • callback String A CSS-style expression to match a node
  • descendents Boolean An optional boolean to filter all desendant nodes

Returns:

  •   XMLList An XML list of the filtered nodes

The following example finds all immediate child nodes of node name "a":

var nodes = xml.find('a');
trace(nodes.toXMLString());
<a id="a" name="vowel"/>

The following example finds all immediate nodes with an id attribute "b":

var nodes = xml.find('#b');
trace(nodes.toXMLString());
<b id="b"/>

The following example finds all immediate nodes with the attribute "class" equal to "test":

var nodes = xml.find('.test');
trace(nodes.toXMLString());
<c id="c" class="test"/>
<d id="d" class="test">
    <e id="e" vowel="true">
        <f id="f" class="test" />
    </e>
</d>

The following example finds all descendent nodes with the attribute "class" equal to "test":

var nodes = xml.find('.test', true);
trace(nodes.toXMLString());
<c id="c" class="test"/>
<d id="d" class="test">
    <e id="e" vowel="true">
        <f id="f" class="test"/>
    </e>
</d>
<f id="f" class="test"/>

The following example finds all descendent nodes with the attribute "type" equal to "vowel":

var nodes = xml.find('@type=vowel');
trace(nodes.toXMLString());
<a id="a" vowel="true"/>
<e id="e" vowel="true"/>

The following example finds all descendent nodes with children using a callback:

var nodes = xml.find( function(node, index, nodes){ return node.children().length() > 0; }, true );
trace(nodes.toXMLString());
<d id="d" class="test">
    <e id="e" vowel="true">
        <f id="f" class="test"/>
    </e>
</d>
<e id="e" vowel="true">
    <f id="f" class="test"/>
</e>

remove(callback, descendents)

Remove nodes according to a callback or expression

Parameters:

  • callback Function A callback function of the format function(node, index, array) that should return a Boolean
  • callback String A CSS-style expression to match a node
  • descendents Boolean An optional boolean to filter all desendant nodes

Returns:

  •   XML The original node

The following example removes all descendent nodes with the class 'test':

xml.remove('.test', true);
trace(xml.toXMLString());
<xml>
    <a id="a" vowel="true"/>
    <b id="b"/>
</xml>

XMLList

filter(callback)

Filter an existing XMLList with a callback or expression

Parameters:

  • callback Function A callback function of the format function(node, index, array) that should return a Boolean
  • callback String A CSS-style expression to match a node
  • descendents Boolean An optional boolean to filter all desendant nodes

Returns:

  •   XML The original node

The following example filters an existing XMLList using a callback:

var nodes = xml..*;
trace(nodes.toXMLString());

var filtered = nodes.filter( function(node, index, nodes){ return index % 2 == 0; } );
trace(filtered.toXMLString());

The nodes XMLList:

<a id="a" vowel="true"/>
<b id="b"/>
<c id="c" class="test"/>
<d id="d" class="test">
    <e id="e" vowel="true">
      <f id="f" class="test"/>
    </e>
</d>
<e id="e" vowel="true">
    <f id="f" class="test"/>
</e>
<f id="f" class="test"/>

The filtered XMLList:

<a id="a" vowel="true"/>
<c id="c" class="test"/>
<e id="e" vowel="true">
    <f id="f" class="test"/>
</e>

Comments are closed.