2010-01-15 1 views
9

Im folgenden Code, ich serialisieren ein Objekt in ein XML Zeichenfolge.Wie muss ich diese XML-Zeichenfolge ändern, damit XDocument.Parse es einliest?

Aber wenn ich versuche, diese XML-String in ein XDocument mit XDocument.Parse zu lesen, es gibt mir diese Fehler:

Ungültige Daten auf Stammebene.

Die XML ist:

<?xml version="1.0" encoding="utf-8"?> 
<Customer xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <Id>1</Id> 
    <FirstName>Jim</FirstName> 
    <LastName>Jones</LastName> 
    <ZipCode>23434</ZipCode> 
</Customer> 

UPDATE: ist die hex:

alt text http://www.deviantsart.com/upload/hhcvmu.png

Was muss ich auf diese XML tun, damit es liest in das XDocument ohne einen Fehler?

using System; 
using System.Collections.Generic; 
using System.Xml.Serialization; 
using System.IO; 
using System.Xml; 
using System.Text; 
using System.Xml.Linq; 

namespace TestSerialize2342 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      List<Customer> customers = Customer.GetCustomers(); 

      Console.WriteLine("--- Serializing ------------------"); 

      foreach (var customer in customers) 
      { 
       Console.WriteLine("Serializing " + customer.GetFullName() + "..."); 
       string xml = XmlHelpers.SerializeObject<Customer>(customer); 

       XDocument xdoc = XDocument.Parse(xml); 

      } 

      Console.ReadLine(); 
     } 

    } 

    public static class StringHelpers 
    { 
     public static String UTF8ByteArrayToString(Byte[] characters) 
     { 
      UTF8Encoding encoding = new UTF8Encoding(); 
      String constructedString = encoding.GetString(characters); 
      return (constructedString); 
     } 

     public static Byte[] StringToUTF8ByteArray(String pXmlString) 
     { 
      UTF8Encoding encoding = new UTF8Encoding(); 
      Byte[] byteArray = encoding.GetBytes(pXmlString); 
      return byteArray; 
     } 
    } 

    public static class XmlHelpers 
    { 
     public static string SerializeObject<T>(object o) 
     { 
      MemoryStream ms = new MemoryStream(); 
      XmlSerializer xs = new XmlSerializer(typeof(T)); 
      XmlTextWriter xtw = new XmlTextWriter(ms, Encoding.UTF8); 
      xs.Serialize(xtw, o); 
      ms = (MemoryStream)xtw.BaseStream; 
      return StringHelpers.UTF8ByteArrayToString(ms.ToArray()); 
     } 

     public static T DeserializeObject<T>(string xml) 
     { 
      XmlSerializer xs = new XmlSerializer(typeof(T)); 
      MemoryStream ms = new MemoryStream(StringHelpers.StringToUTF8ByteArray(xml)); 
      XmlTextWriter xtw = new XmlTextWriter(ms, Encoding.UTF8); 
      return (T)xs.Deserialize(ms); 
     } 
    } 

    public class Customer 
    { 
     public int Id { get; set; } 
     public string FirstName { get; set; } 
     public string LastName { get; set; } 
     public string Street { get; set; } 
     public string Location { get; set; } 
     public string ZipCode { get; set; } 

     private int internalValue = 23; 

     public static List<Customer> GetCustomers() 
     { 
      List<Customer> customers = new List<Customer>(); 
      customers.Add(new Customer { Id = 1, FirstName = "Jim", LastName = "Jones", ZipCode = "23434" }); 
      customers.Add(new Customer { Id = 2, FirstName = "Joe", LastName = "Adams", ZipCode = "12312" }); 
      customers.Add(new Customer { Id = 3, FirstName = "Jack", LastName = "Johnson", ZipCode = "23111" }); 
      customers.Add(new Customer { Id = 4, FirstName = "Angie", LastName = "Reckar", ZipCode = "54343" }); 
      customers.Add(new Customer { Id = 5, FirstName = "Henry", LastName = "Anderson", ZipCode = "16623" }); 
      return customers; 
     } 

     public string GetFullName() 
     { 
      return FirstName + " " + LastName + "(" + internalValue + ")"; 
     } 

    } 
} 

ANTWORT:

Dank Andras, GetPreamble() befestigt ist es, so für alle anderen Umgang mit diesem, hier ein wenig Methode ist Ihre XML der BOM zu reinigen:

public static string RemoveUtf8ByteOrderMark(string xml) 
{ 
    string byteOrderMarkUtf8 = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble()); 
    if (xml.StartsWith(byteOrderMarkUtf8)) 
    { 
     xml = xml.Remove(0, byteOrderMarkUtf8.Length); 
    } 
    return xml; 
} 
+0

