In my ongoing Flex/.NET Web Service hell, I've come across a solution to remove all the namespaces from the SOAP XML returned from a (.NET) Web Service.

You might be wondering why one would need to strip XML namespaces from the SOAP response. The long and short of it is that there are known bugs (that Adobe will not fix for v3.x but is fixed in Gumbo/v4) in the Flex 3 SDKs related to the auto-generation of AS3 classes from a WSDL file and the subsequent decoding of complex SOAP XML objects to their corresponding ActionScript objects. In brief, Flex doesn't create the AS3 classes "properly" such that they can decode the response how a developer not only would expect but also need. Google "SOAP decoding error Flex 3 .NET" and you should get plenty of information, or just skim through some of my Flex-labeled posts.

You can fight with this and waste hours upon hours, days upon days, and weeks upon weeks (like me -- this whole thing made me realize how stubborn I am/can be). Or, you can take a somewhat more efficient, if not more intelligent, approach and revert to using Flex's WebService class for methods that throw errors, manipulating the returned SOAP XML manually.

An issue (I use 'issue' very loosely here) with the e4x format in ActionScript is that namespaces in your XML will make it hard to impossible to work with the XML. Ultimately, in my opinion, one is better off simply stripping all the namespaces out of the XML. I initially tried to go about this programmatically, using properties of the XML class (i.e., namespace). This had mixed results and took up a lot of my time. So, this morning, with the help of some good blog posts and forum topics, I found a nice function that cleanly strips out all the namespace data from an XML file and returns a "clean" XML string.

I want to stress that the code from the following function is not mine. I found it on ActionScript.org's Forums. Scroll down to the question titled 'How do I strip all namespaces from the XML?'

If you don't want to go to that site, the function to strip namespaces follows with minor edits to the author's post (above) in order to fit the process into my app:

private function reportHistoryReceived( evt:ResultEvent ):void
{
var dsReport:XMLList; // the parent of the next var, below, in the SOAP result XML
var reportHistory:XMLList; // the XML list that contains the elements I ultimately want from the SOAP XML
var xml:XML; // the XML that will be 'cleaned' of namespaces
var item:XML; // the variable to be used in my for..each loop below
var respXML:XML; // the raw XML from the result event
var xmlSource:String; // the string representation of the response XML (respXML)
respXML = evt.result[0] as XML;
xmlSource = respXML.toXMLString();
xmlSource = xmlSource.replace(/<[^!?]?[^>]+?>/g, removeNamspaces); // will invoke the function detailed below
xml = XML(xmlSource); // take the cleaned XML string and parse it back to valid XML
dsReport = xml..*::DsReport; // grabbing the parent element of the returned data
reportHistory = dsReport.children(); // the specific items of data being returned from the Web Service
for each( item in reportHistory ) // looping over the reportHistory elements to act on them
{
trace( "XML Item Study: " + item.Study ); // ye ole boring trace statement :)
}
}
// the sweet little cleaner function from a User named: wvxvw (THANKS DUDE, OR DUDETTE!!!!)
private function removeNamspaces(...rest):String
{
rest[0] = rest[0].replace(/xmlns[^"]+\"[^"]+\"/g, "");
var attrs:Array = rest[0].match(/\"[^"]*\"/g);
rest[0] = rest[0].replace(/\"[^"]*\"/g, "%attribute value%");
rest[0] = rest[0].replace(/(<\/?|\s)\w+\:/g, "$1");
while (rest[0].indexOf("%attribute value%") > 0)
{
rest[0] = rest[0].replace("%attribute value%", attrs.shift());
}
return rest[0];
}

The first function, reportHistoryReceived is invoked when the Web Service returns its successful result. I've commented out the function, line by line, to explain what it's doing with each step.

There is one thing I wanted to point out for anyone out there, like me, who might be looking at the parameter of the removeNamespace function and wondering what the hell '...rest' is. Rather than try to explain it myself, I think the person below did an excellent job.

"The ...rest parameter is a special parameter placed at the end of a parameter list in a function that specifies that there can be any number of additional arguments of any type passed into that function when its called. The form of the parameter is 3 periods followed by a keyword. When the function is called, the additional arguments are assigned to that keyword in the form of an array."

-Source: Kirupa.com


I have somehow missed this little gem thus far in my Flex/AS3 life (not to mention other languages) but think it's a nice, little tool to add to our arsenals!

Comments

Craig Kaminsky
you may now download these files from S3
http://s3.amazonaws.com/oss-projects/namespace.remover.flex.app.zip
Anonymous
I wasted a week and finally found this post useful.
http://www.actionscript.org/forums/showthread.php3?t=162565
chaky
THANK YOU! THANK YOU! THANK YOU! THANK YOU!THANK YOU!THANK YOU! THANK YOU! THANK YOU! THANK YOU! THANK YOU! THANK YOU! THANK YOU! THANK YOU! THANK YOU! THANK YOU! THANK YOU! THANK YOU!

ADOBE IS SO STUPID! ADOBE IS SO STUPID! ADOBE IS SO STUPID! ADOBE IS SO STUPID! ADOBE IS SO STUPID! ADOBE IS SO STUPID! ADOBE IS SO STUPID! ADOBE IS SO STUPID! ADOBE IS SO STUPID! ADOBE IS SO STUPID! ADOBE IS SO STUPID!
shri
I am new to actionscript & was assuming that there is something wrong with how I was trying to parse the XML...But after countless hours of work, I found this article, copied the function & life is good. Thanks for sharing...
medford
Thank you very much Craig, I emailed you my code.
Craig Kaminsky
@Jeff: I'm on and offline a bit this weekend but please do feel free to post some code or email me the code, if that's easier/better for you. My email is craig.kaminsky at gmail dot com. I'll be checking back tomorrow in case you have time this weekend.

To try and answer your initial question in the comment, the function I have will return the XML document with all that namespace crap pulled out of it. So, if the root element of your XML document is 'reportHistory' then yes, that's essentially what you'll get back (reportHistory.someOtherElement.andSoOn.

Code will probably make it a lot easier to explain tho :)!
medford
Hi Craig,
I believe this post has ended my many hours/days of dealing with namespaces. I am doing a simple HTTPService request but what I am recieving back is a namespace nightmare - from your example above, after I pass the result through these functions, is reportHistory what I will be able to create as an XMLList that is bindable in Flex? Is that the finished result? Thank you again for this post, I could send a quick snippet of the XML I am working with if you a second to look at it. Thanks again.

-Jeff
Craig Kaminsky
@Gord: So glad to know that the cleaner class helped you out! Thank you very much for letting me know it helped.

Cheers, Craig
Anonymous
Craig,
You are so right. I fought for a day with namespace based XML in my Flex program. Finally stuffed in the removeNamspaces function into my program and life was easy again.

Cheers,
Gord