local-xpath-query

I often have to parse an XML Document to pull out element text when doing an integration with a third party system. I have used XPATH for these types of queries for years, but have always cringed when there were a lot of namespace declarations and prefixes used in the elements. Half of the time, these prefixes wouldn’t be declared or used properly and it would through off my XPATH query.

A few months ago I discovered a nice little XPath command that lets me ignore the namespace prefixes. Of course, XML evangelists would hang me up to dry if I ignored namespaces, but in all honesty, namespaces have never made a difference in my SOAP Responses or other XML data transfers. So, since this probably will work accurately for people in 99% of the use cases out there, I am making it my new favorite way to query an XML document using XPATH.

For example, if you wanted to access an XML document like the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<soapenv:Envelope xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
     <RetrieveContentResponse xmlns="urn:srm0">
          <returnval>
               <apiVersion>2.0</apiVersion>
               <srmApi type="SrmApi">SrmRecoveryApi1</srmApi>
               <protection type="SrmProtection">SrmProtection</protection>
               <recovery type="SrmRecovery">SrmRecovery</recovery>
               <about xmlns:vim25="urn:vim25">
                    <vim25:name>VMware vCenter Site Recovery Manager</vim25:name>
                    <vim25:fullName>
                         VMware vCenter Site Recovery Manager 5.0.0 build-474459
                    </vim25:fullName>
                    <vim25:vendor>VMware, Inc.</vim25:vendor>
                    <vim25:version>5.0.0</vim25:version>
                    <vim25:build>474459</vim25:build>
                    <vim25:localeVersion>INTL</vim25:localeVersion>
                    <vim25:localeBuild>000</vim25:localeBuild>
                    <vim25:osType>Windows</vim25:osType>
                    <vim25:productLineId>srm</vim25:productLineId>
                    <vim25:apiType>SiteRecovery</vim25:apiType>
                    <vim25:apiVersion>2.0</vim25:apiVersion>
               </about>
          </returnval>
     </RetrieveContentResponse>
</soapenv:Body>
</soapenv:Envelope>

You may want to get the contents of the “version” field, which in this case is “5.0.0”.

Since there is only one “version” element in the document, you may suppose that you could use an XPath statement of “//version”. However, this xpath statement doesn’t work with many XPATH query libraries probably due to some namespacing issues in the document.

One sure fire way to get an element in the document is to ignore namespaces altogether. In the grand scheme of things, ignoring namespaces is not often desired with big XML documents. However, for Web Service responses, you are usually pretty safe in doing so.

In order to ignore a namespace, you can use the following command:

*[local-name()='ELEMENT_NAME_GOES_HERE']

So, for example, if I wanted an easy way to get the version data from the XML document above, I could use any of the following XPATH statements (as well as other derivatives):

  • //*[local-name()=’version’]
  • /*/*/*/*/*/*[local-name()=’version’]
  • //*[local-name()=’about’]//*[local-name()=’version’]

The “local-name()” function offers a very convenient way to blow past any namespace errors/weirdness in an XML response to allow you to quickly identify an XML element.