I saw a recent post that expressed concern that a XMLSearch bug in ColdFusion MX 6/7 still has not been fixed in ColdFusion MX 7.01. I think its just a misunderstanding about how to reference namespaces, specifically the no-name namespace, and in fact there is no such bug.
Notice how two namespaces are defined: - xmlns="http://ns.r-xml.org/2004-08-02"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
Both of these namespaces are defined in the root element, BackgroundReports. Which namespace does the node BackgroundReports belong to? What namespace does IdValue belong to?
Now look at the following code:
<cfset currentDir = getDirectoryFromPath(ExpandPath('*.*'))>
<cffile action="read" file="#currentDir#/test.xml" variable="unparsedXmlDoc">
<cfset myXmlDoc = XMLParse(unparsedXmlDoc) />
<cfset myResults = XMLSearch(myXmlDoc,"/BackgroundReports/ProviderReferenceId/IdValue") />
<cfdump var="#myResults#">
And the output of the myResult search result from CFDUMP:
[array][empty]
The result of this is that the variable myResult contains an empty array object. The XPath Expression /BackgroundReports/ProviderReferenceId/IdValue did not match its intended target. This XPath expression qualifies the BackgroundReport node and its children as having no namespace.
However, the BackgroundReport node is in a namespace, the no-name namespace. Look again at just the root element. I've isolatd just the important part for clarity:
Notice how the xmlns="blah blah" namespace definition is lacking a namespace qualifier compared to this one which has a namespace qualifier foo, xmlns:foo="blah blah". When you define a namespace without a prefix qualifier, the element in which the namespace is defined belongs to that namespace unless you prefix that element. Got that? :)
The code example above failed because the XPath expression assumed that the target node was in no namespace at all, but instead it is in the no-name namespace. So how should the XPath expression be written to indicate the elements in the node are in the no-name namespace? Use just an empty colon, ":" .
/:BackgroundReports/:ProviderReferenceId/:IdValue
Here we are saying that we are searching for all elements IdValue that are in the noname namepsace by refering to it as :IdValue. But we have to declare the namespace of its parents namespaces too, so we end up with the expression /:BackgroundReports/:ProviderReferenceId/:IdValue.
Rewriting the code to use the improved XPath expression, we have the following:
<cfset currentDir = getDirectoryFromPath(ExpandPath('*.*'))>
<cffile action="read" file="#currentDir#/fekke.xml" variable="unparsedXmlDoc">
<cfset myXmlDoc = XMLParse(unparsedXmlDoc) />
<cfset myResults = XMLSearch(myXmlDoc,"/:BackgroundReports/:ProviderReferenceId/:IdValue") />
<cfdump var="#myResults#">
This produces the hoped for result which is the myResult variable populated with the matching IdValue node, which looks like this in CFDUMP:
[array]
[1][xml element]
[Xmlname][IdValue]
[XmlNsPrefix][]
[XmlNsURI][
http://ns.r-xml.org/2004-08-02]
[XmlText][204]
[XmlComment][]
[XmlAttributes][struct[empty]]
[XmlChildren][]
This was bug 59667 for CFMX 6.1, which I've recommended to be closed. I've added a comment to the XMLSearch LiveDoc and will propose a technote.