Indentation text in XML serialization of string property?

I have a string property that will contain text with newline characters. There are some properties of HTML text in this text in that spaces are ignored.

If I serialize this type using XML serialization, newlines are constructed correctly, but the indentation is "incorrect". I want the serialization process to backtrack from strings in order to preserve XML formatting, as these whitespace characters will be ignored later.

Here is a LINQPad example:

void Main() { var d = new Dummy(); d.Text = @"Line 1 Line 2 Line 3"; var serializer = new XmlSerializer(typeof(Dummy)); var ns = new XmlSerializerNamespaces(); ns.Add("", ""); using (var writer = new StringWriter()) { serializer.Serialize(writer, d, ns); writer.ToString().Dump(); } } [XmlType("dummy")] public class Dummy { [XmlElement("text")] public string Text { get; set; } } 

Actual output:

 <?xml version="1.0" encoding="utf-16"?> <dummy> <text>Line 1 Line 2 Line 3</text> </dummy> 

Required Conclusion:

 <?xml version="1.0" encoding="utf-16"?> <dummy> <text> Line 1 Line 2 Line 3 </text> </dummy> 

Is it possible? If so, how? I would prefer not to use the hacker way to just add spaces in myself.

The reason for this is that this XML will be viewed and edited by people, so I would like the original output to be better formatted for them out of the box.

+4
source share
1 answer

I came across the same question. In the end, I went out with the usual author:

 public class IndentTextXmlWriter : XmlTextWriter { private int indentLevel; private bool isInsideAttribute; public IndentTextXmlWriter(TextWriter textWriter): base(textWriter) { } public bool IndentText { get; set; } public override void WriteStartAttribute(string prefix, string localName, string ns) { isInsideAttribute = true; base.WriteStartAttribute(prefix, localName, ns); } public override void WriteEndAttribute() { isInsideAttribute = false; base.WriteEndAttribute(); } public override void WriteStartElement(string prefix, string localName, string ns) { indentLevel++; base.WriteStartElement(prefix, localName, ns); } public override void WriteEndElement() { indentLevel--; base.WriteEndElement(); } public override void WriteString(string text) { if (String.IsNullOrEmpty(text) || isInsideAttribute || Formatting != Formatting.Indented || !IndentText || XmlSpace == XmlSpace.Preserve) { base.WriteString(text); return; } string[] lines = text.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); string indent = new string(IndentChar, indentLevel * Indentation); foreach (string line in lines) { WriteRaw(Environment.NewLine); WriteRaw(indent); WriteRaw(line.Trim()); } WriteRaw(Environment.NewLine); WriteRaw(new string(IndentChar, (indentLevel - 1) * Indentation)); } } 

You can use it as follows:

 [TestMethod] public void WriteIndentedText() { var result = new StringBuilder(); using (var writer = new IndentTextXmlWriter(new StringWriter(result)){Formatting = Formatting.Indented, IndentText = true}) { string text = @" Line 1 Line 2 Line 3 "; // some root writer.WriteStartDocument(); writer.WriteStartElement("root"); writer.WriteStartElement("child"); // test auto-indenting writer.WriteStartElement("elementIndented"); writer.WriteString(text); writer.WriteEndElement(); // test space preserving writer.WriteStartElement("elementPreserved"); writer.WriteAttributeString("xml", "space", null, "preserve"); writer.WriteString(text); writer.WriteEndDocument(); } Debug.WriteLine(result.ToString()); } 

And the conclusion:

 <?xml version="1.0" encoding="utf-16"?> <root> <child> <elementIndented> Line 1 Line 2 Line 3 </elementIndented> <elementPreserved xml:space="preserve"> Line 1 Line 2 Line 3 </elementPreserved> </child> </root> 
+2
source

Source: https://habr.com/ru/post/1502248/


All Articles