2009-08-18 18 views
60

का उपयोग करते हुए खाली xml विशेषता मान को शून्य करने योग्य int गुण में deserializing 0 मुझे तीसरे पक्ष से एक एक्सएमएल मिलता है और मुझे इसे C# ऑब्जेक्ट में deserialize करने की आवश्यकता है। इस एक्सएमएल में पूर्णांक प्रकार या खाली मान के मूल्य वाले गुण हो सकते हैं: attr = "11" या attr = ""। मैं संपत्ति में इस विशेषता मूल्य को निरर्थक पूर्णांक के प्रकार के साथ deserialize करना चाहता हूँ। लेकिन XmlSerializer बेकार प्रकारों में deserialization का समर्थन नहीं करता है। निम्न परीक्षण कोड XmlSerializer के निर्माण के दौरान अमान्यऑपरेशन एक्सेप्शन के साथ विफल रहता है {"टाइप 'TestConsoleAplication.SerializeMe' टाइप करने में त्रुटि हुई।"}।XmlSerializer

[XmlRoot("root")] 
public class SerializeMe 
{ 
    [XmlElement("element")] 
    public Element Element { get; set; } 
} 

public class Element 
{ 
    [XmlAttribute("attr")] 
    public int? Value { get; set; } 
} 

class Program { 
    static void Main(string[] args) { 
     string xml = "<root><element attr=''>valE</element></root>"; 
     var deserializer = new XmlSerializer(typeof(SerializeMe)); 
     Stream xmlStream = new MemoryStream(Encoding.ASCII.GetBytes(xml)); 
     var result = (SerializeMe)deserializer.Deserialize(xmlStream); 
    } 
} 

आई इंट को 'मान' संपत्ति का प्रकार बदलते हैं तो अक्रमांकन InvalidOperationException के साथ विफल:

वहाँ XML दस्तावेज़ (1, 16) में कोई त्रुटि है।

क्या कोई सलाह दे सकता है कि खाली मूल्य के साथ विशेषता को शून्य के प्रकार (शून्य के रूप में) में एकजुट करने के लिए एक ही समय में गैर-खाली विशेषता मान को deserializing कैसे करें? क्या इसके लिए कोई चाल है इसलिए मुझे मैन्युअल रूप से प्रत्येक क्षेत्र का deserialization नहीं करना होगा (वास्तव में उनमें से बहुत सारे हैं)? ahsteele से टिप्पणी के बाद

अद्यतन:

  1. Xsi:nil attribute

    जहाँ तक मुझे पता है, यह विशेषता केवल XmlElementAttribute साथ काम करता है - यह विशेषता निर्दिष्ट तत्व कोई सामग्री नहीं है कि, कि बच्चे तत्वों या शरीर पाठ। लेकिन मुझे XmlAttributeAttribute के लिए समाधान ढूंढना होगा। वैसे भी मैं एक्सएमएल नहीं बदल सकता क्योंकि मेरे पास इसका कोई नियंत्रण नहीं है।

  2. bool *Specified property

    यह गुण काम करता है केवल जब विशेषता मान खाली नहीं है या जब विशेषता अनुपलब्ध है। जब attr में खाली मान होता है (attr = '') XmlSerializer कन्स्ट्रक्टर विफल रहता है (अपेक्षित के रूप में)।

    public class Element 
    { 
        [XmlAttribute("attr")] 
        public int Value { get; set; } 
    
        [XmlIgnore] 
        public bool ValueSpecified; 
    } 
    
  3. Custom Nullable class like in this blog post by Alex Scordellis

    मैं मेरी समस्या के लिए इस ब्लॉग पोस्ट से वर्ग को अपनाने की कोशिश की:

    [XmlAttribute("attr")] 
    public NullableInt Value { get; set; } 
    

    लेकिन XmlSerializer निर्माता InvalidOperationException के साथ विफल:

    को क्रमानुसार नहीं कर सकता सदस्य TestConsoleAplplication.NullableInt प्रकार का 'मान'।

    XmlAttribute/XmlText (मुझ पर शर्म की बात है कि मैं इस कोड यहाँ लिखा :)) IXmlSerializable को लागू प्रकार}

  4. बदसूरत सरोगेट समाधान एन्कोड करने के लिए नहीं किया जा सकता:

    public class Element 
    { 
        [XmlAttribute("attr")] 
        public string SetValue { get; set; } 
    
        public int? GetValue() 
        { 
         if (string.IsNullOrEmpty(SetValue) || SetValue.Trim().Length <= 0) 
          return null; 
    
         int result; 
         if (int.TryParse(SetValue, out result)) 
          return result; 
    
         return null; 
        } 
    } 
    

    लेकिन मैं डॉन इस तरह के समाधान के साथ नहीं आना चाहता क्योंकि यह अपने उपभोक्ताओं के लिए मेरी कक्षा के इंटरफ़ेस को तोड़ देता है। मैं मैन्युअल रूप से IXmlSerializable इंटरफेस को मैन्युअल रूप से कार्यान्वित करता हूं।

