Multiple Namespaces in an XML Document
In some cases, your data might contain more than one NameSpaceURI. This can be easily handled. The only difference is that you need to know how namespaces are defined and how they are associated with elements.
When you parse data, you often search for elements by name. To do this, you need to know the expanded name of elements. The expanded name consists of the element's NameSpaceURI and the element's BaseName. When you search, you will pass the expanded name as two parameters: NameSpaceURI and BaseName.
So how do you know what the NameSpaceURI and BaseName values are? There are several ways to do this, but a good approach is to look at the XML data returned and figure it out. Let's provide some examples.
Elements with Prefixes
In some cases, you will have a prefix in the element. Assume we have the following:
<m:Orders>
<m:Order>
<m:OrderNo>1</m:OrderNo>
<m:CustomerNo>99</m:CustomerNo>
</m:Order>
</m:Orders>
To figure out what the BaseNames are, just ignore all of the prefixes (m:). In this case, we've got four elements: Orders, Order, OrderNo, and CustomerNo. Since the prefix for all of these elements is m:, we need to find the NameSpaceURI associated with this prefix. Starting at the element, search for an attribute xmlns:m and use its value. In this case, that would be http://DataAccess.com/webservices/. The expanded names of these elements are:
http://DataAccess.com/webservices/ + Orders
http://DataAccess.com/webservices/ + Order
http://DataAccess.com/webservices/ + OrderNo
http://DataAccess.com/webservices/ + CustomerNo
You'd code this as follows:
Get DocumentElement of hoXML to hoRoot
Get ChildElementNS of hoRoot "http://DataAccess.com/webservices/" "Order" to hoOrder
Get ChildElementValueNs of hoOrder "http://DataAccess.com/webservices/" "OrderNo" to sOrderNo
Get ChildElementValueNs of hoOrder "http://DataAccess.com/webservices/" "CustomerNo" to sCustomerNo
Send destroy of hoOrder
You'd be more likely to code this as follows:
Move "http://DataAccess.com/webservices/" to sNS
Get DocumentElement of hoXML to hoRoot
Get ChildElementNS of hoRoot sNS "Order" to hoOrder
Get ChildElementValueNs of hoOrder sNS "OrderNo" to sOrderNo
Get ChildElementValueNs of hoOrder sNS "CustomerNo" to sCustomerNo
Send destroy of hoOrder
Elements without Prefixes
In some cases, you will not have a prefix in the element. When that happens, you are using a default namespace identified with an attribute called xmlns= or, if there is no attribute, the global namespace is used (""). If you find the xmlns= attribute, you have an element with a default namespace. If you don't find the attribute, you have an element in the global workspace.
Elements with Default Namespaces
Assume we have the following:
<Orders>
<Order>
<OrderNo>1</OrderNo>
<CustomerNo>99</CustomerNo>
</Order>
</Orders>
Since there are no prefixes, the BaseNames are the element names: Orders, Order, OrderNo, and CustomerNo. To figure out what the NameSpaceURI is, search for an attribute xmlns= and use its value. In this case, that would be http://DataAccess.com/webservices/. The expanded names of these elements are:
http://DataAccess.com/webservices/ + Orders
http://DataAccess.com/webservices/ + Order
http://DataAccess.com/webservices/ + OrderNo
http://DataAccess.com/webservices/ + CustomerNo
You'd code this as follows:
Move "http://DataAccess.com/webservices/" to sNS
Get DocumentElement of hoXML to hoRoot
Get ChildElementNS of hoRoot sNS "Order" to hoOrder
Get ChildElementValueNs of hoOrder sNS "OrderNo" to sOrderNo
Get ChildElementValueNs of hoOrder sNS "CustomerNo" to sCustomerNo
Send destroy of hoOrder
The above two examples represent the same XML document data!
Elements with no Default Namespaces (Global Namespace)
Assume we have the following:
<Orders>
<Order>
<OrderNo>1</OrderNo>
<CustomerNo>99</CustomerNo>
</Order>
</Orders>
Since there are no prefixes, the BaseNames are the element names: Orders, Order, OrderNo, and CustomerNo. To figure out what the NameSpaceURI is, search for an attribute xmlns= and use its value. Since this can't be found, the namespace is global (""). The expanded names of these elements are:
"" + Orders
"" + Order
"" + OrderNo
"" + CustomerNo
You'd code this as follows:
Move "" to sNS
Get DocumentElement of hoXML to hoRoot
Get ChildElementNS of hoRoot sNS "Order" to hoOrder
Get ChildElementValueNs of hoOrder sNS "OrderNo" to sOrderNo
Get ChildElementValueNs of hoOrder sNS "CustomerNo" to sCustomerNo
Send destroy of hoOrder
Documents with Multiple Namespaces
A document may contain a mix of prefixes and namespaces. When this happens, you apply the same rules as above on an element-by-element basis.
- For each element, check to see if it has a prefix.
- If it does have a prefix, search for the attribute
xmlns:ns=that defines the namespace for that prefix. - If it does not have a prefix, look for an attribute that defines a default namespace (
xmlns=). If no namespace is found, theNameSpaceis global. - Parse the element using the
NameSpaceURIand theBaseName.
Do this for every element.
For example:
<m:Orders xmlns:m="http://DataAccess.com/Customers/">
<m:Order>
<m:OrderNo>1</m:OrderNo>
<m:CustomerNo>99</m:CustomerNo>
</m:Order>
</m:Orders>
We have the following elements with the following expanded names:
http://DataAccess.com/webservices/ + Orders
http://DataAccess.com/webservices/ + Order
http://DataAccess.com/webservices/ + OrderNo
http://DataAccess.com/Customers/ + Customer
http://DataAccess.com/Customers/ + CustomerNo
http://DataAccess.com/Customers/ + CustomerName
You'd code this as follows:
Move "http://DataAccess.com/webservices/" to sNS1
Move "http://DataAccess.com/Customers/" to sNS2
Get DocumentElement of hoXML to hoRoot
Get ChildElementNs of hoRoot sNS1 "Order" to hoOrder
Get ChildElementValueNs of hoOrder sNS1 "OrderNo" to sOrderNo
Get ChildElementNs of hoOrder sNS2 "Customer" to hoCust
Get ChildElementValueNs of hoCust sNS2 "CustomerNo" to sCustomerNo
Get ChildElementValueNs of hoCust sNS2 "CustomerName" to sName
Send destroy of hoCust
Send destroy of hoOrder
Consider the following two XML documents. These represent the same data. Since the documents are the same, the code example shown above will be applied to all of these documents.
In this case, we apply prefixes to all elements:
<m:Orders xmlns:m="http://DataAccess.com/Customers/">
<m:Order>
<m:OrderNo>1</m:OrderNo>
<m:CustomerNo>99</m:CustomerNo>
</m:Order>
</m:Orders>
In this case, we reverse the prefix names:
<Orders xmlns="http://DataAccess.com/Customers/">
<Order>
<OrderNo>1</OrderNo>
<CustomerNo>99</CustomerNo>
</Order>
</Orders>
This final example mixes three namespaces. This document has three elements with the same BaseName (State) and it mixes namespaces throughout the document. You will never see a real document like this. In a situation like this, you do not need to try to understand why the document was created this way. Whoever designed the service and the schema made the decision. All you need to worry about is using the service.
<Orders xmlns:m="http://DataAccess.com/webservicesOrders/" xmlns:x="">
<Order>
<OrderNo>1</OrderNo>
<CustomerNo>99</CustomerNo>
<State>CA</State>
<State>Angry</State>
<State>Yes</State>
</Order>
</Orders>
We have the following elements with the following expanded names:
http://DataAccess.com/webservices/ + Orders
"" + Order
http://DataAccess.com/webservices/ + OrderNo
http://DataAccess.com/webservicesOrders/ + Customer
http://DataAccess.com/webservicesOrders/ + CustomerNo
"" + State
http://DataAccess.com/webservicesOrders/ + State
http://DataAccess.com/webservices/ + State
You'd code this as follows:
Move "http://DataAccess.com/webservices/" to sNS1
Move "http://DataAccess.com/webservicesOrders/" to sNS2
Move "" to sNS3
Get DocumentElement of hoXML to hoRoot
Get ChildElementNs of hoRoot sNS3 "Order" to hoOrder
Get ChildElementValueNs of hoOrder sNS1 "OrderNo" to sOrderNo ---> 1
Get ChildElementNs of hoOrder sNS2 "Customer" to hoCust
Get ChildElementValueNs of hoCust sNS2 "CustomerNo" to sCustomerNo ---> 99
Get ChildElementValueNs of hoCust sNS3 "State" to sRegion ---> CA
Get ChildElementValueNs of hoCust sNS2 "State" to sStateOfMind ---> Angry
Get ChildElementValueNs of hoCust sNS1 "State" to sMaintainsState ---> Yes
Send destroy of hoCust
Send destroy of hoOrder
If this makes sense, you know how to parse XML documents with namespaces.