如何在 .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 的行为有所不同——即,它会转义输出。
这太棒了。无需经过String
或Stream
就可以快速而优雅地构建XmlDocument
。一个有用的例子:将任意 WPF 运行时实例直接转换为它根的XAML
对象图的XmlDocument
表示:var xd = new XmlDocument(); var w = xd.CreateNavigator().AppendChild(); XamlWriter.Save(inst, new XamlDesignerSerializationManager(w) XamlWriterMode = XamlWriterMode.Expression );
(确保使用来自System.Windows.Markup
的XamlWriter
)这显然使替代品看起来非常笨重。太棒了!【参考方案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?的主要内容,如果未能解决你的问题,请参考以下文章
C# XMLWriter 创建 WriteAttributeStringAsync