Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
676 views
in Technique[技术] by (71.8m points)

c# - Indent text in xml serialization of string property?

I have a string property which will contain text with newlines. This text has some of the properties of HTML text in that whitespace is disregarded.

If I serialize this type using XML serialization, the newlines are serialized properly, but the indentation is "wrong". I want the serialization process to indent the lines to keep the formatting of the XML, since those whitespace characters will be disregarded later anyway.

Here's an example LINQPad program:

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>

Desired output:

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

Is this possible? If so, how? I'd rather not do the hackish way of just adding the whitespace in myself.

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

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I bumped into the same issue. At the end I came out with a custom writer:

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 like this:

[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 output:

<?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>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...