ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

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

2019-07-05 22:05:56  阅读:453  来源: 互联网

标签:c indentation xml 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);

但似乎它不会达到我的预期.

我试图提供一个自定义类,它从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);
}

解决方法:

我最终没有完全使用XDocument.Save,而是创建了一个带有XDocument,XmlWriter和TextWriter的类.
该类解析XDocument中的所有节点,TextWriter绑定到磁盘上的文件,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,indentation,xml,xmlwriter
来源: https://codeday.me/bug/20190705/1391159.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有