Reputation: 4605
I am writing an XML file using XDocument
. I want to make adjustments to the file layout. Let me explain, here is an extract of the generated file:
<ROOTELEMENT>
<CHILDELEMENT>
<INFO1>Test a 1</INFO1>
<INFO2>Test a 2</INFO2>
</CHILDELEMENT>
<CHILDELEMENT>
<INFO1>Test b 1</INFO1>
<INFO2>Test b 2</INFO2>
</CHILDELEMENT>
<ROOTELEMENT>
I want my file to look like this instead :
<ROOTELEMENT>
<CHILDELEMENT><INFO1>Test a 1</INFO1><INFO2>Test a 2</INFO2></CHILDELEMENT>
<CHILDELEMENT><INFO1>Test b 1</INFO1><INFO2>Test b 2</INFO2></CHILDELEMENT>
</ROOTELEMENT>
Here is my code:
var myDoc = new XDocument(new XElement("ROOTELEMENT",
new XElement("CHILDELEMENT",
new XElement("INFO1", "Test a 1"),
new XElement("INFO2", "Test a 2")),
new XElement("CHILDELEMENT",
new XElement("INFO1", "Test b 1"),
new XElement("INFO2", "Test b 2"))));
myDoc.Save("Test.xml");
Upvotes: 2
Views: 604
Reputation: 116876
Formatting of XML output is controlled by XmlWriter
not XElement
or XDocument
, so if you need precise control of formatting you will need to create your own writer by subclassing one of the implementations of XmlWriter
, specifically XmlTextWriter
whose Formatting
property is mutable and can be changed during writing.
For instance, here is a version that disables indentation when the element depth exceeds 1:
public class CustomFormattingXmlTextWriter : XmlTextWriter
{
readonly Stack<Formatting> stack = new Stack<Formatting>();
public CustomFormattingXmlTextWriter(TextWriter writer, int indentDepth) : base(writer)
{
this.Formatting = Formatting.Indented;
this.IndentDepth = indentDepth;
}
int IndentDepth { get; }
void OnElementStarted(string localName, string ns)
{
stack.Push(Formatting);
// You could e.g. modify the logic here to check to see whether localName == CHILDELEMENT
// if (localName == "CHILDELEMENT")
if (stack.Count == IndentDepth+1)
Formatting = Formatting.None;
}
void OnElementEnded()
{
var old = stack.Pop();
if (old != Formatting)
Formatting = old;
}
public override void WriteStartElement(string prefix, string localName, string ns)
{
base.WriteStartElement(prefix, localName, ns);
OnElementStarted(localName, ns);
}
public override void WriteEndElement()
{
base.WriteEndElement();
OnElementEnded();
}
public override void WriteFullEndElement()
{
base.WriteEndElement();
OnElementEnded();
}
}
public static partial class XNodeExtensions
{
public static void SaveWithCustomFormatting(this XDocument doc, string filename, int indentDepth)
{
using (var textWriter = new StreamWriter(filename))
using (var writer = new CustomFormattingXmlTextWriter(textWriter, indentDepth))
{
doc.Save(writer);
}
}
}
Using it, you can do:
myDoc.SaveWithCustomFormatting(fileName, 1);
which outputs, as required:
<ROOTELEMENT>
<CHILDELEMENT><INFO1>Test a 1</INFO1><INFO2>Test a 2</INFO2></CHILDELEMENT>
<CHILDELEMENT><INFO1>Test b 1</INFO1><INFO2>Test b 2</INFO2></CHILDELEMENT>
</ROOTELEMENT>
Notes:
You can modify the logic in CustomFormattingXmlTextWriter.OnElementStarted()
to disable the formatting using any criteria you desire such as checking to see whether the incoming localName
is CHILDELEMENT
.
XmlTextWriter
is deprecated in favor of XmlWriter
-- but the latter does not have a mutable Formatting
property. If you must needs use XmlWriter
you might look at Is there a way to serialize multiple XElements onto the same line?.
Demo fiddle #1 here.
Upvotes: 2