2012-03-12 38 views
6

Xem xét XML sau:Deserialize Xml với các yếu tố có sản phẩm nào

<a> 
    <b>2</b> 
    <c></c> 
</a> 

tôi cần phải deserialize xml này cho một đối tượng. Vì vậy, tôi đã viết lớp sau.

public class A 
{ 
    [XmlElement("b", Namespace = "")] 
    public int? B { get; set; } 

    [XmlElement("c", Namespace = "")] 
    public int? C { get; set; } 

} 

Vì tôi đang sử dụng nullables, tôi đã mong đợi rằng, khi deserialing xml trên, tôi sẽ nhận được đối tượng A có thuộc tính null C.

Thay vì điều này, tôi nhận được một ngoại lệ cho biết tài liệu có lỗi.

+0

là * không * null. Nó là một chuỗi có độ dài bằng không. –

+0

Vui lòng không thêm tiền tố vào tiêu đề của bạn bằng "C#". Đó là những gì các thẻ cho. –

Trả lời

7

Có sự khác biệt giữa yếu tố thiếu và yếu tố null.

Phần tử bị thiếu, <a><b>2</b></a>. Tại đây C sẽ lấy bất kỳ giá trị mặc định nào bạn chỉ định, bằng cách sử dụng thuộc tính DefaultValue hoặc null nếu không có mặc định rõ ràng.

Phần tử rỗng <a><b>2</b><c xs:Nil='true'/></a>. Ở đây bạn sẽ nhận được null.

Khi bạn làm <a><b>2</b><c></c><a/> bộ nối tiếp xml sẽ cố gắng phân tích cú pháp chuỗi.Empty dưới dạng số nguyên sẽ thất bại chính xác.

Kể từ khi nhà cung cấp của bạn được tạo ra xml hợp lệ bạn sẽ cần phải làm điều này, nếu sử dụng XmlSerializer:

[XmlRoot(ElementName = "a")] 
public class A 
{ 
    [XmlElement(ElementName = "b")] 
    public int? B { get; set; } 

    [XmlElement(ElementName = "c")] 
    public string _c { get; set; } 

    public int? C 
    { 
     get 
     { 
      int retval; 

      return !string.IsNullOrWhiteSpace(_c) && int.TryParse(_c, out retval) ? (int?) retval : null; 
     } 
    } 
} 

hoặc tốt hơn một chút bằng cách sử dụng DataContractSerializer

[DataContract(Name="a")] 
public class A1 
{ 
    [DataMember(Name = "b")] 
    public int? B { get; set; } 

    [DataMember(Name = "c")] 
    private string _c { get; set; } 

    public int? C 
    { 
     get 
     { 
      int retval; 

      return !string.IsNullOrWhiteSpace(_c) && int.TryParse(_c, out retval) ? (int?)retval : null; 
     } 
    } 
} 

mặc dù DataContractSerializer không hỗ trợ các thuộc tính nếu đó là một vấn đề.

+0

Cảm ơn bài đăng của bạn. Tôi biết những gì bạn đang nói với tôi. Nhưng tôi không có quyền kiểm soát dữ liệu xml (nó đến từ một dịch vụ bên ngoài). Và nhà cung cấp dịch vụ sevice đang trả lại khi thực tế nó sẽ trả lại một xs: Nil = 'true', vì vậy tôi phải giải quyết vấn đề này. –

+0

Bạn sẽ cần phải tạo một chuỗi C và sau đó có một thuộc tính trình bao bọc để phân tích cú pháp chuỗi được deserialized thành một int? theo yêu cầu. – Phil

+0

Cảm ơn. Không nên thử nghiệm của bạn là "Strng.IsNullOrEmpty" thay vì "IsNullOrWhiteSpace"? Bạn không cần phải thực hiện phép thử lại (int?). Tuy nhiên, để tránh lỗi biên dịch, chúng ta cần phải cast (int?) Null –

1

Để deserialize thẻ trống như 'c' trong ví dụ của bạn:

<foo> 
     <b>2</b> 
     <c></c> 
    </foo> 

tôi đã sử dụng phương pháp này. Đầu tiên nó loại bỏ các phần tử rỗng hoặc rỗng khỏi tệp XML bằng cách sử dụng LINQ và sau đó nó deserialize tài liệu mới mà không có các thẻ rỗng hoặc rỗng cho lớp Foo.

public static Foo ReadXML(string file) 
    { 
      Foo foo = null; 
      XDocument xdoc = XDocument.Load(file); 
      xdoc.Descendants().Where(e => string.IsNullOrEmpty(e.Value)).Remove(); 

      XmlSerializer xmlSer = new XmlSerializer(typeof(Foo)); 
      using (var reader = xdoc.Root.CreateReader()) 
      { 
       foo = (Foo)xmlSer.Deserialize(reader); 
       reader.Close(); 
      } 
      if (foo == null) 
       foo = new Foo(); 

      return foo; 
    } 

Điều này sẽ cung cấp cho bạn giá trị mặc định trên các thuộc tính bị thiếu.

foo.b = 2; 
    foo.c = 0; //for example, if it's an integer 

tôi kết hợp thông tin từ này liên kết:

Remove empty XML tags

Use XDocument as the source for XmlSerializer.Deserialize?

+0

Tại sao không 'xdoc.Descendants(). Ở đâu (e => e.IsEmpty || String.IsNullOrWhiteSpace (e.Value))'? – stomy

+0

Bạn cũng có thể thực hiện bằng cách sử dụng (TextReader reader = new StringReader (xdoc.ToString())) 'thay thế. – stomy

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