Using Coldfusion 8 and XMLSearch() I am trying to build a XPath() statment that will find the occurance of specific children of a parent.
I have parents combinationCharts
who can have children of bar
or line
or both. I need to be able to find the three combinations of bar no line
; line no bar
; or bar and line
I've tried several iterations of
<cfset myBarLineChart = XMLSearch(cleanedXML, "//*[descendant::combinationChartTypes][contains(name(),'bar') and contains(name(),'line')]" )>
Using different combinations of descendant
or child
or //*
etc. Somehow, I just can't find the magic order to get any results.
The ones that work are:
<cfset myBarChart = XMLSearch(cleanedXML, "//*[name()='combinationChartTypes']//*[name()='bar']")>
<cfset myLineChart = XMLSearch(cleanedXML, "//*[name()='combinationChartTypes']//*[name()='line']")>
But the problem is they double count when a combinationChartTypes
has both bar
and line
I've tried solutions from:
Recursive Query of XML in ColdFusion 8 to find unknown number of children sub levels
Is it possible in XPath to find parent when none of the children met some criteria
All to no avail, even after reading and re-reading over: http://www.w3schools.com/xpath/xpath_axes.asp
http://zvon.org/comp/r/tut-XPath_1.html#Pages~List_of_XPaths
Any help to point me in the right direction or to solve this outright would be much appreciated!
Here is the sample xml that I'm searching over:
<?xml version="1.0" encoding="UTF-8"?>
<report expressionlocale="en" ignorefiltercontext="false" xmlns="http://www.w3.org/1999/xhtml"><reportName>Revenue by GO Subsidiary 2005</reportName>
...
<!--- Example of line chart only --->
<combinationChartTypes>
<line bordercolor="black" datapointsize="4" pointchartdatapointshape="verticalLine" showabsolutevalues="true" showborders="false" showline="false" showvalues="false" usenumericalaxis="numericalAxisY1" valuetype="absolute">
<chartNodes>
<chartNode>
<chartNodeMembers>
<chartNodeMember refdataitem="Example of line chart only">
<chartContents>
<chartTextItem>
<dataSource>
</dataSource>
</chartTextItem>
</chartContents>
</chartNodeMember>
</chartNodeMembers>
</chartNode>
</chartNodes>
</line>
</combinationChartTypes>
...
<!--- Example of bar chart only --->
...
<combinationChartTypes>
<bar>
<chartNodes>
<chartNode>
<chartNodeMembers>
<chartNodeMember refdataitem="Example of bar chart only">
<chartContents>
<chartTextItem>
<dataSource>
</dataSource>
<conditionalDataSources refvariable="Report Language1">
<conditionalDataSource refvariablevalue="de">
<staticValue>Einnahmen (Millionen)</staticValue>
</conditionalDataSource>
<conditionalDataSource refvariablevalue="fr">
<staticValue>Revenus (millions)</staticValue>
</conditionalDataSource>
</chartTextItem>
</chartContents>
</chartNodeMember>
</chartNodeMembers>
</chartNode>
</chartNodes>
</bar>
</combinationChartTypes>
...
<!--- Example of bar and line chart mixed --->
...
<combinationChartTypes>
<bar>
<chartNodes>
<chartNode>
<chartNodeMembers>
<chartNodeMember refdataitem="example of bar and line chart mixed">
<chartContents>
<chartTextItem>
<dataSource>
</dataSource>
<conditionalDataSources refvariable="Report Language1">
<conditionalDataSource refvariablevalue="de">
<staticValue>Einnahmen (Millionen)</staticValue>
</conditionalDataSource>
<conditionalDataSource refvariablevalue="fr">
<staticValue>Revenus (millions)</staticValue>
</conditionalDataSource>
</chartTextItem>
</chartContents>
</chartNodeMember>
</chartNodeMembers>
</chartNode>
</chartNodes>
</bar>
<line bordercolor="black" datapointsize="4" pointchartdatapointshape="verticalLine" showabsolutevalues="true" showborders="false" showline="false" showvalues="false" usenumericalaxis="numericalAxisY1" valuetype="absolute">
<chartNodes>
<chartNode>
<chartNodeMembers>
<chartNodeMember refdataitem="Same quarter, 2004">
<chartContents>
<chartTextItem>
<dataSource>
</dataSource>
</chartTextItem>
</chartContents>
</chartNodeMember>
</chartNodeMembers>
</chartNode>
</chartNodes>
</line>
</combinationChartTypes>
...
</report>
If you want the full long-ugly form of the file that is being searched it is here: http://jsfiddle.net/asheppardwork/3uuaj5jb/
You are missing the default namespace (xmlns="http://www.w3.org/1999/xhtml"
). (The fact that your XML is in the XHTML namespace without actually being XHTML is rather suspicious. I assume its creation process is broken. If you any influence on that, I suggest you start there.)
During standard XPath 1.0 use, searching for //combinationChartTypes
will only turn up <combinationChartTypes>
nodes that are in no namespace.
But you don't have any of those.
Now usually you would register the namespace URIs you need before you can use them in XPath, but ColdFusion 8 does not provide a way to do that. (If it would, you could register http://www.w3.org/1999/xhtml
as xhtml
and then query for "//xhtml:combinationChartTypes"
.)
XmlSearch()
automagically supports namespace prefixes that are in the XML source:
<doc xmlns:foo="http://foo">
<foo:element />
</doc>
and
<cfset result = XmlSearch(doc, "//foo:element")>
will return something. However, this is not the case for XML with a default namespace (i.e., no prefix).
In that case you can still fall back to this much more cumbersome pattern:
<cfset path = "//*[local-name() = 'combinationChartTypes' and *[local-name() = 'bar'] and not(*[local-name() = 'line'])]">
<cfset myBarChart = XMLSearch(cleanedXML, path)>
or, as a dirty hack, you could get away with XmlParse(Replace(xml, 'xmlns="namespace-uri-in-question"', ''))
and then use XmlSearch()
normally on the now namespace-less XML.