Mit diesem XML ist nichts falsch. Sind Sie sicher, dass dieselbe XML-Datei die Ausnahme verursacht? –

+0

Ungültige Daten auf Stammebene, Zeile 1, Zeichen 1. Wenn ich den Text in NotePad ++ kopiere, ist das erste Zeichen ein "?" und in anderen Editoren einige Steuerzeichen ... –

+0

Dann hast du während des Ausschneidens und Einfügens das offene "<" verloren. Mit dem XML ist nichts falsch. –

Antwort

15

Es ist, weil die Daten den Unicode oder utf8 BOM marks am Anfang des Streams enthält.

Sie müssen alle Byte Order Marks im Stream überspringen - Sie können diese anhand der Methode System.Text.Encoding.GetPreamble() identifizieren.

+0

Sie erhalten häufig dieses Problem beim Erstellen von XML-Dateien im Editor. VS kann sie auch manchmal hinzufügen. –

+0

Verwenden von GetPreamble() ist ein Versuch, Konsequenzen statt Grund zu lösen. Sieh dir meine Antwort an. – Restuta

+0

Ja, das ist eine gute Antwort - und es funktioniert, wenn die Codierung immer UTF8 ist. Mithilfe der GetPreamble-Methode können Sie jedoch die Codierung einer Datei automatisch erkennen, sodass Sie nicht nur an eine Datei gebunden sind. Sobald Sie ausgewählt wurden, können Sie Ihr Codebeispiel an die Codierung anpassen. –

1

Sie können Ihr Problem lösen, indem Sie einen StreamReader unter Verwendung der Daten in der MemoryStream in einen String statt zu konvertieren:

public static string SerializeObject<T>(object o) 
{ 
    using (MemoryStream ms = new MemoryStream()) 
    { 
     XmlSerializer xs = new XmlSerializer(typeof(T)); 
     using (XmlWriter xtw = XmlWriter.Create(ms)) 
     { 
      xs.Serialize(xtw, o); 
      xtw.Flush(); 
      ms.Seek(0, SeekOrigin.Begin); 
      using (StreamReader reader = new StreamReader(ms)) 
      { 
       return reader.ReadToEnd(); 
      } 
     } 
    } 
} 
+0

-1: 'XmlTextWriter' ist veraltet. Verwenden Sie stattdessen "XmlWriter.Create". –

+0

@ John: Der Compiler gibt keine Informationen darüber aus, dass 'XmlTextWriter' veraltet ist. Ich kenne die XmlWriter.Create-Empfehlung, aber ich wollte den OP-Code nicht mehr ändern als nötig, um das Problem zu lösen. Trotzdem habe ich meinen Code aktualisiert, um der Empfehlung zu folgen. –

-1

Alle oben ist richtig, und hier ist ein Code, den Sie anstelle von Ihnen benutzen soll, um BOM überspringen:

public static string SerializeObject<T>(object o) 
     { 
      MemoryStream ms = new MemoryStream(); 
      XmlSerializer xs = new XmlSerializer(typeof(T)); 
      //here is my code 
      UTF8Encoding encoding = new UTF8Encoding(false); 
      XmlTextWriter xtw = new XmlTextWriter(ms, encoding); 
      //XmlTextWriter xtw = new XmlTextWriter(ms, Encoding.UTF8); 
      xs.Serialize(xtw, o); 
      ms = (MemoryStream)xtw.BaseStream; 
      return StringHelpers.UTF8ByteArrayToString(ms.ToArray()); 
     } 

von falsch im Konstruktor Angabe Sie sagen, "BOM nicht vorgesehen ist". Genießen! =)

+0

-1, -1, -1: Sie müssen 'using' Blöcke um den' MemoryStream' und den 'XmlWriter' legen. Sie müssen 'XmlTextWriter' nicht verwenden, was seit .NET 2.0 veraltet ist - verwenden Sie stattdessen' XmlWriter.Create'. Der Parameter 'o' sollte vom Typ 'T' sein; unter anderem können Ihre Anrufer nicht angeben - dies wird oft durch den Typ des Parameters impliziert. –

+0

Zustimmen, aber dies ist eine Kopie des ORIGINAL-Code mit nur einer Änderung, so war es nicht mein Ziel, es zu überprüfen und Löcher und Design-Probleme zu finden. Wenn Sie versuchen, diese Diskussion zu lesen, werden Sie wahrscheinlich bemerken, dass ich das Problem gelöst habe, für das ich gebeten wurde. Also nimm dein "-1" raus, Sir. – Restuta