2010-01-15 9 views
9

Nel seguente codice, I serializza un oggetto in una stringa XML .Come devo cambiare questa stringa XML in modo che XDocument.Parse lo legga?

Ma quando provo a leggere questa stringa XML in un XDocument con XDocument.Parse, mi dà questo errore :

dati non validi a livello root.

L'XML è:

<?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: Ecco l'esagono:

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

Cosa devo fare per questo XML in modo che legga in l'XDocument senza errori?

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

    } 
} 

RISPOSTA:

Grazie Andras, GetPreamble() fisso, quindi per chiunque altro che fare con questo, ecco un po 'di metodo per pulire il vostro XML del BOM:

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

Non c'è niente di sbagliato in questo XML. Sei sicuro che sia lo stesso XML che causa l'eccezione? –

+0

Dati non validi a livello di root, riga 1, carattere 1. Quando copio il testo in NotePad ++, il primo carattere è un "?" e in altri editor alcuni caratteri di controllo ... –

+0

Quindi hai perso l'apertura "<" durante il taglia e incolla. Non c'è niente di sbagliato nell'XML. –

risposta

15

È perché i dati contengono l'unicode o utf8 BOM marks all'inizio dello stream.

È necessario saltare tutti i segni di ordine dei byte nello stream: è possibile identificarli dal metodo System.Text.Encoding.GetPreamble().

+0

si verifica spesso questo problema durante la creazione di file XML in Blocco note. VS può anche aggiungerli a volte anche. –

+0

Utilizzare GetPreamble() è un tentativo di risolvere le conseguenze anziché la ragione. Guarda la mia risposta per favore. – Restuta

+0

Sì, questa è una buona risposta, e funziona, se la codifica è sempre UTF8. Tuttavia, utilizzando il metodo GetPreamble è possibile rilevare automaticamente la codifica di un file, il che significa che non si è vincolati a uno solo. Una volta selezionato, è quindi possibile regolare il codice di esempio per adattarsi a qualsiasi codifica. –

1

È possibile risolvere il problema utilizzando un StreamReader per convertire i dati in MemoryStream in una stringa invece:

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' è deprecato. Usa invece 'XmlWriter.Create'. –

+0

@John: il compilatore non rilascia informazioni su 'XmlTextWriter' che sono deprecate. Conosco il consiglio 'XmlWriter.Create', ma non volevo modificare il codice OP più del necessario per risolvere il problema. Ancora, aggiornato il mio codice di esempio per seguire la raccomandazione. –

-1

Tutti sopra è corretto, e qui è un codice che si dovrebbe utilizzare al posto di vostro da saltare BOM:

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

specificando falso nel costruttore si dice "BOM non è previsto". Godere! =)

+0

-1, -1, -1: è necessario inserire i blocchi 'using' attorno a' MemoryStream' e 'XmlWriter'. Non devi usare 'XmlTextWriter', che è stato deprecato da .NET 2.0 - usa invece' XmlWriter.Create'. Il parametro 'o' dovrebbe essere di tipo' T'; tra le altre cose, ciò consentirebbe ai chiamanti di non specificare - sarà spesso implicito dal tipo di parametro. –

+0

Accetto, ma questa è una COPIA del codice ORIGINALE con una sola modifica, quindi non era il mio obiettivo esaminarlo e trovare buchi e problemi di progettazione. Se cercherete di leggere questa discussione, probabilmente noterete che ho risolto il problema per il quale sono stato CHIESTO. Quindi togliti il ​​"-1", signore. – Restuta

Problemi correlati