Thursday, September 28, 2006

XPath Trick: Count() Function

For those who use XML to mark up their data, you're probably used to seeing statements such as the one below, that returns a set of nodes that each have a specified child node as per the criteria:
"/root/record[lastname]"
This would return all record nodes that are children of the root node, but only if they have a lastname child node. If there are any record nodes that don't have lastname children, they won't be returned in the resulting nodeset.


But what if rather than search for nodes that have a certain child node, you want to search for all nodes that don't have that child node? For instance, recently I worked on a project where a last-minute change was applied to the specs, where a certain record only applied to one set of data, but not the others.

The thing was, they wanted a side-by-side comparison between these data sets, and the design called for showing the record in the relevant set and showing blank data cells for the other sets. Also, each data set could be viewed individually, and they wanted it to not show in the other data sets.

So I had an interesting problem. I needed a way to extensibly tag that particular record to indicate that it only applied to the one data set. I knew that I could set up a node named something like "includethis" in every other record, but that seemed like overkill. It would be much simpler to do an XPath query similar to:
"/root/record[!excludethis]"
i.e. Return all nodes that don't have the excludethis child node. But that particular syntax doesn't exist in XPath, so I had to find another way. Luckily the answer turned out to be pretty simple.

The standard XPath functions include a Count(node-set) function, that returns an integer. So for instance, if you used something like:
"Count(/root)"
you should always get a result of 1, because you can only have one root node in your XML tree. So the answer to my exclusion problem is as such:
"/root/record[Count(excludethis)=0]"
Which does exactly what I want: only return record nodes where the number of excludethis children is 0, i.e. there aren't any. This way, I only need to tag the one record, and I can leave all of the others alone.

If you know any other snazzy XPath tricks, feel free to leave them in the Comments!

1 Comments:

At 9:44 AM, Anonymous Anonymous said...

Thanks, that was exactly what I needed!

 

Post a Comment

<< Home