【问题标题】:.NET XML Serialization without <?xml> text declaration没有 <?xml> 文本声明的 .NET XML 序列化
【发布时间】:2009-06-01 05:30:48
【问题描述】:

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

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

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

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

我真正的直觉想法是让这个工作在我序列化时做到这一点:

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>");

但是,这会生成这样的 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>

即serialize 语句自动添加

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

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

【问题讨论】:

  • 谢谢,对 .NET 2.0 有什么想法吗?
  • 自动?您似乎正在手动添加声明: w.WriteLine(@"");.
  • @Cerebrus,他不想要 标记内的内部
  • @John DataContractSeializer 没有创建标题
  • DataContractSerializer 也不会发出 DTD 声明。

标签: .net xml-serialization .net-2.0


【解决方案1】:

试试这个:

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;
}

【讨论】:

    【解决方案2】:

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

    输出:

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

    代码:

    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; }
    }
    

    【讨论】:

    • 谢谢,我知道字符串 concat 不好,但我认为它至少可以工作 - 我想不会!谢谢:-)
    • 我不会说这是邪恶的。这不是首选,但如果您遇到性能至关重要的情况,并且您已将编写器确定为该性能影响的来源,那么使用字符串连接可能是一个巨大的胜利。当然,这是有条件的,我几乎总是使用XmlWriter,但在某些情况下,这是合理的。
    【解决方案3】:

    如果您出于性能等原因不想依赖 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() 现在包含裸序列化

    【讨论】:

    • 对于 ReadLine 技巧感觉很脏,但很聪明。我喜欢。对缩进等有任何顾虑吗?
    【解决方案4】:

    派生您自己的 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
    

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

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

    【讨论】:

    • @Doug D:我很难相信你认为这是一个更好的解决方案。
    【解决方案5】:

    Scott Hanselman's 得到了一个很好的帖子。不久前,我使用了 Kzu 的示例(Scott 的博客指出),效果很好。

    【讨论】:

    • @Tone:有点像meee-tooo?这正是道格 D 一个月前所说的。 -1.
    【解决方案6】:
    if (!string.IsNullOrEmpty(strXML) && strXML.Contains(@"<?xml"))
    strXML = strXML.Remove(0, strXML.IndexOf(@"?>", 0) + 2);
    

    【讨论】:

    • strXML = strXML.Remove(0, sXMLContent.IndexOf(@"?>", 0) + 2);
    • 你能解释一下你的答案吗?
    【解决方案7】:

    一个衬线,从字符串中删除第一行:

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

    不优雅,但简洁。

    【讨论】:

      猜你喜欢
      • 2012-04-08
      • 1970-01-01
      • 1970-01-01
      • 2010-09-09
      • 1970-01-01
      • 2012-03-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多