My post addresses a specific need related to the OP's inquiry, but not specifically what the OP asked. I love both Regex and recursion when I need them, but in this case I think the goal of the OP's inquiry was to learn a way to generate properly-formatted XML output, and what I've provided below does exactly that with no heavy contextual source development (why reinvent the wheel?) and is supported in back in the .NET 2.0 framework.
In my work, I often end up supporting modern government systems. Those systems often still only support up through 2.0 on deployment systems -- primarily for reasons of security. The 2.0 Framework lacks some of the graceful output of more recent .NET editions, particularly where XML objects are concerned. The fully validated method-set below has been valuable and time-saving to me and I offer it for unseen developer comrades who also service government interests.
Additionally you can also utilize LinqBridge libraries for limited Linq support (.NET up through 3.5 service-pack actually internally self-evaluates to 2.0 so LinqBridge was constructed to bridge that specific gap (limited Linq query support while developing to 2.0 build while using Visual Studio 2008). However, note that LinqBridge is currently not supported forward of Visual Studio 2008.
In order to minimize package publish-sizes and also stay compatible with the organizational requirements where I provide my services I avoid using associative non-XML libraries (such as Regex) for parsing XML and stick to standard XML objects. Specifically the older Xml*-prefix objects vs the more modern (and much more flexible) X*-prefix objects...
Below I provide numerous safe, simple, efficient methods that generate formatted XML from an assortment of standard 2.0 Xml* objects. Also note that the workhorse for these functions is really the XPathNavigator class, not it's cousins.
Here is a C# code fragment that calls the sample methods:
doc = new XmlDocument();
doc.Load(Input_FilePath);
sb = StringBuilderFromXmlDocument(doc);
Out(sb);
sb = StringBuilderFromXPathDocument(new XPathDocument(Input_FilePath));
Out(sb);
sb = StringBuilderFromXPathNavigator(new XPathDocument(Input_FilePath).CreateNavigator());
Out(sb);
ss = StringFromXmlDocument(doc);
Out(ss);
ss = StringFromXPathDocument(new XPathDocument(Input_FilePath));
Out(ss);
ss = StringFromXPathNavigator(new XPathDocument(Input_FilePath).CreateNavigator());
Out(ss);
and here are the sample methods, one of which will likely suffice your XML formatting needs:
public static StringBuilder StringBuilderFromXmlDocument(XmlDocument _xd)
{
XPathNavigator _xpn;
try
{
_xpn = _xd.CreateNavigator();
}
catch
{
_xd.LoadXml(DEFAULT_ERROR_TEXT);
_xpn = _xd.CreateNavigator();
}
return StringBuilderFromXPathNavigator(_xpn);
}
private static StringBuilder StringBuilderFromXPathDocument(XPathDocument _xpd)
{
StringBuilder returnVal = new StringBuilder();
XPathNavigator _xpn;
try
{
_xpn = _xpd.CreateNavigator();
returnVal.AppendLine(_xpn.OuterXml.Trim());
}
catch
{
returnVal = new StringBuilder()
.Append(DEFAULT_ERROR_TEXT);
}
return returnVal;
}
private static StringBuilder StringBuilderFromXPathNavigator(XPathNavigator _xpn)
{
StringBuilder returnVal = new StringBuilder();
try
{
returnVal.AppendLine(_xpn.OuterXml.Trim());
}
catch
{
returnVal = new StringBuilder()
.Append(DEFAULT_ERROR_TEXT);
}
return returnVal;
}
public static string StringFromXmlDocument(XmlDocument _xd)
{
XPathNavigator _xpn;
try
{
_xpn = _xd.CreateNavigator();
}
catch
{
_xd.LoadXml(DEFAULT_ERROR_TEXT);
_xpn = _xd.CreateNavigator();
}
return StringFromXPathNavigator(_xpn);
}
private static string StringFromXPathNavigator(XPathNavigator _xpn)
{
string returnVal;
try
{
returnVal = _xpn.OuterXml.Trim();
}
catch
{
returnVal = DEFAULT_ERROR_TEXT;
}
returnVal = _xpn.OuterXml.Trim();
return returnVal;
}
private static string StringFromXPathDocument(XPathDocument _xpd)
{
string returnVal;
XPathNavigator _xpn;
try
{
_xpn = _xpd.CreateNavigator();
returnVal = _xpn.OuterXml.Trim();
}
catch
{
returnVal = DEFAULT_ERROR_TEXT;
}
return returnVal;
}
enjoy. ^^
Note that in later Framework editions and using newer XElement objects you can foreach(){} the XElement's nodes and .ToString() each result for automated proper formatting. Like I said above, much more graceful :).