没有 <?xml> 文本声明的 .NET XML 序列化

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/933664/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 12:47:14  来源:igfitidea点击:

.NET XML Serialization without <?xml> text declaration

.netxml-serialization.net-2.0

提问by Matt Mitchell

I'm trying to generate XML like this:

我正在尝试像这样生成 XML:

<?xml version="1.0"?>
<!DOCTYPE APIRequest SYSTEM
"https://url">
<APIRequest>
  <Head>
      <Key>123</Key>
  </Head>
  <ObjectClass>
    <Field>Value</Field
  </ObjectClass>
</APIRequest>

I have a class (ObjectClass) decorated with XMLSerialization attributes like this:

我有一个用 XMLSerialization 属性装饰的类(ObjectClass),如下所示:

[XmlRoot("ObjectClass")]
public class ObjectClass
{
    [XmlElement("Field")]
    public string Field { get; set; }
}

And my really hacky intuitive thought to just get this working is to do this when I serialize:

而我真正的 hacky 直观想法就是在我序列化时执行此操作:

ObjectClass inst = new ObjectClass();
XmlSerializer serializer = new XmlSerializer(inst.GetType(), "");

StringWriter w = new StringWriter();
w.WriteLine(@"<?xml version=""1.0""?>");
w.WriteLine("<!DOCTYPE APIRequest SYSTEM");
w.WriteLine(@"""https://url"">");
w.WriteLine("<APIRequest>");
w.WriteLine("<Head>");
w.WriteLine(@"<Field>Value</Field>");
w.WriteLine(@"</Head>");

XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", ""); 
serializer.Serialize(w, inst, ns);

w.WriteLine("</APIRequest>");

However, this generates XML like this:

但是,这会生成这样的 XML:

<?xml version="1.0"?>
<!DOCTYPE APIRequest SYSTEM
"https://url">
<APIRequest>
  <Head>
      <Key>123</Key>
  </Head>
  <?xml version="1.0" encoding="utf-16"?>
  <ObjectClass>
    <Field>Value</Field>
  </ObjectClass>
</APIRequest>

i.e. the serialize statement is automatically adding a <?xml text declaration.

即序列化语句自动添加一个 <?xml 文本声明。

I know I'm attacking this wrong so can someone point me in the right direction?

我知道我在攻击这个错误,所以有人可以指出我正确的方向吗?

As a note, I don't think it will make practical sense to just make an APIRequest class with an ObjectClass in it (because there are say 20 different types of ObjectClass that each needs this boilerplate around them) but correct me if I'm wrong.

作为说明,我认为只创建一个带有 ObjectClass 的 APIRequest 类是没有实际意义的(因为有 20 种不同类型的 ObjectClass,每个都需要这个样板)但如果我是,请纠正我错误的。

回答by Giuseppe Dimauro

try this:

尝试这个:

internal static string ToXml(object obj)
{
  string retval = null;
  if (obj != null)
  {
    StringBuilder sb = new StringBuilder();
    using(XmlWriter writer = XmlWriter.Create(sb, new XmlWriterSettings() { OmitXmlDeclaration = true }))
    {
      new XmlSerializer(obj.GetType()).Serialize(writer, obj);
    }
    retval = sb.ToString();
  }
  return retval;
}

回答by sisve

Never build xml using string concatenation. It's evil.

永远不要使用字符串连接来构建 xml。这是邪恶的。

Output:

输出:

<?xml version="1.0" encoding="utf-16"?>
<!DOCTYPE APIRequest SYSTEM "https://url">
<APIRequest>
  <Head>
    <Key>123</Key>
  </Head>
  <ObjectClass>
    <Field>Value</Field>
  </ObjectClass>
</APIRequest>

Code:

代码:

using System;
using System.Diagnostics;
using System.Text;
using System.Xml;
using System.Xml.Serialization;

public static class Program {
    public static void Main() {
        var obj = new ObjectClass { Field = "Value" };

        var settings = new XmlWriterSettings {
            Indent = true
        };

        var xml = new StringBuilder();
        using (var writer = XmlWriter.Create(xml, settings)) {
            Debug.Assert(writer != null);

            writer.WriteDocType("APIRequest", null, "https://url", null);
            writer.WriteStartElement("APIRequest");
            writer.WriteStartElement("Head");
            writer.WriteElementString("Key", "123");
            writer.WriteEndElement(); // </Head>

            var nsSerializer = new XmlSerializerNamespaces();
            nsSerializer.Add("", "");

            var xmlSerializer = new XmlSerializer(obj.GetType(), "");
            xmlSerializer.Serialize(writer, obj, nsSerializer);

            writer.WriteEndElement(); // </APIRequest>
        }

        Console.WriteLine(xml.ToString());
        Console.ReadLine();
    }
}

[XmlRoot("ObjectClass")]
public class ObjectClass {
    [XmlElement("Field")]
    public string Field { get; set; }
}

回答by Dominic

If you don't want to rely on an xml writer for performance reasons etc you can do this:

如果出于性能原因等不想依赖 xml 编写器,则可以执行以下操作:

// Read into memory stream and set namespaces to empty strings
XmlSerializerNamespaces nsSerializer = new XmlSerializerNamespaces();
nsSerializer.Add(string.Empty, string.Empty);
XmlSerializer xs = new XmlSerializer(typeof(Model.AudioItem));
xs.Serialize(ms, item, nsSerializer);

// Read into UTF-8 stream and read off first line (i.e "<?xml version="1.0"?>")
StreamReader sr = new StreamReader(ms);
ms.Position = 0;
sr.ReadLine();

sr.ReadToEnd().ToString() now contains the naked serialization

sr.ReadToEnd().ToString() 现在包含裸序列化

回答by Doug Domeny

Derive your own XmlTextWriter to omit the XML declaration.

派生您自己的 XmlTextWriter 以省略 XML 声明。

Private Class MyXmlTextWriter
Inherits XmlTextWriter
Sub New(ByVal sb As StringBuilder)
    MyBase.New(New StringWriter(sb))
End Sub
Sub New(ByVal w As TextWriter)
    MyBase.New(w)
End Sub

Public Overrides Sub WriteStartDocument()
    ' Don't emit XML declaration
End Sub
Public Overrides Sub WriteStartDocument(ByVal standalone As Boolean)
    ' Don't emit XML declaration
End Sub
End Class

Call Serialize with an instance of the derived MyXmlTextWriter.

使用派生的 MyXmlTextWriter 的实例调用 Serialize。

Dim tw As New MyXmlTextWriter(sb)
Dim objXmlSerializer As New XmlSerializer(type)
objXmlSerializer.Serialize(tw, obj)

回答by Tone

Scott Hanselman'sgot a good post on this. I used Kzu's example (which Scott's blog points to) a while back for the same thing and it worked great.

Scott Hanselman在这方面有很好的帖子。不久前,我使用 Kzu 的示例(Scott 的博客指向)来做同样的事情,并且效果很好。

回答by sas

if (!string.IsNullOrEmpty(strXML) && strXML.Contains(@"<?xml"))
strXML = strXML.Remove(0, strXML.IndexOf(@"?>", 0) + 2);

回答by user250718

One liner, to remove the first line from a string:

一个班轮,从字符串中删除第一行:

String.Join("\n", strXML.Split('\n').Skip(1).ToArray())

Not elegant, but concise.

不优雅,但简洁。