如何在 .NET 中使用 XmlWriter 创建 XmlDocument?

Posted

技术标签:

【中文标题】如何在 .NET 中使用 XmlWriter 创建 XmlDocument?【英文标题】:How to create a XmlDocument using XmlWriter in .NET? 【发布时间】:2010-11-23 17:41:22 【问题描述】:

许多 .NET 函数使用 XmlWriter 来输出/生成 xml。输出到文件/字符串/内存是一个非常操作:

XmlWriter xw = XmlWriter.Create(PutYourStreamFileWriterEtcHere);
xw.WriteStartElement("root");
...

有时,您需要操作生成的 Xml,因此希望将其加载到 XmlDocument 中,或者出于其他原因可能需要 XmlDocument,但您必须使用 XmlWriter 生成 XML。例如,如果您调用仅输出到 XmlWriter 的 3rd 方库中的函数。

您可以做的事情之一是将 xml 写入字符串,然后将其加载到您的 XmlDocument 中:

StringWriter S = new StringWriter();
XmlWriter xw = XmlWriter.Create(S);
/* write away */
XmlDocument xdoc = new XmlDocument();
xdoc.LoadXml(S.ToString());

然而这是低效的——首先将所有 xml 信息序列化为一个字符串,然后再次解析该字符串以创建 DOM。

如何直接指向 XmlWriter 构建 XmlDocument?

【问题讨论】:

+1 好问题,很有帮助。 【参考方案1】:

您可以使用 XMLWriter 类编写 xml 文件。 这是一个例子。

    XmlWriterSettings objSetting = new XmlWriterSettings();
    objSetting.Indent = true;
    objSetting.NewLineOnAttributes = true;

    System.Text.StringBuilder sb = new System.Text.StringBuilder();


    using (XmlWriter objWriter = XmlWriter.Create(sb, objSetting))
    
        //Note the artificial, but useful, indenting
        objWriter.WriteStartDocument();

        objWriter.WriteStartElement("books");

        ////////Start Book Element///////

        objWriter.WriteStartElement("book");

        objWriter.WriteStartAttribute("ISBN");
        objWriter.WriteValue("asp1");
        objWriter.WriteEndAttribute();

        objWriter.WriteStartElement("Title");
        objWriter.WriteValue("ASP.NET");
        objWriter.WriteEndElement();

        objWriter.WriteElementString("ReleaseDate", "11/11/2010");

        objWriter.WriteStartElement("Pages");
        objWriter.WriteValue(200);
        objWriter.WriteEndElement(); //price

        objWriter.WriteEndElement(); //book
        ////////End Book Element///////


        ////////Another Element

        ////////Start Book Element///////

        objWriter.WriteStartElement("book");

        objWriter.WriteStartAttribute("ISBN");
        objWriter.WriteValue("c#2");
        objWriter.WriteEndAttribute();

        objWriter.WriteStartElement("Title");
        objWriter.WriteValue("C#.NET");
        objWriter.WriteEndElement();

        objWriter.WriteElementString("ReleaseDate", "10/11/2010");

        objWriter.WriteStartElement("Pages");
        objWriter.WriteValue(500);
        objWriter.WriteEndElement(); 

        objWriter.WriteEndElement(); //book
        ////////End Book Element///////



        objWriter.WriteEndElement(); //books
        objWriter.WriteEndDocument();

    

    File.WriteAllText(Server.MapPath("BooksList.xml"), sb.ToString());

【讨论】:

【参考方案2】:

这里至少有一个解决方案:

XmlDocument doc = new XmlDocument(); 
using (XmlWriter writer = doc.CreateNavigator().AppendChild()) 
 
    // Do this directly 
     writer.WriteStartDocument(); 
     writer.WriteStartElement("root"); 
     writer.WriteElementString("foo", "bar"); 
     writer.WriteEndElement(); 
     writer.WriteEndDocument();
    // or anything else you want to with writer, like calling functions etc.

显然,当您调用 AppendChild() 时,XpathNavigator 会为您提供一个 XmlWriter

感谢 Martin Honnen:http://groups.google.com/group/microsoft.public.dotnet.xml/browse_thread/thread/24e4c8d249ad8299?pli=1

【讨论】:

