.NET XML-сериализация без <? Xml> текстовой декларации - PullRequest
20 голосов
/ 01 июня 2009

Я пытаюсь сгенерировать XML следующим образом:

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

У меня есть класс (ObjectClass), украшенный такими атрибутами XMLSerialization:

[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 автоматически добавляет текстовое объявление <? xml. </p>

Я знаю, что нападаю на это неправильно, поэтому кто-то может направить меня в правильном направлении?

Как примечание, я не думаю, что будет иметь практический смысл просто сделать класс APIRequest с ObjectClass в нем (потому что есть, скажем, 20 различных типов ObjectClass, каждый из которых нуждается в этом образце вокруг них), но поправьте меня, если Я не прав.

Ответы [ 7 ]

30 голосов
/ 17 сентября 2010

попробуйте это:

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;
}
24 голосов
/ 01 июня 2009

Никогда не создавайте 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; }
}
2 голосов
/ 03 мая 2011

Если вы не хотите полагаться на 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 () теперь содержит скрытую сериализацию

1 голос
/ 31 июля 2009

Скотт Хансельман получил хороший пост по этому вопросу. Некоторое время назад я использовал пример Кзу (на который указывает блог Скотта), и он отлично работал.

1 голос
/ 05 июня 2009

Получите свой собственный 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

Вызовите Serialize с экземпляром производного MyXmlTextWriter.

Dim tw As New MyXmlTextWriter(sb)
Dim objXmlSerializer As New XmlSerializer(type)
objXmlSerializer.Serialize(tw, obj)
0 голосов
/ 19 января 2016
if (!string.IsNullOrEmpty(strXML) && strXML.Contains(@"<?xml"))
strXML = strXML.Remove(0, strXML.IndexOf(@"?>", 0) + 2);
0 голосов
/ 14 января 2010

Один вкладыш, чтобы удалить первую строку из строки:

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

Не элегантно, но лаконично.

...