How to use XDocument.Save to save a file using custom indentation for attributes

My goal is to output the modified XML file and preserve the special indentation that was present in the source file. The goal is to make the resulting file still look like the original, making it easier to compare and merge through the original control.

My program will read the XML file and add or modify one specific attribute.

Here is the formatting I'm trying to achieve / save:

<Base Import="..\commom\style.xml">
  <Item Width="480"
        Height="500"
        VAlign="Center"
        Style="level1header">
(...)

In this case, I just want to align all the attributes that have passed the first with the first.

XmlWriterSettings provides formatting options, but they will not achieve the result I'm looking for.

settings.Indent = true;
settings.NewLineOnAttributes = true;

These settings put the first attribute on a new line, instead of holding it on the same line as the node, and build the attributes using node.

Load, :

MyXml = XDocument.Load(filepath, LoadOptions.PreserveWhitespace);

, , .

, XmlWriter XDocument.Save, , InvalidOperationException. , .

, , xml ( )

XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.NewLineOnAttributes = true;
settings.OmitXmlDeclaration = true;
using (XmlWriter writer = XmlWriter.Create(filepath + "_auto", settings))
{
    MyXml.Save(writer);
}
+4
1

XDocument.Save , XDocument, XmlWriter, TextWriter. XDocument, TextWriter , XmlWriter .

XmlWriter xml. fooobar.com/questions/1679993/..., TextWriter.

.

:

XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.NewLineOnAttributes = false; // Behavior changed in PrettyXmlWriter
settings.OmitXmlDeclaration = true;

using(TextWriter rawwriter = File.CreateText(filepath))
using (XmlWriter writer = XmlWriter.Create(rawwriter, settings))
{
    // rawwriter is used both by XmlWriter and PrettyXmlWriter
    PrettyXmlWriter outputter = new PrettyXmlWriter(writer, rawwriter);
    outputter.Write(MyXml);

    writer.Flush();
    writer.Close();
}

PrettyXmlWriter:

private XmlWriter Writer { get; set; }
private TextWriter InnerTextWriter { get; set; }

public void Write(XDocument doc)
{
    XElement root = doc.Root;
    WriteNode(root, 0);
}

private void WriteNode(XNode node, int currentNodeDepth)
{
    if(node.NodeType == XmlNodeType.Element)
    {
        WriteElement((XElement)node, currentNodeDepth);
    }
    else if(node.NodeType == XmlNodeType.Text)
    {
        WriteTextNode((XText)node, currentNodeDepth, doIndentAttributes);
    }
}

private void WriteElement(XElement node, int currentNodeDepth)
{
    Writer.WriteStartElement(node.Name.LocalName);

    // Write attributes with indentation
    XAttribute[] attributes = node.Attributes().ToArray();

    if(attributes.Length > 0)
    {
        // First attribute, unindented.
        Writer.WriteAttributeString(attributes[0].Name.LocalName, attributes[0].Value);

        for(int i=1; i<attributes.Length; ++i)
        {
            // Write indentation
            Writer.Flush();
            string indentation = Writer.Settings.NewLineChars + string.Concat(Enumerable.Repeat(Writer.Settings.IndentChars, currentNodeDepth));
            indentation += string.Concat(Enumerable.Repeat(" ", node.Name.LocalName.Length + 1));
            // Using Underlying TextWriter trick to output whitespace
            InnerTextWriter.Write(indentation);

            Writer.WriteAttributeString(attributes[i].Name.LocalName, attributes[i].Value);
        }
    }

    // output children
    foreach(XNode child in node.Nodes())
    {
        WriteNode(child, currentNodeDepth + 1);
    }

    Writer.WriteEndElement();
}
+1

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


All Articles