XML.orgXML.org
FOCUS AREAS |XML-DEV |XML.org DAILY NEWSLINK |REGISTRY |RESOURCES |ABOUT
OASIS Mailing List ArchivesView the OASIS mailing list archive below
or browse/search using MarkMail.

 


Help: OASIS Mailing Lists Help | MarkMail Help

[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index]
Avoid writing special case code

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

 



[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index]


News | XML in Industry | Calendar | XML Registry
Marketplace | Resources | MyXML.org | Sponsors | Privacy Statement

Copyright 1993-2007 XML.org. This site is hosted by OASIS