2009-06-01 34 views
20

sto cercando di generare codice XML in questo modo:NET serializzazione XML senza dichiarazione <?xml> testo

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

Ho una classe (ObjectClass) decorato con XMLSerialization attributi come questo:

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

E il mio pensiero intuitivo molto hacky per ottenere questo funziona è quello di farlo quando serializzo:

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

Tuttavia, questo genera XML come questo:

<?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> 

vale a dire la dichiarazione serializzare aggiunge automaticamente una dichiarazione di testo < xml?.

So che sto attaccando così male, quindi qualcuno può indicarmi la giusta direzione?

Come nota, non penso che abbia un senso pratico semplicemente creare una classe APIRequest con un oggetto ObjectClass (perché ci sono 20 diversi tipi di ObjectClass che ognuno ha bisogno di questo bollino attorno a loro) ma correggimi se sbaglio

+0

Automaticamente? Sembra che tu stia aggiungendo manualmente la dichiarazione: w.WriteLine (@ "") ;. – Cerebrus

+1

@Cerebrus, non vuole l'interno all'interno del tag . – sisve

+0

Sì, grazie per averlo chiarito :-) –

risposta

24

Non generare mai xml utilizzando la concatenazione di stringhe. È malvagio.

uscita:

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

Codice:

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

Grazie, sapevo che la stringa concat era male ma pensavo che avrebbe funzionato almeno - immagino di no! Grazie :-) –

+0

Appena controllato - grazie mille! –

+0

Non direi che è malvagio. Non è preferibile, ma se hai situazioni in cui la performance è cruciale e hai identificato lo sceneggiatore come la fonte di quel successo in termini di prestazioni, usare la concatenazione di stringhe può essere una vittoria tremenda. Certo, è situazionale e quasi * sempre * uso 'XmlWriter', ma in * alcuni * casi, è giustificato. – casperOne

1

derivare il proprio XmlTextWriter di omettere la dichiarazione 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 

Chiama Serializza con un'istanza del derivato MyXmlTextWriter.

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

@Doug D: Ho difficoltà a credere che tu consideri questa una soluzione migliore. –

1

Scott Hanselman's ottenuto un buon post su questo. Ho usato l'esempio di Kzu (che il blog di Scott indica) un po 'indietro per la stessa cosa e ha funzionato alla grande.

+2

@Tone: una specie di meee-tooo? È proprio quello che ha detto Doug D un mese fa. -1. –

-2

uno di linea, per rimuovere la prima linea da una stringa:

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

Non elegante, ma concisa.

+1

-1: come aiuta? –

30

provare questo:

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

Se non si vuole fare affidamento su uno scrittore xml per motivi di prestazioni, ecc si può fare questo:.

// 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 () ora contiene la serializzazione nuda

+0

si sente sporco, eppure intelligente, per il trucco ReadLine. Mi piace. Qualche problema con il rientro e così via? – sirthomas

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

strXML = strXML.Remove (0, sXMLContent.IndexOf (@ "?>", 0) + 2); – sas

+1

puoi spiegare la tua risposta? – CoderPi

Problemi correlati