वर्तमान में यह है कि मैं पूरे तत्व वर्ग के लिए IXmlSerializable लागू करना लग रहा है (यह बड़ा है) और कोई सरल समाधान का ...

उत्तर

17

मैंने IXmlSerializable इंटरफेस को लागू करके इस समस्या को हल किया। मुझे आसान तरीका नहीं मिला।

यहाँ परीक्षण कोड नमूना है:

[XmlRoot("root")] 
public class DeserializeMe { 
    [XmlArray("elements"), XmlArrayItem("element")] 
    public List<Element> Element { get; set; } 
} 

public class Element : IXmlSerializable { 
    public int? Value1 { get; private set; } 
    public float? Value2 { get; private set; } 

    public void ReadXml(XmlReader reader) { 
     string attr1 = reader.GetAttribute("attr"); 
     string attr2 = reader.GetAttribute("attr2"); 
     reader.Read(); 

     Value1 = ConvertToNullable<int>(attr1); 
     Value2 = ConvertToNullable<float>(attr2); 
    } 

    private static T? ConvertToNullable<T>(string inputValue) where T : struct { 
     if (string.IsNullOrEmpty(inputValue) || inputValue.Trim().Length == 0) { 
      return null; 
     } 

     try { 
      TypeConverter conv = TypeDescriptor.GetConverter(typeof(T)); 
      return (T)conv.ConvertFrom(inputValue); 
     } 
     catch (NotSupportedException) { 
      // The conversion cannot be performed 
      return null; 
     } 
    } 

    public XmlSchema GetSchema() { return null; } 
    public void WriteXml(XmlWriter writer) { throw new NotImplementedException(); } 
} 

class TestProgram { 
    public static void Main(string[] args) { 
     string xml = @"<root><elements><element attr='11' attr2='11.3'/><element attr='' attr2=''/></elements></root>"; 
     XmlSerializer deserializer = new XmlSerializer(typeof(DeserializeMe)); 
     Stream xmlStream = new MemoryStream(Encoding.ASCII.GetBytes(xml)); 
     var result = (DeserializeMe)deserializer.Deserialize(xmlStream); 
    } 
} 
9

मैं देर से अपने आप को क्रमबद्धता के साथ चारों ओर खिलवाड़ किया गया है एक बहुत देखते हैं और मान प्रकारों के लिए शून्य डेटा से निपटने के दौरान निम्नलिखित लेख और पोस्ट उपयोगी पाए हैं।

How to make a value type nullable with XmlSerializer in C# - serialization का उत्तर XmlSerializer की एक सुंदर निफ्टी चाल का विवरण देता है। विशेष रूप से, XmlSerialier यह निर्धारित करने के लिए कि क्या इसे शामिल किया जाना चाहिए, यह निर्धारित करने के लिए XSSxialied बूलियन प्रॉपर्टी की तलाश करता है जो आपको नल को अनदेखा करने की अनुमति देता है।

एलेक्स स्कोर्डेलिस ने एक स्टैक ओवरफ्लो प्रश्न पूछा जो a good answer प्राप्त हुआ। एलेक्स ने Using XmlSerializer to deserialize into a Nullable<int> को हल करने की कोशिश कर रहे समस्या के बारे में अपने ब्लॉग पर एक अच्छा लेखन भी किया।

Xsi:nil Attribute Binding Support पर एमएसडीएन दस्तावेज भी उपयोगी है। जैसा कि IXmlSerializable Interface पर प्रलेखन है, यद्यपि अपना स्वयं का कार्यान्वयन लिखना आपका अंतिम उपाय होना चाहिए।

+0

