I ABSOLUTELY HATE WORKING WITH XML.
Don't you have some library to use? I'm not exactly fond of it myself, but it's never been a pain to work with because there's such good support for it.
That's not the point, there's no such thing as elegant code whenever you have to work with XML, no matter what library you use IMO.
Have you used .NET 3.5+ LINQ-to-XML? It's as close to elegant as I've ever seen. I understand VB makes it even better (it's a native data type), though I've never used that. I like composing:
var doc = new XDocument(
new XDeclaration("1.0", "utf-8", null),
new XElement("Root",
new XElement("FirstLevelDeep",
new XElement("SecondLevelDeep",
new XAttribute("Value", 2)
)
)
)
);
produces:
<?xml version="1.0" encoding="utf-8" ?>
<Root>
<FirstLevelDeep>
<SecondLevelDeep Value="2" />
</FirstLevelDeep>
</Root>
Traversing it is really cool too, because you can apply LINQ operations to the traversals. For example, take my sample XML configuration file from JinxBot -
http://code.google.com/p/jinxbot/source/browse/trunk/development/projects/JinxBot/Configuration/SampleConfig.xmlHere's the code that reads it:
http://code.google.com/p/jinxbot/source/browse/trunk/development/projects/JinxBot/Configuration/ConfigurationLoader.cs#73That's a little complicated, but here are the details:
<JinxBotConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Globals>
...
</Globals>
<Profiles>
<ClientProfile ProfileName="DarkTemplar~AoA on useast.battle.net (Starcraft: Brood War)">
<Client>SEXP</Client>
<VersionByte>209</VersionByte>
<PrimaryCdKey>1111111111111</PrimaryCdKey>
<GameExePath>C:\Gamefiles\STAR\Starcraft.exe</GameExePath>
<StormDllPath>C:\Gamefiles\STAR\Storm.dll</StormDllPath>
<BattleSnpPath>C:\Gamefiles\STAR\Battle.snp</BattleSnpPath>
<Username>DarkTemplar~AoA</Username>
<LockdownImagePath>C:\Gamefiles\STAR\STAR.bin</LockdownImagePath>
<Password>password</Password>
<ServerUri>useast.battle.net</ServerUri>
<ServerPort>6112</ServerPort>
<CdKeyOwnerName>Robert Paveza</CdKeyOwnerName>
<Ping>Normal</Ping>
</ClientProfile>
...
</Profiles>
</JinxBotConfiguration>
This code gets the root element, JinxBotConfiguration:
document.Root
This then gets the single child "Profiles" element:
document.Root.Element("Profiles")
This then gets a generator which provides
foreach access over the internal "ClientProfile" elements:
document.Root.Element("Profiles").Elements("ClientProfile")
Then instead of iterating over it with a
foreach, I use a projection function, which converts it into a real class object:
document.Root.Element("Profiles").Elements("ClientProfile").Select(profile => CreateProfileFromElement(profile))
That expression yield an
IEnumerable<ClientProfile>, which can be
foreach'd over or turned into an array or whatever.
I think it's pretty cool...