2010-01-15 25 views
9

Trong mã sau, tôi serialize một đối tượng vào một chuỗi XML.Làm cách nào để thay đổi chuỗi XML này sao cho XDocument.Parse đọc nó?

Nhưng khi tôi cố gắng đọc chuỗi XML thành một XDocument với XDocument.Parse, nó mang lại cho tôi lỗi này:

dữ liệu không hợp lệ ở mức root.

XML là:

<?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: Đây là hex:

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

gì làm tôi phải làm gì để XML này để nó đọc vào XDocument không có lỗi?

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

    } 
} 

ĐÁP:

Cảm ơn Andras, GetPreamble() cố định nó, vì vậy đối với bất cứ ai khác đối phó với điều này, đây là một phương pháp ít để làm sạch XML của bạn của 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

Không có gì sai với XML đó. Bạn có chắc đó là cùng một XML gây ra ngoại lệ? –

+0

Dữ liệu không hợp lệ ở cấp cơ sở, dòng 1, ký tự 1. Khi tôi sao chép văn bản vào NotePad ++, ký tự đầu tiên là "?" và trong các biên tập viên khác một số nhân vật điều khiển ... –

+0

Sau đó, bạn bị mất "<" mở trong khi cắt và dán. Không có gì sai với XML. –

Trả lời

15

Đó là vì dữ liệu chứa unicode hoặc utf8 BOM marks ở đầu luồng.

Bạn cần bỏ qua bất kỳ Dấu đơn hàng nào trong luồng - bạn có thể xác định các điểm này từ phương thức System.Text.Encoding.GetPreamble().

+0

bạn thường xuyên gặp phải vấn đề này khi tạo tệp XML trong Notepad. VS cũng có thể thêm chúng đôi khi quá. –

+0

Sử dụng GetPreamble() là một nỗ lực để giải quyết hậu quả thay vì lý do. Hãy nhìn vào câu trả lời của tôi. – Restuta

+0

Vâng, đó là câu trả lời hay - và nó hoạt động, nếu mã hóa luôn là UTF8. Tuy nhiên, bằng cách sử dụng phương pháp GetPreamble, bạn có thể tự động phát hiện mã hóa của một tệp, có nghĩa là bạn không bị ràng buộc với chỉ một tệp. Sau khi được chọn, bạn có thể điều chỉnh mẫu mã của mình để chứa mã hóa bất kỳ. –

1

Bạn có thể giải quyết vấn đề của bạn bằng cách sử dụng một StreamReader để chuyển đổi dữ liệu trong MemoryStream thành một chuỗi thay vì:

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' không được dùng nữa. Thay vào đó, hãy sử dụng 'XmlWriter.Create'. –

+0

@John: trình biên dịch không có thông tin về 'XmlTextWriter' bị phản đối. Tôi biết về đề xuất 'XmlWriter.Create', nhưng tôi không muốn thay đổi mã OP nhiều hơn mức cần thiết để giải quyết vấn đề. Tuy nhiên, hãy cập nhật mẫu mã của tôi để làm theo đề xuất. –

-1

Tất cả trên là chính xác, và đây là một mã mà bạn nên sử dụng thay vì bạn để skip 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()); 
     } 

Bằng cách xác định sai trong constructor bạn nói "BOM không được cung cấp". Thưởng thức! =)

+0

-1, -1, -1: Bạn cần đặt các khối 'using' xung quanh' MemoryStream' và 'XmlWriter'. Bạn không cần sử dụng 'XmlTextWriter', đã không được dùng nữa kể từ .NET 2.0 - sử dụng' XmlWriter.Create' để thay thế. Tham số 'o' phải thuộc kiểu' T'; trong số những thứ khác, điều này sẽ cho phép người gọi của bạn không chỉ định - nó thường sẽ được ngụ ý bởi loại tham số. –

+0

Đồng ý, nhưng đây là BẢN SAO của mã GỐC với chỉ một sửa đổi, vì vậy nó không phải là mục tiêu của tôi để xem xét nó và tìm lỗ hổng và các vấn đề thiết kế. Nếu bạn sẽ cố gắng đọc cuộc thảo luận này, bạn có thể sẽ nhận thấy rằng tôi đã giải quyết được vấn đề mà tôi đã HỎI. Vì vậy, đưa "-1" của bạn ra, thưa bạn. – Restuta

Các vấn đề liên quan