Hi Folks, “Avoid special case code”. Linus Torvalds calls this “good taste”: Sometimes you can see a problem in a different way and rewrite it so that a special case goes away and becomes the normal case. That’s good code. The sign of people that I really want to work with are they have
good taste. Good taste is about seeing the big patterns and instinctively knowing what is the right way of doing things. [Linus Torvalds] Recently I encountered a situation which seemed to require special case code, but Linus’s words haunted me, so I was determined to avoid it. Thankfully, the excellent people on the xsl-list showed me how. Here is the situation that I was dealing with: My XML document contains a bunch of <Row> elements, like so: <Document> ... <Row> <Cell> <Data>airport</Data> </Cell> <Cell> <Data>airports</Data> </Cell> </Row> ... </Document> I want to fetch the Row whose Cell[1]/Data is 'airport' and whose Cell[2]/Data is 'airports'. So I created this XPath expression: /Document/Row[Cell[1]/Data eq 'airport'][Cell[2]/Data eq 'airports'] I do this kind of fetching operation often, so I created a function to fetch the desired Row: <xsl:function name="f:getRow"> <xsl:param name="element"/> <xsl:param name="parent"/> <xsl:sequence select="$document/Row[Cell[1]/Data eq $element][Cell[2]/Data eq $parent]" /> </xsl:function> I call the function this way: <xsl:sequence select="f:getRow('airport', 'airports')" /> Sometimes there is an element that doesn't have a parent. That is, sometimes I'd like to fetch a Row in which Cell[2] is empty, like this: <Row> <Cell> <Data>aviation</Data> </Cell> <Cell/> </Row> Then this call to f:getRow fails: <xsl:sequence select="f:getRow('aviation', '')" /> <!-- Those are two apostrophes within the parentheses --> Clearly I need to modify f:getRow. I could add special case code to test $parent to see if it is empty and do one thing, and if it's not empty do another thing. But I wonder if there is a more elegant solution that doesn't involve special
case code? Is there a way to modify the XPath expression in f:getRow such that it fetches the correct Row regardless of whether $parent is empty or not? Mukul Gandhi showed me how to do it. Change the XPath from this: $document/Row[Cell[1]/Data eq $element][Cell[2]/Data eq $parent] to this: $document/Row[Cell[1]/Data eq $element][Cell[2]/string(Data) eq $parent] Notice the tiny change: from Data to string(Data). That small change avoids special case code! You might wonder: why does string(Data) work but Data doesn’t? Wendell Piez explained: The step 'string(Data)', in the absence of a Data node, will return '' since string(()) (a string value of nothing) is an empty string. With an XPath expression containing just Data, the failure of the path to reach any node at Data results in the comparison () eq '' which fails. /Roger |