使用XmlWriter将内容写入字符串而不是文件

132

我有一个需要返回XML字符串的WCF服务。 但似乎编写者只想建立一个文件而不是一个字符串。 我尝试了:

string nextXMLstring = "";
using (XmlWriter writer = XmlWriter.Create(nextXMLstring))

这会生成一个错误,指出“nextXMLstring”没有文件路径。它需要类似于以下内容:

using (XmlWriter writer = XmlWriter.Create("nextXMLstring.xml"))

如何构建XML并将其作为字符串返回?

谢谢!

6个回答

243
你需要创建一个StringWriter,并将其传递给XmlWriter。
XmlWriter.Create的字符串重载用于文件名。
例如。
using (var sw = new StringWriter()) {
  using (var xw = XmlWriter.Create(sw)) {
    // Build Xml with xw.


  }
  return sw.ToString();
}

3
@Will:撤销了你的更改。XmlTextWriter.Close()会将数据刷新到流中,因此在提取字符串之前要确保发生刷新。(在这种情况下差别不大,但是为了始终如一地处理,我更喜欢这样做,因为*Writer和Stream类的刷新语义并没有明确定义。) - Richard
1
这只是一个提醒,针对那些使用此代码的人。如果你不小心忘记使用using(),而是正常声明XmlWriter,那么在调用sw.ToString()之前一定要调用xw.Flush,否则你可能无法获取所有内容!(显然最好使用using括号...) - Ravendarksky
请注意,以下代码在代码分析过程中会出现CA2202警告,因为将在 StringWriter 对象上调用Dispose()方法两次。 - Łukasz Kosiak
这就是我在寻找的答案,谢谢! - MAXE

121

像Richard所说的那样,StringWriter是前进的道路。然而,有一个问题:默认情况下,StringWriter会将自己宣传为UTF-16格式。通常XML使用UTF-8格式。通过子类化StringWriter,您可以解决这个问题。

public class Utf8StringWriter : StringWriter
{
    public override Encoding Encoding
    {
         get { return Encoding.UTF8; }
    }
}

这将影响XmlWriter编写的声明。当然,如果您要在其他地方以二进制形式编写该字符串,请确保使用与您为StringWriter设置的编码匹配的编码。(上述代码始终假定为UTF-8;很容易制作一个更通用的版本,在构造函数中接受编码)。

然后您将使用:

using (TextWriter writer = new Utf8StringWriter())
{
    using (XmlWriter xmlWriter = XmlWriter.Create(writer))
    {
        ...
    }
    return writer.ToString();
}

Jon,你确定 writer 没有被多次释放吗? - rasx
2
@rasx:可能是这样,但这并不重要。 - Jon Skeet

33

我知道这个问题早已有答案了,但是这里提供一种新的方法。尤其适用于你不想在字符串开头加入UTF8 BOM并且你想要对文本进行缩进的情况:

using (var ms = new MemoryStream())
using (var x = new XmlTextWriter(ms, new UTF8Encoding(false)) 
                   { Formatting = Formatting.Indented })
{
     // ...
     return Encoding.UTF8.GetString(ms.ToArray());
}

4
Encoding.UTF8.GetString(ms.ToArray()) 是对你所返回的结果进行简化。 - SliverNinja - MSFT
1
当我尝试使用ms.ToArray()时,没有返回任何项。不得不添加x.Close()或将返回语句移动到内部using语句的外面。 - Rich C
utf8.GetString(ms.GetBuffer(), 0, (int)ms.Length); 这个能用吗? - brianary
1
@Rich C - 我猜测这是因为你的流没有被刷新。XmlTextWriter应该已经在其using语句之外被处理,这将导致它被刷新。 - yourbuddypal

16

使用 StringBuilder

var sb = new StringBuilder();
    using (XmlWriter xmlWriter = XmlWriter.Create(sb))
    {
        ...
    }
return sb.ToString();

5

大家不要忘记调用xmlWriter.Close()和xmlWriter.Dispose(),否则你的字符串将无法完成创建。它只会是一个空字符串。


1
不用担心,使用语句将处理对象的释放。 - user848765
这是一个来自2009年的问题。因此,现在提供答案的价值在于未来可能会遇到类似问题的用户。因此,只有当他们能够清楚地确定问题并解释/提供解决方案时,才应该回答这样的旧问题。试图与OP进行交流通常是徒劳的,因为他们可能已经离开了。 - MikeC
1
我正在浏览所有这些示例,并想知道为什么我得到空字符串。xmlWriter.Close()是解决方案。 - Rafał Ryszkowski

0

我认为这里最简单、最快的解决方案就是:

StringBuilder sb = new StringBuilder();

using (var writer = XmlWriter.Create(sb, settings))
{
    ... // Whatever code you have/need :)

    sb = sb.Replace("encoding=\"utf-16\"", "encoding=\"utf-8\""); //Or whatever uft you want/use.
    //Before you finally save it:
    File.WriteAllText("path\\dataName.xml", sb.ToString());
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接