การทำให้เป็นอนุกรม XML - ซ่อนค่า null


128

เมื่อใช้ Serializer .NET Xml มาตรฐานมีวิธีใดบ้างที่ฉันสามารถซ่อนค่า null ทั้งหมดได้ ด้านล่างนี้เป็นตัวอย่างผลลัพธ์ของคลาสของฉัน ฉันไม่ต้องการส่งออกจำนวนเต็มที่เป็นโมฆะได้หากตั้งค่าเป็น null

เอาต์พุต Xml ปัจจุบัน:

<?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>

สิ่งที่ฉันต้องการ:

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

คำตอบ:


255

คุณสามารถสร้างฟังก์ชันที่มีรูปแบบShouldSerialize{PropertyName}ซึ่งจะบอก XmlSerializer ว่าควรทำให้สมาชิกเป็นซีเรียลไลซ์หรือไม่

ตัวอย่างเช่นถ้าคุณสมบัติคลาสของคุณถูกเรียกว่าMyNullableIntคุณสามารถมีได้

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

นี่คือตัวอย่างฉบับเต็ม

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

ต่อเนื่องด้วยรหัสต่อไปนี้

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

ผลลัพธ์ใน XML ต่อไปนี้ - โปรดสังเกตว่าไม่มีอายุ

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

9
คำเดียว: สุดยอด! MSDN ShouldSerialize
scheien

7
รูปแบบ ShouldSerialize จะใช้งานได้ก็ต่อเมื่อคุณสมบัติไม่ได้ถูกทำเครื่องหมายด้วย XmlAttribute-attribute (ฉันคิดว่าสิ่งนี้ควรใช้งานได้เนื่องจากแอตทริบิวต์อาจเป็นทางเลือก แต่ไม่ได้)
Matze

@Matze น่าสนใจฉันยังไม่ได้ลอง ฉันก็คิดว่ามันจะได้ผล
Chris Taylor

@ChrisTaylor ครับ; ฉันสันนิษฐานเหมือนกัน สิ่งที่ยุ่งยากคือการสร้างอินสแตนซ์ XmlSerializer ล้มเหลว (เนื่องจากข้อผิดพลาดเมื่อสะท้อนประเภท) จนกว่าฉันจะลบ XmlAttribute ออกจากคุณสมบัติ int ที่เป็นโมฆะ
Matze

2
@PierredeLESPINAY - ตั้งแต่ Visual Studio 2015 ขึ้นไปคุณสามารถใช้: บูลสาธารณะ ShouldSerializeAge () => Age.HasValue;
RooiWillie

34

นอกจากนี้สิ่งที่คริสเทย์เลอร์เขียน: หากคุณมีบางสิ่งที่ทำให้อนุกรมเป็นแอตทริบิวต์คุณสามารถมีคุณสมบัติในคลาสของคุณที่ตั้งชื่อ{PropertyName}Specifiedเพื่อควบคุมว่าควรจะทำให้เป็นอนุกรมหรือไม่ ในรหัส:

public class MyClass
{
    [XmlAttribute]
    public int MyValue;

    [XmlIgnore]
    public bool MyValueSpecified;
}

ระวัง{PropertyName}Specifiedแอตทริบิวต์ต้องเป็นประเภทบูล
sinsedrix

30

มีคุณสมบัติที่เรียกว่า XmlElementAttribute.IsNullable

ถ้าคุณสมบัติ IsNullable ถูกตั้งค่าเป็น true แอ็ตทริบิวต์ xsi: nil จะถูกสร้างขึ้นสำหรับสมาชิกคลาสที่ถูกตั้งค่าเป็นการอ้างอิง null

ตัวอย่างต่อไปนี้แสดงเขตข้อมูลที่XmlElementAttributeนำไปใช้และคุณสมบัติ IsNullable ตั้งค่าเป็นเท็จ

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

คุณสามารถดูอื่น ๆXmlElementAttributeสำหรับการเปลี่ยนชื่อในการทำให้เป็นอนุกรมเป็นต้น


11
น่าเสียดายที่สิ่งนี้ใช้ได้กับประเภทการอ้างอิงเท่านั้นไม่ใช่สำหรับประเภทค่าหรือคู่ที่เป็นโมฆะ
Vincent Sels

3
@ VincentSels ถูกต้อง MSDN กล่าวว่า: คุณไม่สามารถใช้คุณสมบัติ IsNullable กับสมาชิกที่พิมพ์เป็นชนิดค่าได้เนื่องจากชนิดของค่าไม่สามารถมีค่า null ได้ นอกจากนี้คุณไม่สามารถตั้งค่าคุณสมบัตินี้เป็นเท็จสำหรับชนิดค่าว่างได้ เมื่อประเภทดังกล่าวเป็นโมฆะพวกมันจะถูกทำให้เป็นอนุกรมโดยตั้งค่า xsi: nil เป็น true
bouvierr

12

คุณสามารถกำหนดค่าดีฟอลต์บางค่าและป้องกันไม่ให้ฟิลด์ถูกทำให้เป็นอนุกรม

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

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

น่าเสียดายที่สิ่งนี้ใช้ไม่ได้กับประเภทค่าที่เป็น
โมฆะ

2

ฉันชอบสร้าง xml ของตัวเองโดยไม่มีแท็กที่สร้างขึ้นโดยอัตโนมัติ ในสิ่งนี้ฉันสามารถเพิกเฉยต่อการสร้างโหนดด้วยค่า 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

ในกรณีของฉันตัวแปร / องค์ประกอบที่เป็นโมฆะเป็นประเภท String ทั้งหมด ดังนั้นฉันจึงทำการตรวจสอบและกำหนดสตริงให้ว่างเปล่าในกรณีของ NULL ด้วยวิธีนี้ฉันได้กำจัดแอตทริบิวต์ nil และ xmlns ที่ไม่จำเป็น (p3: nil = "true" xmlns: p3 = "http://www.w3.org/2001/XMLSchema-instance)

// Example:

myNullableStringElement = varCarryingValue ?? string.Empty

// OR

myNullableStringElement = myNullableStringElement ?? string.Empty

1
โซลูชันนี้มีข้อ จำกัด มากและใช้ได้กับสตริงเท่านั้น สำหรับสตริงว่างประเภทอื่นยังคงเป็นค่า ตัววิเคราะห์บางตัวพยายามค้นหาแอตทริบิวต์และหากพบให้ลองแปลงค่าเป็นประเภทเป้าหมาย สำหรับตัวแยกวิเคราะห์ดังกล่าวแอตทริบิวต์ที่ขาดหายไปหมายถึงโมฆะและหากมีแอตทริบิวต์จะต้องมีค่าที่ถูกต้อง
ZafarYousafi
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.