c# - 如何使用 XDocument.Save 使用属性的自定义缩进保存文件

标签 c# xml indentation xmlwriter

我的目标是输出修改后的 XML 文件并保留原始文件中存在的特殊缩进。目的是使生成的文件看起来仍然像原始文件,使它们更容易通过源代码管理进行比较和合并。

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

这是我试图实现/保留的格式:

<Base Import="..\commom\style.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 编写器(无论如何都不起作用)

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,而是创建了一个采用 XDocument、XmlWriter 和 TextWriter 的类。 该类解析 XDocument 中的所有节点,TextWriter 绑定(bind)到磁盘上的文件,XmlWriter 将其用作其输出管道。

我的类然后使用 XmlWriter 输出 xml。为了获得额外的间距,我使用了此处描述的解决方案,https://stackoverflow.com/a/24010544/5920497 ,这就是我还使用底层 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();
}

关于c# - 如何使用 XDocument.Save 使用属性的自定义缩进保存文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44726344/

相关文章:

使用 ToBase64String 的 C# 字符串编码

c# - 是否可以在不使用 "if"的情况下执行此操作(asp.net mvc post action 方法)

Android以编程方式将XML形状设置为可绘制

python - 如何使用python缩进文件中的所有列

c# - 你能在 C# 中找到 Active Directory 用户的主要组吗?

c# - Lambda性能 killer

Java,dom4j : how to add inline element (b, i,u) 位于文本中间

java - 在 Spark 中将纯文本文件转换为 Hadoop 序列文件

php - 如何缩进 Laravel Controller ,查看代码?

c++ - gnu缩进的谷歌c风格设置?