谢谢!对我来说很明显,您可以使用 XmlWriter 作为 XmlDocument 的构建器,但是我找不到简单的方法来做到这一点,所以我最终写到缓冲区并再次解析。他们本可以让它更容易找到。 任何人都知道是否可以使用 xdocument/xelement(使用 .NET 3.5,因此无法直接从内存流加载) 另请注意,如所写,生成的XmlWriter 将具有Document 的一致性级别,因此如果您将其作为输入发送到 XSL 转换作为输入(并且您是不创建完整的文档),您可以改用new XmlDocument().CreateFragment().CreateNavigator() 请注意,这样做的一个缺点是,对于基于 XPathNavigator 的 XmlWriter,WriteRaw 的行为有所不同——即,它会转义输出。 这太棒了。无需经过StringStream 就可以快速而优雅地构建XmlDocument。一个有用的例子:将任意 WPF 运行时实例直接转换为它根的XAML 对象图的XmlDocument 表示:var xd = new XmlDocument(); var w = xd.CreateNavigator().AppendChild(); XamlWriter.Save(inst, new XamlDesignerSerializationManager(w) XamlWriterMode = XamlWriterMode.Expression );(确保使用来自System.Windows.MarkupXamlWriter)这显然使替代品看起来非常笨重。太棒了!【参考方案3】:

XmlWriter 正在写入一个底层 Stream 对象,如果它是双向的 (MemoryStream),您可以简单地将其重新定位回 -0-,然后在 XmlDocument.Load(stream) 中使用 Stream 对象.

HTH,

Z

【讨论】:

这将导致同样的低效率 - 重新解析流以再次构建 DOM。 +1 这是我在问题中给出的示例中选择的方式,因为不需要将字符串创建为中间体。 Boaz 是对的,和从字符串中解析 XmlDocument 基本一样【参考方案4】:

XmlWriter 背后的想法是等到您完成修改数据后再开始编写。

XmlWriter 的构建并未考虑到您的情况。

要么

等到你知道你的数据是什么 会在写作之前完成

做你目前正在做的事情

【讨论】:

我不同意。 XmlWriter 是构建器模式的一个很好的示例,使用它来构建 DOM(XmlDocument 或任何其他实现)非常有意义。而且我有一个非常真实的用例:我读取 XML 数据并使用一些 XslCompiledTransform 对其进行转换,它写入 XmlWriter,它直接构造 XmlDocument,我可以对其进行处理然后写出(可能在输出上应用一些其他 XSLT)。那有什么问题?写出流然后再次解析是:a)毫无意义(它没有帮助或使设计更清晰),b)不必要和c)效率非常低。【参考方案5】:

您可以做相反的事情:首先使用 DOM 构建 XmlDocument,然后将其写入 XmlWriter

XmlDocument xdoc = new XmlDocument();
... // build the document

StringWriter S = new StringWriter();
XmlWriter xw = XmlWriter.Create(S);
xdoc.WriteTo(xw);

【讨论】:

XmlWriter 并非设计用于写入 XmlDocument,而是设计用于写入 Stream 或 TextWriter。你问的根本不可能,我只是建议另一种方法...... +1 反对毫无意义的反对票。这是对恕我直言的问题的一个不错的答案 我也不喜欢这个答案。这是经典的 SO 问题:“我怎样才能只用 javascript 解决这个问题?” -- “使用 jQuery!” @Tomas Levesque:我的意思是有人问了一个问题“我如何解决 X”,而答案是“不要解决 X,而是解决 Y”,而这不是问题所在。如果不可能做到,那就是答案。 @Seb:我强烈反对。如果我们每次需要从 A 到 C 时都停下来并且没有直接的根,我们就不会像程序员那样走得更远。我们的职业取决于能否通过 B 找到替代路线。Thomas 提出了另一种方法,老实说我不明白这个答案的诽谤(是的,我意识到这是一个社区。是的,我已经行使了投票权关于这个答案。但是我可以表达我对一般反应的不满)

以上是关于如何在 .NET 中使用 XmlWriter 创建 XmlDocument?的主要内容,如果未能解决你的问题,请参考以下文章

使用XmlWriter写Xml

使用XmlWriter写Xml

.NET XmlWriter 中的正确名称空间管理

C# XMLWriter 创建 WriteAttributeStringAsync

如何将 EntityReference(例如 )写入 XmlNodeReader 读取的 XmlWriter?

可以使用 XmlWriter 将 XML 写入内存吗?