"एक Nullable में deserialize करने के लिए XmlSerializer का उपयोग करना" रूपांतरण के साथ-साथ किसी भी संभावित नल प्रविष्टियों का प्रतिनिधित्व करने के लिए लिंक मर चुका है । [यहां Google से एक कैश संस्करण है] (http://webcache.googleusercontent.com/search?q=cache:vT5GiyOCWyIJ:www.rqna.net/qna/zzrzt-deserialise-missing-xml-attribute-to-nullable-type । एचटीएमएल) – Anttu

+0

@ एंटू मैंने मूल * के वेबैक मशीन संग्रह के जवाब में लिंक को स्विच किया है जिसका उपयोग एक्सएमएलएसरियललाइज़र का उपयोग करने के लिए एक नालीबल * में deserialize करने के लिए किया गया है। – ahsteele

43

यह काम करना चाहिए: एक कस्टम प्रकार बनाने के द्वारा इस समस्या को हल:

[XmlIgnore] 
public int? Age { get; set; } 

[XmlElement("Age")] 
public string AgeAsText 
{ 
    get { return (Age.HasValue) ? Age.ToString() : null; } 
    set { Age = !string.IsNullOrEmpty(value) ? int.Parse(value) : default(int?); } 
} 
+4

यह काम करेगा, लेकिन यह मेरे प्रश्न से संख्या 4 के समान समाधान है)। मैं अपनी कक्षा के सार्वजनिक इंटरफ़ेस में सरोगेट फ़ील्ड पेश नहीं करना चाहता हूं। धन्यवाद –

+4

एफडब्ल्यूआईडब्ल्यू, मुझे यह समाधान स्पष्ट IXmlSerializable कार्यान्वयन (स्वीकृत समाधान) से बेहतर होने के लिए मिलता है, हालांकि ओपी के विशिष्ट प्रश्न के लिए नहीं। मैं IXmlSerializable को लागू करने से बचने तक पूरी तरह से जरूरी नहीं है, यह पता लगाने के लिए कि यह लंबे समय तक रखरखाव में मुझे और अधिक लागत दे रहा है। इस तरह के एक साधारण मामले में और बिना किसी अन्य कमजोर कारकों के, मैं इसे "बदसूरत" सरोगेट समाधान के लिए दूसरा विचार देने के बिना जाऊंगा। –

2

सोचा मैं भी टोपी में मेरा उत्तर फेंक सकती है जो IXmlSerializable इंटरफ़ेस लागू करता है:

कहें कि आपके पास निम्न नोड्स के साथ एक XML ऑब्जेक्ट है:

<ItemOne>10</Item2> 
<ItemTwo /> 

वस्तु उन्हें प्रतिनिधित्व करने के लिए:

public class MyItems { 
    [XmlElement("ItemOne")] 
    public int ItemOne { get; set; } 

    [XmlElement("ItemTwo")] 
    public CustomNullable<int> ItemTwo { get; set; } // will throw exception if empty element and type is int 
} 

गतिशील नल struct

public struct CustomNullable<T> : IXmlSerializable where T: struct { 
    private T value; 
    private bool hasValue; 

    public bool HasValue { 
     get { return hasValue; } 
    } 

    public T Value { 
     get { return value; } 
    } 

    private CustomNullable(T value) { 
     this.hasValue = true; 
     this.value = value; 
    } 

    public XmlSchema GetSchema() { 
     return null; 
    } 

    public void ReadXml(XmlReader reader) { 
     string strValue = reader.ReadString(); 
     if (String.IsNullOrEmpty(strValue)) { 
      this.hasValue = false; 
     } 
     else { 
      T convertedValue = strValue.To<T>(); 
      this.value = convertedValue; 
      this.hasValue = true; 
     } 
     reader.ReadEndElement(); 

    } 

    public void WriteXml(XmlWriter writer) { 
     throw new NotImplementedException(); 
    } 

    public static implicit operator CustomNullable<T>(T value) { 
     return new CustomNullable<T>(value); 
    } 

} 

public static class ObjectExtensions { 
    public static T To<T>(this object value) { 
     Type t = typeof(T); 
     // Get the type that was made nullable. 
     Type valueType = Nullable.GetUnderlyingType(typeof(T)); 
     if (valueType != null) { 
      // Nullable type. 
      if (value == null) { 
       // you may want to do something different here. 
       return default(T); 
      } 
      else { 
       // Convert to the value type. 
       object result = Convert.ChangeType(value, valueType); 
       // Cast the value type to the nullable type. 
       return (T)result; 
      } 
     } 
     else { 
      // Not nullable. 
      return (T)Convert.ChangeType(value, typeof(T)); 
     } 
    } 
}