如何使用XDocument打印"<?xml version="1.0"?>"?

70

在使用ToString方法时,有没有办法让XDocument打印xml版本?让它输出这样的内容:

<?xml version="1.0"?>
<!DOCTYPE ELMResponse [
]>
<Response>
<Error> ...

我有以下代码:

var xdoc = new XDocument(new XDocumentType("Response", null, null, "\n"), ...

这将打印出相应的内容,虽然没问题,但是缺少了之前提到的"<?xml version"。

<!DOCTYPE ELMResponse [
]>
<Response>
<Error> ...
我知道你可以通过手动输出来完成这个操作。只是想知道是否可以使用XDocument实现。

2
顺便提一下:XDocument.ToString() 省略了 XDeclaration,这也意味着即使 XDeclaration 存在于 XDocument 中,在 VS 调试器的监视窗口中也看不到声明。 - dthorpe
6个回答

129

通过使用XDeclaration,您可以添加声明。

但是,使用ToString()方法将无法获得所需的输出。

您需要使用XDocument.Save()方法之一来实现目标输出。

完整示例:

var doc = new XDocument(
        new XDeclaration("1.0", "utf-16", "yes"), 
        new XElement("blah", "blih"));

var wr = new StringWriter();
doc.Save(wr);
Console.Write(wr.ToString());

2
没错,我漏掉了他说他在使用ToString()的部分。所以,要使用XDeclaration和Save()(保存到文件或内存流)。 - Yann Schwartz
1
或者通过StringWriter将翻译后的文本返回为字符串。 - EricSch
3
直接使用wr.toString()即可,无需在其间添加GetStringBuilder()。 - amarnath chatterjee
2
提示:您可以创建一个扩展方法来添加功能到 ToString 方法中。例如:public static string ToString(this XDocument doc, bool addDeclaration) - Bart Friederichs
1
这个答案仅适用于utf-16,因为它使用StringWriter将流编码为utf-16。其ToString()方法始终修改声明。对于utf-8,您可以使用@Kevin的答案https://dev59.com/u3NA5IYBdhLWcg3wcddk#4337505。 - R. Schreurs
显示剩余5条评论

15

这绝对是最好的方法,也是最易管理的:

var xdoc = new XDocument(new XElement("Root", new XElement("Child", "台北 Táiběi.")));

string mystring;

using(var sw = new MemoryStream())
{
    using(var strw = new StreamWriter(sw, System.Text.UTF8Encoding.UTF8))
    {
         xdoc.Save(strw);
         mystring = System.Text.UTF8Encoding.UTF8.GetString(sw.ToArray());
    }
}

我说这话只是因为你可以通过将 .UTF8 更改为 .Unicode 或 .UTF32 来更改编码。


14
晚回答一个旧问题,但我会尽量提供比其他答案更详细的细节。
您所询问的东西称为XML声明
首先,XDocument具有类型为XDeclaration的属性Declaration。您可以使用XDocument构造函数的另一个重载:
var xdoc = new XDocument(
  new XDeclaration("1.0", null, null), // <--- here
  new XDocumentType("Response", null, null, "\n"), ... 
  );

或者稍后设置该属性:

xdoc.Declaration = new XDeclaration("1.0", null, null);

但是取决于你如何在之后保存或写入XDocument,声明(或其中的部分)可能会被忽略。稍后再详细说明。

XML声明可以有多种外观。以下是一些有效的示例:

<?xml version="1.0"?>                                        new XDeclaration("1.0", null, null)
<?xml version="1.1"?>                                        new XDeclaration("1.1", null, null)
<?xml version="1.0" encoding="us-ascii"?>                    new XDeclaration("1.0", "us-ascii", null)
<?xml version="1.0" encoding="utf-8"?>                       new XDeclaration("1.0", "utf-8", null)
<?xml version="1.0" encoding="utf-16"?>                      new XDeclaration("1.0", "utf-16", null)
<?xml version="1.0" encoding="utf-8" standalone="no"?>       new XDeclaration("1.0", "utf-8", "no")
<?xml version="1.0" encoding="utf-8" standalone="yes"?>      new XDeclaration("1.0", "utf-8", "yes")
<?xml version="1.0" standalone="yes"?>                       new XDeclaration("1.0", null, "yes")

请注意XDeclaration会接受无效的参数,因此你需要确保参数正确。

在许多情况下,第一个形式为<?xml version="1.0"?>的请求是完美的(如果只是UTF-8(包括ASCII),则不需要提供encoding,如果其预期值为"no"或者没有DTD,则不需要指定standalone)。

请注意,在我的.NET版本中,xdoc.ToString()XNode基类中覆盖,并且不包括XML声明。你可以轻松地创建一个方法来处理它,像这样:

public static string ToStringWithDecl(this XDocument d)
  => $"{d.Declaration}{Environment.NewLine}{d}";

其他答案中有些人表示,如果您使用xdoc.Savexdoc.WriteTo方法,则将尊重XDeclaration,但这并不完全正确:

  • 即使XDocument中没有XML声明,它们也可能包含XML声明。
  • 它们可能指定目标文件、流、写入器、字符串构建器等使用的编码,而不是您提供的编码,或者特意省略编码。
  • 它们可能会更改您的版本,例如将其从1.1更改为1.0

当然,当您保存/写入文件时,声明与该文件的实际编码匹配是一件好事!

但是有时候当您在内存中写入字符串时,您可能不希望使用utf-16(即使您意识到.NET字符串在内部是UTF-16)。您可以使用上面的扩展方法。或者您可以使用以下来自EricSch答案的修改版方法:

  string xdocString;
  using (var hackedWriter = new SuppressEncodingStringWriter())
  {
    xdoc.Save(hackedWriter);
    xdocString = hackedWriter.ToString();
  }

你有:

// a string writer which claims its encoding is null in order to omit encoding in XML declarations
class SuppressEncodingStringWriter : StringWriter
{
  public sealed override Encoding Encoding => null;
}

添加。谁更新了类型StringWriter(及其基类型TextWriter)以使用可空引用类型,决定像EncodingFormatProvider这样的属性不应该是可空的。也许这很不幸?无论如何,如果您打开了可为空引用类型,则可能需要编写null!而不仅仅是null


2

只需输入以下内容

var doc =
    new XDocument (
        new XDeclaration ("1.0", "utf-16", "no"),
        new XElement ("blah", "blih")
    );

而且你可以得到:

<?xml version="1.0" encoding="utf-16" standalone="no"?>
<blah>blih</blah>

1
此外,由于问题指示使用了DTD,因此standalone必须为“no”。 - Greg Beech

0

VB.NET解决方案代码

代码

   Dim _root As XElement = <root></root>
   Dim _element1 As XElement = <element1>i am element one</element1>
   Dim _element2 As XElement = <element2>i am element one</element2>
   _root.Add(_element1)
   _root.Add(_element2)
   Dim _document As New XDocument(New XDeclaration("1.0", "UTF-8", "yes"), _root)
   _document.Save("c:\xmlfolder\root.xml")

输出 注意(请在记事本中打开输出)

 <?xml version="1.0" encoding="utf-8" standalone="yes"?>
 <root>
   <element1>i am element one</element1>
   <element2>i am element one</element2>
</root>

0

更简单的方法是:

var fullXml = $"{xDocument.Declaration}{xDocument}";

如果你的 xDocument.Declaration 是空的,只需添加它即可。

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