Tuần tự hóa Xml - Ẩn các giá trị null


128

Khi sử dụng Trình tạo nối tiếp .NET Xml tiêu chuẩn, có cách nào để tôi có thể ẩn tất cả các giá trị null không? Dưới đây là một ví dụ về đầu ra của lớp tôi. Tôi không muốn xuất các số nguyên nullable nếu chúng được đặt thành null.

Sản lượng Xml hiện tại:

<?xml version="1.0" encoding="utf-8"?>
<myClass>
   <myNullableInt p2:nil="true" xmlns:p2="http://www.w3.org/2001/XMLSchema-instance" />
   <myOtherInt>-1</myOtherInt>
</myClass>

Những gì tôi muốn:

<?xml version="1.0" encoding="utf-8"?>
<myClass>
   <myOtherInt>-1</myOtherInt>
</myClass>

Câu trả lời:


255

Bạn có thể tạo một hàm với mẫu thông báo ShouldSerialize{PropertyName}cho XmlSerializer xem nó có nên tuần tự hóa thành viên hay không.

Ví dụ: nếu thuộc tính lớp của bạn được gọi, MyNullableIntbạn có thể có

public bool ShouldSerializeMyNullableInt() 
{
  return MyNullableInt.HasValue;
}

Đây là một mẫu đầy đủ

public class Person
{
  public string Name {get;set;}
  public int? Age {get;set;}
  public bool ShouldSerializeAge()
  {
    return Age.HasValue;
  }
}

Nối tiếp với mã sau

Person thePerson = new Person(){Name="Chris"};
XmlSerializer xs = new XmlSerializer(typeof(Person));
StringWriter sw = new StringWriter();
xs.Serialize(sw, thePerson);

Kết quả trong XML theo dõi - Thông báo không có Tuổi

<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>Chris</Name>
</Person>

9
Một từ: Tuyệt vời! MSDN ShouldSerialize
scheien

7
Mẫu ShouldSerialize chỉ hoạt động, nếu thuộc tính không được đánh dấu bằng thuộc tính XmlAttribution (tôi nghĩ rằng nó sẽ hoạt động, bởi vì một thuộc tính có thể là tùy chọn, nhưng nó không).
Matze

@Matze thú vị, tôi chưa thử. Tôi cũng sẽ cho rằng nó sẽ làm việc.
Chris Taylor

@ChrisTaylor Có; Tôi giả sử như vậy. Điều khó khăn là việc tạo cá thể XmlSerializer không thành công (do lỗi khi phản ánh loại) cho đến khi tôi xóa XmlAttribution khỏi thuộc tính intable nullable.
Matze

2
@PierredeLESPINAY - Từ visual studio 2015 trở lên, bạn có thể sử dụng: public bool ShouldSerializeAge () => Age.HasValue;
RooiWillie

34

Ngoài ra với những gì Chris Taylor đã viết: nếu bạn có một thứ gì đó được tuần tự hóa như một thuộc tính, bạn có thể có một thuộc tính trên lớp của bạn được đặt tên {PropertyName}Specifiedđể kiểm soát nếu nó nên được tuần tự hóa. Trong mã:

public class MyClass
{
    [XmlAttribute]
    public int MyValue;

    [XmlIgnore]
    public bool MyValueSpecified;
}

Hãy cẩn thận, {PropertyName}Specifiedcác thuộc tính phải là loại bool.
sinsedrix

30

Nó tồn tại một tài sản được gọi là XmlElementAttribute.IsNullable

Nếu thuộc tính IsNullable được đặt thành true, thuộc tính xsi: nil được tạo cho các thành viên lớp đã được đặt thành tham chiếu null.

Ví dụ sau đây cho thấy một trường XmlElementAttributeđược áp dụng cho nó và thuộc tính IsNullable được đặt thành false.

public class MyClass
{
   [XmlElement(IsNullable = false)]
   public string Group;
}

Bạn có thể có một cái nhìn khác XmlElementAttributeđể thay đổi tên trong serialization, vv


11
Thật không may, điều này chỉ hoạt động cho các loại tham chiếu, không phải cho các loại giá trị hoặc các đối tác Nullable của chúng.
Vincent Sels

3
@VincentSels là chính xác. MSDN nói: Bạn không thể áp dụng thuộc tính IsNullable cho thành viên được nhập dưới dạng loại giá trị vì loại giá trị không thể chứa null. Ngoài ra, bạn không thể đặt thuộc tính này thành false cho các loại giá trị nullable. Khi các kiểu như vậy là null, chúng sẽ được tuần tự hóa bằng cách đặt xsi: nil thành true.
bouvierr

12

Bạn có thể xác định một số giá trị mặc định và nó ngăn các trường không được tuần tự hóa.

    [XmlElement, DefaultValue("")]
    string data;

    [XmlArray, DefaultValue(null)]
    List<string> data;

Thật không may, điều này không hoạt động đối với các loại giá trị vô giá trị
bubi

2

Tôi thích tạo xml của riêng tôi mà không có thẻ tự động tạo. Trong phần này, tôi có thể bỏ qua việc tạo các nút có giá trị null:

public static string ConvertToXML<T>(T objectToConvert)
    {
        XmlDocument doc = new XmlDocument();
        XmlNode root = doc.CreateNode(XmlNodeType.Element, objectToConvert.GetType().Name, string.Empty);
        doc.AppendChild(root);
        XmlNode childNode;

        PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
        foreach (PropertyDescriptor prop in properties)
        {
            if (prop.GetValue(objectToConvert) != null)
            {
                childNode = doc.CreateNode(XmlNodeType.Element, prop.Name, string.Empty);
                childNode.InnerText = prop.GetValue(objectToConvert).ToString();
                root.AppendChild(childNode);
            }
        }            

        return doc.OuterXml;
    }

1
private static string ToXml(Person obj)
{
  XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
  namespaces.Add(string.Empty, string.Empty);

  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,namespaces);
    }
    retval = sb.ToString();
  }
  return retval;
}

1

Trong trường hợp của tôi, các biến / phần tử nullable đều là kiểu String. Vì vậy, tôi chỉ cần thực hiện một kiểm tra và gán cho chúng chuỗi.Empty trong trường hợp NULL. Bằng cách này, tôi đã loại bỏ các thuộc tính nil và xmlns không cần thiết (p3: nil = "true" xmlns: p3 = "http://www.w3.org/2001/XMLSchema-instance)

// Example:

myNullableStringElement = varCarryingValue ?? string.Empty

// OR

myNullableStringElement = myNullableStringElement ?? string.Empty

1
Giải pháp này rất hạn chế và chỉ hoạt động với chuỗi. Đối với các loại khác, chuỗi rỗng vẫn là một giá trị. Một số trình phân tích cú pháp cố gắng tìm thuộc tính và nếu tìm thấy hãy cố gắng chuyển đổi giá trị thành loại mục tiêu. Đối với các trình phân tích cú pháp như vậy, thuộc tính bị thiếu có nghĩa là null và nếu có thuộc tính thì nó phải có giá trị hợp lệ.
ZafarYousafi
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.