tags:

views:

24

answers:

1

Hi,

I have an XML structure like the following:

<Root>
    <Base>
        <Greeting>Base Hello!</Greeting>
        <SpecialMessage>Base Special Message</SpecialMessage>

        <Products>
            <Product id="001">
                <Greeting>Base 001 Hello!</Greeting>
            </Product>
        </Products>
    </Base>

    <Buy>
        <Greeting>Buy Hello!</Greeting>
        <SpecialMessage>Buy Special Message</SpecialMessage>
        <Products>
            <Product id="001">
                <Greeting>Buy 001 Hello!</Greeting>
            </Product>
        </Products>
    </Buy>

    <Rent>
        <Greeting>Rent Hello</Greeting>
    </Rent>
</Root>

The Base, Buy and Rent nodes will always exist, but the nodes within them may or may not. At runtime, I'll determine if this is a Buy or Rent scenario. I also may or may not have a product id.

For example, if it's a buy scenario and the product id is "001", I'll get the "Buy 001 Hello" Message. However, if the Product section in the Buy section were to be missing for whatever reason, I'll return "Base 001 Hello".

A second example would be if I wanted to get the SpecialMessage for a Rent scenario. Since no SpecialMessage node is in the Rent section, I'll return "Base Special Message"

I assemble a list of XPaths like this, using Greeting as an example in a Buy scenario for product 001):

  1. /Root/Buy/Products/Product[id=001]/Greeting
  2. /Root/Base/Products/Product[id=001]/Greeting
  3. /Root/Buy/Greeting
  4. /Root/Base/Greeting

At the moment, I start at the top of the list, run the XPath, return the result if it's found, other wise move on to the next XPath and so on:

string result;
result = RunXPath(xpaths["Level1"], document);
if (!String.IsNullOrEmpty(result))
    return result;

result = RunXPath(xpaths["Level2"], document);
if (!String.IsNullOrEmpty(result))
    return result;

result = RunXPath(xpaths["Level3"], document);
if (!String.IsNullOrEmpty(result))
    return result;

result = RunXPath(xpaths["Level4"], document);
if (!String.IsNullOrEmpty(result))
    return result;

return String.Empty;

While it works, it seems awkward and a little rough to read. Are there better approaches, in terms of readability?

A: 

One option is to create a collection of paths, and iterate over it:

string[] paths = {"Level1", "Level2", "Level3", "Level4"};
foreach(string path in paths)
{
    result = RunXPath(xpaths[path], document);
    if (!String.IsNullOrEmpty(result))
        return result;
}
return "";

Generally, if you find yourself write repeated code, you should consider using a loop or a method (or both!).
Also, try not to use the same variable for different things. Go for meaningful names - it will help readability, and help detect errors. This is less offending in your senarion, but important enough. Consider:

result = RunXPath(xpaths["/document/my:things/rooms[0]/floor"], document);
Print(result);
result = RunXPath(xpaths["/document/my:things/roomate/phone/mobile"], document);
Print(result);

I recently had to debug code exactly like that, and refactored it to:

string floor = RunXPath(xpaths["/document/my:things/rooms[0]/floor"], document);
Print(floor);
string friendMobilePhone = RunXPath(xpaths["/document/my:things/roomate/phone/mobile"], document);
Print(friendMobilePhone);
Kobi