VMware Cloud Community
TimLawrence
Enthusiast
Enthusiast

E4X XML Parsing - Namespace Declarations

Hi all,

Doing quite a bit of Orchestration with vCloud etc at the moment.

I have just started using E4X for XML queries etc. I find it pretty easy to use if a little poorly documented..

In vCloud object's XML representation include a large number of different namespaces and I have found it pretty annoying trying to declare them all.

consider the following:

sXML = "<parent><vmext:EntityLink rel="up" type="vcloud:org" name="System" id="urn:vcloud:org:a93c9db9-7471-3192-8d09-a8f7eeda85f9"/></parent>"

Now, say I want to return the EntityLink element from this:

oXML = XML(sXML);

System.log(oXML.vmext::EntityLink)

would return something like "vmext undefined"

This is because we have not declared aliases for the namespaces.

Namespace alias' can be declared thusly:

var vmext = new Namespace("http://urlofnamespace...");

The problem comes when we are looking at XMLDocs with large numbers of namespaces (vCloud often uses the format ns1: ns2: etc..)

A well formed XML document will declare these Namespaces internally via the xmlns attributes. These are automatically added to the XML object when it is constructed and can be retrieved via:

XML.namespaceDeclarations() -> returns an aray of http urls

Unfortunately I could not find a way of returning the aliases for these namespaces directly from the XML object so I wrote the following function which works but is rather ugly in my opinion:

function DeclareNS(xmlstring){

     var nsNames = xmlstring.match(/xmlns:?[^\s]+/g);

     var xOut = new XML(xmlstring);

     for (var i=0,iMax=nsNames.length;i<iMax;i++){

          var nUrl = nsNames[i].split("=")[1];

          var aName = nsNames[i].split("=")[0].split(":");

          if (aName.length == 2){

               var nName = aName[1];

               eval("this."+nName +"= new Namespace("+nUrl+")");

               System.log("Creating Namespace Definition: "+nName+"="+nUrl);

          }else{

               default xml namespace = nUrl;

               System.log("Setting Default Namespace: "+nUrl);

          }

     }

     return xOut;

}

xDoc = DeclareNS(msgBody);

This will Declare ALL namespaces referenced by an xmlns attribute in the document and return a constructed XML Object. All we now need to do is call DeclareNS each time we need a new XML object (from string) and we can write nice E4X queries to access the data we need.

Anyway, I hope that is useful to someone. I would love to hear from you if you have suggestions on how to declare Namespaces easier!!

0 Kudos
6 Replies
cdecanini_
VMware Employee
VMware Employee

If you have the namespaces declaration in the XML wouldn't this work ?

default xml namespace = oXML.namespace();

I was surprised to see that oXML = XML(sXML) works. I have always used oXML = new XML(sXML);

If my answer resolved or helped you, please mark it as Correct or Helpful to award points. Thank you! Visit http://www.vcoteam.info & http://blogs.vmware.com/orchestrator for vCenter Orchestrator tips and tutorials - @vCOTeam on Twitter
0 Kudos
TimLawrence
Enthusiast
Enthusiast

as far as I know that only allows access to the default namespace. I may very well be wrong though so I will test and check.

0 Kudos
cdecanini_
VMware Employee
VMware Employee

You may be right since I remember having to use .*:: to get access to the elements.

If my answer resolved or helped you, please mark it as Correct or Helpful to award points. Thank you! Visit http://www.vcoteam.info & http://blogs.vmware.com/orchestrator for vCenter Orchestrator tips and tutorials - @vCOTeam on Twitter
0 Kudos
TimLawrence
Enthusiast
Enthusiast

Yep, just tested and default xml namespace = oXML.namespace(); unfortunately doesnt work.

Also noticed there are some issues with the above function.

It seems that namespace declarations can be xmlns= or xmlns:ns= so need to re-do the regex

Will post back in a bit.

0 Kudos
TimLawrence
Enthusiast
Enthusiast

Ok,

I have updated it now. If it finds a namepace attribute without a : it declares it as the default namespace (I presume that is what it should be)

I dont think there will ever be more than one of these but if there are then only the last one found will be set.

Just tested it on a vCloud Task XML Doc and it set 7 NS* aliases plus 1 default.

Seems to work quite well 🙂

Hope it works for someone else too.

Tim

0 Kudos
cdecanini_
VMware Employee
VMware Employee

I did something similar using   namespaceDeclarations();

default xml namespace = xml.namespace();

var namespaceDeclarations = xml.namespaceDeclarations();

for each (var namespaceDeclaration in namespaceDeclarations) {
    //xml.removeNamespace(namespaceDeclaration);
    if (namespaceDeclaration.prefix.length >0) {
        System.log(namespaceDeclaration.prefix + ' = new Namespace("' + namespaceDeclaration.uri + '");');
        eval(namespaceDeclaration.prefix + ' = new Namespace("' + namespaceDeclaration.uri + '");');
    }

   
}

Christophe.

If my answer resolved or helped you, please mark it as Correct or Helpful to award points. Thank you! Visit http://www.vcoteam.info & http://blogs.vmware.com/orchestrator for vCenter Orchestrator tips and tutorials - @vCOTeam on Twitter
0 Kudos