c# - XDocument 在一行中写入特定的 XElement

标签 c# xml linq linq-to-xml xelement

我正在使用 XDocument 编写 XML 文件。我想调整文件布局。让我解释一下,这里是生成文件的摘录:

<ROOTELEMENT>
  <CHILDELEMENT>
    <INFO1>Test a 1</INFO1>
    <INFO2>Test a 2</INFO2>
  </CHILDELEMENT>
  <CHILDELEMENT>
    <INFO1>Test b 1</INFO1>
    <INFO2>Test b 2</INFO2>
  </CHILDELEMENT>
<ROOTELEMENT>

我希望我的文件看起来像这样:

<ROOTELEMENT>
  <CHILDELEMENT><INFO1>Test a 1</INFO1><INFO2>Test a 2</INFO2></CHILDELEMENT>
  <CHILDELEMENT><INFO1>Test b 1</INFO1><INFO2>Test b 2</INFO2></CHILDELEMENT>
</ROOTELEMENT>

这是我的代码:

var myDoc = new XDocument(new XElement("ROOTELEMENT",
                                    new XElement("CHILDELEMENT",
                                        new XElement("INFO1", "Test a 1"),
                                        new XElement("INFO2", "Test a 2")),
                                    new XElement("CHILDELEMENT",
                                        new XElement("INFO1", "Test b 1"),
                                        new XElement("INFO2", "Test b 2"))));

myDoc.Save("Test.xml");

最佳答案

XML 输出的格式由 XmlWriter 控制不是 XElementXDocument,因此,如果您需要精确控制格式,则需要通过子类化 XmlWriter 的实现之一来创建自己的编写器,具体来说XmlTextWriter谁的Formatting属性是可变的,可以在写入期间更改。

例如,这是一个当元素深度超过 1 时禁用缩进的版本:

public class CustomFormattingXmlTextWriter : XmlTextWriter
{
    readonly Stack<Formatting> stack = new Stack<Formatting>();

    public CustomFormattingXmlTextWriter(TextWriter writer, int indentDepth) : base(writer) 
    { 
        this.Formatting = Formatting.Indented; 
        this.IndentDepth = indentDepth;
    }
    
    int IndentDepth { get; }

    void OnElementStarted(string localName, string ns)
    {
        stack.Push(Formatting);
        // You could e.g. modify the logic here to check to see whether localName == CHILDELEMENT
        // if (localName == "CHILDELEMENT")
        if (stack.Count == IndentDepth+1)
            Formatting = Formatting.None;
    }

    void OnElementEnded()
    {
        var old = stack.Pop();
        if (old != Formatting)
            Formatting = old;
    }

    public override void WriteStartElement(string prefix, string localName, string ns)
    {
        base.WriteStartElement(prefix, localName, ns);
        OnElementStarted(localName, ns);
    }

    public override void WriteEndElement()
    {
        base.WriteEndElement();
        OnElementEnded();
    }
    
    public override void WriteFullEndElement()
    {
        base.WriteEndElement();
        OnElementEnded();
    }
}

public static partial class XNodeExtensions
{
    public static void SaveWithCustomFormatting(this XDocument doc, string filename, int indentDepth)
    {
        using (var textWriter = new StreamWriter(filename))
        using (var writer = new CustomFormattingXmlTextWriter(textWriter, indentDepth))
        {
            doc.Save(writer);
        }
    }
}

使用它,您可以执行以下操作:

myDoc.SaveWithCustomFormatting(fileName, 1);

根据需要输出:

<ROOTELEMENT>
  <CHILDELEMENT><INFO1>Test a 1</INFO1><INFO2>Test a 2</INFO2></CHILDELEMENT>
  <CHILDELEMENT><INFO1>Test b 1</INFO1><INFO2>Test b 2</INFO2></CHILDELEMENT>
</ROOTELEMENT>

注释:

  • 您可以修改 CustomFormattingXmlTextWriter.OnElementStarted() 中的逻辑,以使用您想要的任何条件禁用格式设置,例如检查传入的 localName 是否为 child

  • XmlTextWriter 已弃用,取而代之的是 XmlWriter ——但后者没有可变的 Formatting 属性。如果您必须使用 XmlWriter,您可以查看 Is there a way to serialize multiple XElements onto the same line?

演示 fiddle #1 here .

关于c# - XDocument 在一行中写入特定的 XElement,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57287775/

相关文章:

c# - 在android中序列化对象列表并在WCF中反序列化

java - 当 Xml 不包含标记时,JAXB 返回 null

c# 使用 linq 替换类的属性中的字符串不起作用

java - (ImageView)findViewById() 始终返回 null

xml - 以 XML 格式写入 2D 点

linq - 什么是 LINQ 中的表达式树?

c# - LINQ-Sum 的不同行为和手动添加整数值

c# - 如何在不在 C# 中生成垃圾的情况下将 int 转换为 char[]

c# - ASP .Net jQuery AJAX 登录安全吗?

c# - 使用动态确定的类类型静态定义成员