Flex and XML namespaces

While learning Abobe's Flex technology one of the issues I faced was how to handle multiple namespaces in the soap messages returned from the web services we were calling. The web services had been written using XFire and, due to the tight deadlines, the namespaces where left to the verbose XFire defaults.

XML Processing with Flex in tutorials is easy

When reading Flex tutorials the XML provided is always in the default name space so there is no issue and it all looks extremely facile until you hit namespace issues. To be fair it is pretty easy once you work out how to use namespaces with Flex and e4x (javascript for xml)

Typically in the tutorials your XML looks like this:

  1. <root>
  2. <item>
  3. <name>Xandros Business Edition</name>
  4. <price>R350.00</price>
  5. </item>
  6. </root>

Real life XML processing with Flex

But when you get it back from a web service it looks more like

  1. <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  2. <soap:Body>
  3. <getStoreItemsResponse xmlns="http://www.jumpingbean.co.za/">
  4. <out>
  5. <ns1:item xmlns:ns1="http://storeitem.jumpingbean.co.za">
  6. <name xmlns="http://storeitem.jumpingbean.co.za>Xandros Business Edition</name>
  7. <price xmlns="http://storeitem.jumpingbean.co.za>R350</price>
  8. </getStoreItemsResponse>
  9. ...

To access price in the first example, assuming the XMLList variable which has been assigned the results, using HTTPService object, is called "getItemsResult", you can just go

  1. getItemsResult.item.price

The above will work if there is only one element in the XMLList, i.e it can be treated as an XML data type. If there is more than one item, which is more likely, then something like the following will return R350

  1. getItemsResult.item[0].price

With the second xml you would think you could just go (assuming that the lastResult method on the WebService object has been used to populate "getItemResult"):

  1. getItemsResult.out.item.price or,
  2. getItemsResult.out.item[0].price

The result returned will be a null or empty value as the xml query has no namespace information so uses the default namespace and the elements are not in the default namespace.

This works the same way as package names in Java. An object type of person in the default package is not the same as an object of type za.co.jumpingbean.person. Another analogy is SQL select statements. The analogy is not perfect because SQL will happily select columns from different tables if there is no name collision but employee.firstName is not the same field as customer.firstName.

How to access xml with multiple namespaces in Flex

To be able to access the data you need to define some XML namespaces in Flex. There is a namespace data type for this purpose. So you start off by declaring some namespace variables:

  1. var jbns1:Namespace = new Namespace ("http://www.jumpingbean.co.za");
  2. var jbns2:Namespace = new Namespace("http://storeitem.jumpingbean.co.za");

Ways to access xml namespace with Flex

The information on the Adboe site suggests the following way to access elements in different namespaces.

  1. default xml namespace=jbw1;
  2. var price:String = getStoreItemsResponse.out.item[0].price;

This did not work for me because:

  1. There is more than one namespace used in the XML,
  2. Even in the case of a single namespace my entire Flex page didn't load after declaring the default namespace. It was as if the parsing of the entire mxml file was affected and components in the "mxml" namespace where no longer visible. This even though the "default xml namespace =" was declared inside a function. This problem probably has more to do with my lack of knowledge on Flex though.

The way I could access my XML data was as follows:

  1. var price:String = getStoreItemsResponse.jbns1::out.jnbs2::item[0].jnbs2::price;

I had to qualify each element with its relevant namespace which makes sense. If you are familiar with SQL it is like qualifying each column name with its table name in a query. I also saw references elsewhere to using:

  1. use namespace jbns1;

I never tried this but should assume it won't work for more than one namespace in a xml object.

Why Flex's xml namespace handling suxs for components

On issue that I found quiet annoying was that some attributes of Flex components, that could take a XMLList obejct as a value, did not handle namespace at all. So the useful shortcuts for providing a label values with an xmllist did not work.

  1. <mx:DataGridColumn dataField="name" label="jbns1::getStoreItemsResponse.out.jnbs2::item.jnbs2::name" ...

I had to apply the XML query in Actionscript using the label function

  1. <mx:DataGridColumn dataField="name" labelFunction="labelFunction"

Maybe it was just my lack of knowledge but this was sucky. If it is a "feature" lets hope it gets fixed in Flex 3.