I haven't found a way using .NET's XmlWriter and associated XmlWriterSettings to format an XML string in indented form exactly the way that Visual Studio does it with its auto-format command (Ctrl-E Ctrl-D, or, depending on keyboard mapping, Ctrl-K Ctrl-D).
I would like to do this because I habitually auto-format all my files in VS, both code and .config files. I have an installer app that updates .config files, and I would like to see actual diffs instead of the entire document changed.
I haven't explored all the different formatting options for auto-format, but I like each XML attribute to be on a separate line, with the first on the same line as the opening tag and subsequent ones lined up with the first, like this:
<asset assetId="12345"
bucket="default"
owner="nobody">
<file path="\\localhost\share\assetA.mov"/>
<metadata metadataId="23456"
key="asset_type"
value="video"/>
</asset>
I've tried formatting with XmlWriterSettings properties 'NewLineHandling = NewLineHandling.None' and 'NewLineOnAttributes = true', but that puts the first attribute below the opening tag and all attributes have the same indentation regardless of the # of characters in the element name, like this:
<asset
assetId="12345"
bucket="default"
owner="nobody">
<file
path="\\localhost\share\assetA.mov" />
<metadata metadataId="23456"
key="asset_type"
value="video" />
</asset>
Notice that the standard XmlWriter also ends attribute-only elements with " />" (extra space before the slash), which I dislike but not sure if that's the XML standard. I would think that Visual Studio uses the same API options readily available to developers, but I've yet to find those magical settings. Anyway, here's my format method:
public static string FormatXml( string xmlString, bool indented )
{
using ( TextReader textReader = new StringReader( xmlString ) )
using ( XmlReader xmlReader = new XmlTextReader( textReader ) )
{
using ( TextWriter textWriter = new StringWriter() )
{
var settings = new XmlWriterSettings();
if ( indented )
{
settings.Indent = true;
settings.IndentChars = " ";
settings.NewLineOnAttributes = true;
settings.NewLineHandling = NewLineHandling.None;
}
using ( var xmlWriter = XmlWriter.Create( textWriter, settings ) )
{
while ( xmlReader.Read() )
xmlWriter.WriteNode( xmlReader, false );
}
return textWriter.ToString();
}
}
}