Stephen's dev blog

Posts Tagged ‘xml

  • In: Tutorials
  • Comments Off on XML namespaces

If you’re a developer, I’m sure you would have seen XML namespaces somewhere before whilst looking at an XML document. But what are they? According to the Wiki page:

“XML namespaces are used for providing uniquely named elements and attributes in an XML instance. They are defined by a W3C recommendation called Namespaces in XML. An XML instance may contain element or attribute names from more than one XML vocabulary. If each vocabulary is given a namespace then the ambiguity between identically named elements or attributes can be resolved.”

So they provide a way of differentiating between similar, or same named XML elements/attributes in an XML document. How do you use them? Here’s an example:

<?xml version="1.0" encoding="utf-8"?>
<root xmlns:prod="http://www.my-site.com/namespaces/product" xmlns:ship="http://www.my-site.com/namespaces/shipping">
    <prod:items>
        <prod:item>
            <prod:name value="My product" />
            <prod:code value="123321" />
            <prod:price prod:currency="GBP" value="11.99" />
        </prod:item>
    </prod:items>
    <ship:method ship:postCode="CR3 4FT">
        <ship:name value="Next day AM" />
        <ship:price ship:currency="GBP" value="3.99" />
    </ship:method>
</root>

The first thing you’ll probably notice is the use of the xmlns attributes of the root node. This is used to declare a namespace. It can be used on any node and only child nodes of a node with the xmlns attribute will be able to use that namespace.

The part after the colon – in one of our cases ‘prod’ – is the alias for the namespace. All elements and attributes of that namespace have to be prefixed with this alias. The URL that the xmlns attribute points to doesn’t actually have to contain anything, it doesn’t even really have to exist. Your standard browser XML parser doesn’t take any information from this URL, it’s just there for usability. Some people use this URL to give information on what the namespace in question is used for and what it’s attributes/elements are. Oh, and it can’t be an empty string (“”)!

There are a number of tutorials on doing this around the web but I thought I’d write my own tailored tutorial on this topic.

I’m going to cover two scenarios;

Assigning XML results as a dataProvider:

This is by far the simplest of the two:

// The initialisation function
protected function init():void
{
    var serviceObj:HTTPService = new HTTPService();
    serviceObj.resultFormat = 'e4x';
    serviceObj.method = 'GET';
    serviceObj.useProxy = false;
    serviceObj.addEventListener(ResultEvent.RESULT, processResult);
    serviceObj.url = 'myScriptURL.php';
    serviceObj.send();
}

// The result processing function
protected function processResult(response:ResultEvent):void
{
    // make sure the response is cast as the correct data type
    var XMLResults:XML = response.result as XML;
    MyDataGrid.dataProvider = XMLResults.user;
}

// Sample XML sent from the server
<?xml version="1.0" encoding="utf-8" ?>
<users>
    <user>
        <id>1</id>
        <username>stephen</username>
        <email>stephen@example.com</email>
    </user>
</users>

You’ll notice I’ve set the resultFormat attribute of the HTTPService object to be ‘e4x’. In my experience I’ve found e4x more useful to work with XML in Flex. e4x stands for ECMAScript for XML and you can find out more about it here. e4x allows you to use XML as a primitive data type in your actionscript. I.E. you can do:

var myXML:XML = <root>
                    <myNode>
                        <myChildNode />
                    </myNode>
                </root>;

When using e4x as the result format, you don’t have to reference the root node when processing the XML, which is why I use the line

MyDataGrid.dataProvider = XMLResults.user;

instead of

MyDataGrid.dataProvider = XMLResults.users.user;

Creating a new XML dataProvider from an existing RPC result

This method is slightly more complicated but isn’t really needed as much. There’s really only a few situations that this would come in handy but I’ve had to use it on a recent project so I thought I may aswell post it.

Say you are making a call to a preexisting web service which is out of your control. In my situation, the web service WAS in my control, but it was already being used for other means so changing the output now wasn’t really an option. I wanted to process the XML, perform some logic on it and then add a new variable or two into the XML before assigning it to my DataGrid control.

The method I used in the end is quite simple and quick to do. You basically create a new empty XML document, loop through the results of the web service call, perform your logic and rebuild the new values into the new XML document. You then assign it to your control:

protected function processResult(response:ResultEvent):void
{
    // make sure the response is cast as the correct data type
    var XMLResults:XML = response.result as XML;
    // create the new XML document
    var newXML:XML = new XML('<users></users>');
    // loop through previous results
    for (var i:String in XMLResults.users)
    {
        // userXML is going to be our new user XML record
        var userXML:XML = new XML();
        // status is the new variable I want to add to the dataProvider
        var status:String;
        // perform some logic on the previous results
        if (XMLResults.users.activated[i] == 1)
        {
            status = 'Active';
        }
        else
        {
            status = 'Inactive';
        }
        // build the new XML record for this user
        // we can use {XMLResults.user.field[i]} to keep any previous elements in tact that we want to keep
        // use the {} parenthesis to put actionscript variables into the XML datatype
        userXML =
                <user>
                    {XMLResults.user.username[i]}
                    {XMLResults.user.email[i]}
                    <status>{status}</status>
                </user>;
        // add the new user record to the XML document
        newXML = newXML.appendChild(userXML);
    }
    MyDataGrid.dataProvider = newXML;
}



  • Patrick: I changed my code, but now I have another problem: Fatal error: Call to a member function isAvailable() on a non-object in /var/www/vhost/web/shopA
  • Stephen Gray: Hi Patrick, That first error is my fault. I had the method name for the refund() method as void() as I had copied the code from the other method!
  • Patrick: Hi Stephen, thanks for sharing your knowledge about creating a custom payment module. I need an extension for magento to handle a credit card payme

Categories