如何使用xdocument.save使用自定义缩进来保存文件



我的目标是输出修改的XML文件并保留原始文件中存在的特殊凹痕。目的是使生成的文件仍然看起来像原始文件,从而使它们更易于通过源控件进行比较和合并。

我的程序将读取XML文件并添加或更改一个特定属性。

这是我要实现/保存的格式:

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

在这种情况下,我只想将所有属性与第一个属性保持一致。

XmlWriterSettings提供格式化选项,但它们无法实现我要寻找的结果。

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

这些设置将把第一个属性放在新线上,而不是将其与节点保持在同一行,并将属性与节点对齐。

这是Load呼叫,它要求保存空间:

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

,但似乎不会做我预期的。

我尝试提供一个自定义类,该类从XmlWriterXDocument.Save调用,但是我尚未设法正确插入空格而不遇到InvalidOperationException。另外,该解决方案对于我要寻找的小型添加似乎过于杀伤。

供参考,这是我的保存呼叫,不使用我的自定义XML Writer(无论如何不起作用(

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

我最终不完全使用xdocument.save.save,而是创建了一个将XDocument的类,XMLWriter和Textwriter。该类解析Xdocument中的所有节点,TextWriter绑定到磁盘上的文件,XMLWriter用作其输出管道。

我的班级然后使用XMLWriter输出XML。为了实现额外的间距,我使用了这里描述的解决方案,https://stackoverflow.com/a/a/24010544/5920497,这就是为什么我也使用基础文本作者。

这是解决方案的示例。

致电课程保存文档:

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();
}

最新更新