Not yet rated
Tags:



Problem

Using JSON.stringify() on an ActionScript XML class does not return a usable result. The XMLList class does not define toJSON() at all; in this case, JSON.stringify() returns the string resulting from a standard traversal of the object. How can I override this default behavior to customize how my XML or XMLList maps to JSON?

Solution

Way #1: Convert XML object to Object and pass it into JSON.stringify method. Way #2 (thanks Richard): Override toJSON method (for XML) or add toJSON method (for XMLList) through prototype.

Detailed explanation

Way #1: Convert XML object to Object and pass it into JSON.stringify method.

Something like:

//Converter
package   
{   
    import flash.xml.XMLDocument;
    import flash.xml.XMLNode;
    import flash.xml.XMLNodeType;

    public class XMLToObjectConverter
    {
        //---------------------------------------------------------------------
        //
        // public methods
        //
        //---------------------------------------------------------------------
        public static function converXMLToObject(xml:XML):Object
        {
            var xmlDocument:XMLDocument = new XMLDocument(xml.toXMLString());
            return _getObjectFromXMLNode(xmlDocument.firstChild);
        }

        public static function converXMLListToObject(xmlList:XMLList):Object
        {
            var result:Array = [];
            for each(var xml:XML in xmlList)
            {
                result.push(converXMLToObject(xml));
            }
            return result;
        }

        //---------------------------------------------------------------------
        //
        // private methods
        //
        //---------------------------------------------------------------------
        private static function _getObjectFromXMLNode(node:XMLNode):Object
        {
            var result:Object = { };

            switch(node.nodeType)
            {
                case XMLNodeType.ELEMENT_NODE:
                {
                    //node name
                    result['name'] = node.nodeName;
                    result['type'] = 'element';

                    //node attributes
                    var attributes:Object = node.attributes;
                    var isNodeHaveAttributes:Boolean;
                    for (var attr:* in attributes)
                    {
                        isNodeHaveAttributes = true;
                        break;
                    }

                    if (isNodeHaveAttributes)
                    {
                        result['attributes'] = attributes;
                    }

                    //node children
                    if (node.hasChildNodes())
                    {
                        var children:Array = [];

                        var i:uint;
                        var count:uint = node.childNodes.length;
                        for (i; i < count; i++)
                        {
                            var childNode:XMLNode = node.childNodes[i];
                            var childNodeObj:Object = _getObjectFromXMLNode(childNode);
                            if (childNodeObj)
                            {
                                children.push(childNodeObj);
                            }
                        }

                        result['children'] = children;
                    }

                    break;
                }
                case XMLNodeType.TEXT_NODE:
                {
                    //filter empty string text nodes
                    var nodeValue:String = node.nodeValue;
                    nodeValue = nodeValue.split('\t').join('').split('  ').join('');
                    nodeValue = nodeValue.split('\n').join('').split('\r').join('');
                    if (!nodeValue)
                    {
                        return null;
                    }

                    result['type'] = 'text';
                    result['text'] = nodeValue;           
                    break;
                }
                default:
                {
                    return null;
                }
            }
            return result;
        }
    }
}

//Usage
var xml:XML =   
    <data>
        <item part="1">
            <item data="itemData1">Some text 1</item>
            <item data="itemData2">Some text 2</item>
        </item>
        <item part="2">
            <item data="itemData4">
                <subitem>Some subitem text 1</subitem>
            </item>
            <item data="itemData5">Some text 3</item>
        </item>
    </data>

var obj1:Object = XMLToObjectConverter.converXMLToObject(xml);

var list:XMLList = xml.elements('item');
var obj2:Object = XMLToObjectConverter.converXMLListToObject(list);

trace(JSON.stringify(obj1));
trace(JSON.stringify(obj2));

----------------------------------------------------
Way #2 (thanks Richard):
Override toJSON method (for XML) or add toJSON method (for XMLList) through prototype.

BETA ActionScript® 3.0 Reference for toJSON() method of XML class says:
"Provides an overridable method for customizing the JSON encoding of values in an XML object.".

Here is the reference page: http://goo.gl/4r6nv.

XML.prototype.toJSON = function():*
{
    var result:String = '';
    result += 'Overrided toJSON result for XML:\n';
    //here this is reference to current XML object
    result += this.toXMLString();
    return result;
}

XMLList.prototype.toJSON = function():*
{
    var result:String = '';
    result += 'Overrided toJSON result for XMLList:\n';
    //here this is reference to current XMLList object
    result += this.toXMLString();
    return result;
}

var xml:XML =    
    <data>
        <item part="1">
            <item data="itemData1">Some text 1</item>
            <item data="itemData2">Some text 2</item>
        </item>
        <item part="2">
            <item data="itemData4">
                <subitem>Some subitem text 1</subitem>
            </item>
            <item data="itemData5">Some text 3</item>
        </item>
    </data>

trace(JSON.stringify(xml));

trace(JSON.stringify(xml.item));

+
This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. Permissions beyond the scope of this license, pertaining to the examples of code included within this work are available at Adobe.

Report abuse

Related recipes