E5ca3abec062f8174570a4b1d1c840d8

I have an unformatted XML string I want to format. I want to do the traditional line breaks and indents on the tags (which XDocument provides beautifully), but the first tag has a lot of attributes, so I want to break on the attributes in the first tag too. The code I have here works, but it requires more gyrations then I would have expected. Curious if anyone has any suggestions . .. Using C#/.NET 3.5.

Example desired output:

<?xml version="1.0"?>
<Node1
Attribute1="value1"
Attribute2="value2"
Attribute3="value3">
<Node2>another value</Node2>
<Node3>another value</Node3>
<Node4>another value</Node4>
</Node1>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// The XDocument does the intenting and breaking at the tags fine.
var doc = System.Xml.Linq.XDocument.Parse(rawXml);
var msg = doc.ToString();
// Now I want to break the first line at the attributes
// So I get each line (breaking on the linebreak from XDocument
var lines = msg.Split(new string[] {Environment.NewLine}, StringSplitOptions.None);
var sb = new System.Text.StringBuilder();
if (lines.Count() > 0)
{
    // Take the first line and turn each space into a newline.
    lines[0] = lines[0].Replace(" ", Environment.NewLine + "    ");
}
// now I put all of them into a string builder
foreach (var line in lines)
{
    sb.AppendLine(line);
}
// and back into a single string.
msg = sb.ToString();   

Refactorings

No refactoring yet !

Ec72b0ab3eb1855c56fd04bcc886f65c

Jamie

June 18, 2010, June 18, 2010 13:34, permalink

1 rating. Login to rate!

I might be misunderstanding your intent here but why do it yourself when you can use the XmlWriter and XmlWriterSettings to specify a new line upon each attribute?

For a full list of formatting options see http://msdn.microsoft.com/en-us/library/system.xml.xmlwritersettings_properties.aspx

1
2
3
4
5
6
7
8
9
const string originalXmlStr = @"<?xml version=""1.0""?> <Node1 Attribute1=""value1"" Attribute2=""value2"" Attribute3=""value3""> 
<Node2>another value</Node2> <Node3>another value</Node3> <Node4>another value</Node4> </Node1>";

var doc = new XmlDocument();
doc.LoadXml(originalXmlStr);
var outputSettings = new XmlWriterSettings {NewLineOnAttributes = true, Indent = true};
using (var xmlWriter = XmlWriter.Create(@"output.xml", outputSettings)) {
  doc.Save(xmlWriter);
}
E5ca3abec062f8174570a4b1d1c840d8

JimMcKeeth

June 18, 2010, June 18, 2010 16:46, permalink

No rating. Login to rate!

Thanks Jamie, I knew there was an easier way. I originally was trying to remember the XmlWriter, but couldn't recall it. I really only wanted it to break for the attributes on the first node, but that works. I changed it to save the xml back to a string when it is done. Good stuff.

Example Input

1
<?xml version="1.0" encoding="utf-16"?><Node1 Attribute1="value1" Attribute2="value2" Attribute3="value3"><Node2 otherAttribute="other">another value</Node2><Node3>another value</Node3><Node4>another value</Node4></Node1>

C# Code

1
2
3
4
5
6
7
8
9
10
11
12
const string originalXmlStr = @"<?xml version=""1.0""?> <Node1 Attribute1=""value1"" Attribute2=""value2"" Attribute3=""value3""> 
    <Node2 otherAttribute=""other"">another value</Node2> <Node3>another value</Node3> <Node4>another value</Node4> </Node1>";

var doc = new XmlDocument();
doc.LoadXml(originalXmlStr);
var outputSettings = new XmlWriterSettings { NewLineOnAttributes = true, Indent = true };
var sb = new StringBuilder();
using (var xmlWriter = XmlWriter.Create(sb, outputSettings))
{
    doc.Save(xmlWriter);
}
var xml = sb.ToString();

Example Output

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="utf-16"?>
<Node1
  Attribute1="value1"
  Attribute2="value2"
  Attribute3="value3">
  <Node2
    otherAttribute="other">another value</Node2>
  <Node3>another value</Node3>
  <Node4>another value</Node4>
</Node1>

Your refactoring





Format Copy from initial code

or Cancel