XML में TimeSpan कैसे क्रमबद्ध करें


206

मैं TimeSpanXML के लिए एक .NET ऑब्जेक्ट को क्रमबद्ध करने की कोशिश कर रहा हूं और यह काम नहीं कर रहा है। एक त्वरित Google ने सुझाव दिया है कि TimeSpanधारावाहिक होने के दौरान, वस्तुओं को XML से और XmlCustomFormatterपरिवर्तित करने के लिए तरीके प्रदान नहीं करता है TimeSpan

एक सुझाया गया दृष्टिकोण TimeSpanक्रमबद्धता के लिए उपेक्षा करना था , और इसके बजाय TimeSpan.Ticks(और new TimeSpan(ticks)विचलन के लिए उपयोग ) के परिणाम को क्रमबद्ध करना था । इसका एक उदाहरण इस प्रकार है:

[Serializable]
public class MyClass
{
    // Local Variable
    private TimeSpan m_TimeSinceLastEvent;

    // Public Property - XmlIgnore as it doesn't serialize anyway
    [XmlIgnore]
    public TimeSpan TimeSinceLastEvent
    {
        get { return m_TimeSinceLastEvent; }
        set { m_TimeSinceLastEvent = value; }
    }

    // Pretend property for serialization
    [XmlElement("TimeSinceLastEvent")]
    public long TimeSinceLastEventTicks
    {
        get { return m_TimeSinceLastEvent.Ticks; }
        set { m_TimeSinceLastEvent = new TimeSpan(value); }
    }
}

जबकि यह मेरे संक्षिप्त परीक्षण में काम करता है - क्या इसे प्राप्त करने का सबसे अच्छा तरीका है?

क्या XML से और उसके लिए TimeSpan को क्रमबद्ध करने का एक बेहतर तरीका है?


4
Rory MacLeod का जवाब नीचे दिया गया है जिस तरह से Microsoft ऐसा करने की सिफारिश करता है।
जेफ

2
मैं टाइमस्पैंड के लिए लंबे समय तक टिक का उपयोग नहीं करूंगा क्योंकि एक्सएमएल की अवधि सटीक मिलान है। इस मुद्दे को वर्ष 2008 में Microsoft के समक्ष उठाया गया था लेकिन कभी हल नहीं किया गया। वहाँ एक वर्कअराउंड डॉक्यूमेंट किया गया है: kennethxu.blogspot.com/2008/09/…
केनेथ जू

जवाबों:


71

आपके द्वारा पहले से पोस्ट किया गया तरीका शायद सबसे साफ है। यदि आपको अतिरिक्त संपत्ति पसंद नहीं है IXmlSerializable, तो आप इसे लागू कर सकते हैं , लेकिन फिर आपको वह सब कुछ करना होगा , जो मुख्य रूप से बिंदु को हरा देता है। मैं खुशी से आपके द्वारा पोस्ट किए गए दृष्टिकोण का उपयोग करूंगा; यह (उदाहरण के लिए) कुशल (कोई जटिल पार्सिंग आदि) नहीं है, संस्कृति स्वतंत्र, अस्पष्ट और टाइमस्टैम्प-प्रकार की संख्या आसानी से और आमतौर पर समझ में आती है।

एक तरफ के रूप में, मैं अक्सर जोड़ता हूं:

[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]

यह सिर्फ यूआई में छुपाता है और भ्रम से बचने के लिए, डीएल को संदर्भित करता है।


5
यदि आप MyClass पर इसे लागू करने के बजाय System.TimeSpan को लपेटते हैं, तो आप इंटरफ़ेस को लागू करने पर सब कुछ इतना बुरा नहीं है। तब आपको केवल अपने
MyClass.TimeSinceLastEvent

103

यह प्रश्न में सुझाए गए दृष्टिकोण पर केवल एक मामूली संशोधन है, लेकिन यह Microsoft कनेक्ट समस्या इस तरह से क्रमांकन के लिए एक संपत्ति का उपयोग करने की सिफारिश करता है:

[XmlIgnore]
public TimeSpan TimeSinceLastEvent
{
    get { return m_TimeSinceLastEvent; }
    set { m_TimeSinceLastEvent = value; }
}

// XmlSerializer does not support TimeSpan, so use this property for 
// serialization instead.
[Browsable(false)]
[XmlElement(DataType="duration", ElementName="TimeSinceLastEvent")]
public string TimeSinceLastEventString
{
    get 
    { 
        return XmlConvert.ToString(TimeSinceLastEvent); 
    }
    set 
    { 
        TimeSinceLastEvent = string.IsNullOrEmpty(value) ?
            TimeSpan.Zero : XmlConvert.ToTimeSpan(value); 
    }
}

यह समयसमूह 0:02:45 को क्रमबद्ध करेगा:

<TimeSinceLastEvent>PT2M45S</TimeSinceLastEvent>

वैकल्पिक रूप से, DataContractSerializerTimeSpan का समर्थन करता है।


15
XmlConvert.ToTimeSpan () के लिए +1। यह PT2H15M जैसे टाइमपेन के लिए ISO मानक अवधि सिंटैक्स को हैंडल करता है, en.wikipedia.org/wiki/ISO_8601#Durations
yzorg

2
अगर मैं गलत हूं तो मुझे सुधारें, लेकिन समयसमय पर "पीटी 2 एम 45 एस" 00:02:45 नहीं, 2:45:00 है।
टॉम पैजोर्रेक

कनेक्ट लिंक अब टूट गया है, शायद इसे इस एक के साथ बदला जा सकता है: connect.microsoft.com/VisualStudio/feedback/details/684819/… ? तकनीक भी कुछ अलग लगती है ...
TJB

एक अजीब सवाल का पालन करने के लिए, क्या हमारे पास इस मूल्य PT2M45S को एसक्यूएल में टाइम के लिए डिसेररलाइज करने का एक तरीका है?
Xander

28

कुछ चीजें जो कुछ मामलों में काम कर सकती हैं, वह है आपकी सार्वजनिक संपत्ति को एक बैकिंग फ़ील्ड देना, जो टाइमस्पैन है, लेकिन सार्वजनिक संपत्ति को एक स्ट्रिंग के रूप में उजागर किया जाता है।

उदाहरण के लिए:

protected TimeSpan myTimeout;
public string MyTimeout 
{ 
    get { return myTimeout.ToString(); } 
    set { myTimeout = TimeSpan.Parse(value); }
}

यह ठीक है अगर संपत्ति का मूल्य ज्यादातर w / युक्त वर्ग या विरासत वाली कक्षाओं में उपयोग किया जाता है और xml कॉन्फ़िगरेशन से लोड किया जाता है।

अन्य प्रस्तावित समाधान बेहतर हैं यदि आप चाहते हैं कि सार्वजनिक संपत्ति अन्य वर्गों के लिए एक उपयोगी टाइमस्पैन मान हो।


अब तक का सबसे आसान उपाय। मैं बिल्कुल उसी चीज के साथ आया हूं और यह एक आकर्षण की तरह काम करता है। लागू करने और समझने में आसान।
wpfwannabe

1
यह यहां का सबसे अच्छा समाधान है। यह बहुत अच्छा serializes !!! इनपुट मित्र के लिए धन्यवाद!
डेवलपर

25

रंग क्रमांकन और इस मूल समाधान (जो अपने आप में महान है) से एक उत्तर का संयोजन मुझे यह समाधान मिला:

[XmlElement(Type = typeof(XmlTimeSpan))]
public TimeSpan TimeSinceLastEvent { get; set; }

जहां XmlTimeSpanवर्ग इस तरह है:

public class XmlTimeSpan
{
    private const long TICKS_PER_MS = TimeSpan.TicksPerMillisecond;

    private TimeSpan m_value = TimeSpan.Zero;

    public XmlTimeSpan() { }
    public XmlTimeSpan(TimeSpan source) { m_value = source; }

    public static implicit operator TimeSpan?(XmlTimeSpan o)
    {
        return o == null ? default(TimeSpan?) : o.m_value;
    }

    public static implicit operator XmlTimeSpan(TimeSpan? o)
    {
        return o == null ? null : new XmlTimeSpan(o.Value);
    }

    public static implicit operator TimeSpan(XmlTimeSpan o)
    {
        return o == null ? default(TimeSpan) : o.m_value;
    }

    public static implicit operator XmlTimeSpan(TimeSpan o)
    {
        return o == default(TimeSpan) ? null : new XmlTimeSpan(o);
    }

    [XmlText]
    public long Default
    {
        get { return m_value.Ticks / TICKS_PER_MS; }
        set { m_value = new TimeSpan(value * TICKS_PER_MS); }
    }
}

इस समस्या को हल करने का सबसे अच्छा और आसान तरीका ... मेरे लिए
मोरारू विओरेल

यह बिल्कुल सरल है - मैं सुपर प्रभावित हूँ!
जिम

9

आप TimeSpan संरचना के चारों ओर एक प्रकाश आवरण बना सकते हैं:

namespace My.XmlSerialization
{
    public struct TimeSpan : IXmlSerializable
    {
        private System.TimeSpan _value;

        public static implicit operator TimeSpan(System.TimeSpan value)
        {
            return new TimeSpan { _value = value };
        }

        public static implicit operator System.TimeSpan(TimeSpan value)
        {
            return value._value;
        }

        public XmlSchema GetSchema()
        {
            return null;
        }

        public void ReadXml(XmlReader reader)
        {
            _value = System.TimeSpan.Parse(reader.ReadContentAsString());
        }

        public void WriteXml(XmlWriter writer)
        {
            writer.WriteValue(_value.ToString());
        }
    }
}

नमूना क्रमबद्ध परिणाम:

<Entry>
  <StartTime>2010-12-06T08:45:12.5</StartTime>
  <Duration>2.08:29:35.2500000</Duration>
</Entry>

किसी भी विचार कैसे XmlAttribute के रूप में उत्पादन करने के लिए?
ala

@ बाला, अगर मैं आपके प्रश्न को सही ढंग से समझता हूं, तो इसका जवाब यह है कि जिस संपत्ति को आप एक विशेषता के रूप में व्यक्त करना चाहते हैं, उसके लिए XmlAttributeAttribute को लागू करें। यह निश्चित रूप से TimeSpan के लिए विशेष रूप से नहीं है।
2

+1 नाइस, सिवाय इसके कि मैं इसे स्ट्रिंग के रूप में नहीं बल्कि Ticksलंबे समय तक सीरीज़ करुँगी ।
क्रिसव्यू

@ChrisWue मेरे कार्यालय में हम xml क्रमांकन का उपयोग करते हैं जब हम मानव-पठनीय आउटपुट चाहते हैं; एक समय के रूप में एक टाइमपैन को क्रमबद्ध करना उस लक्ष्य के साथ काफी संगत नहीं है। यदि आप एक अलग कारण के लिए xml क्रमांकन का उपयोग करते हैं, तो निश्चित रूप से, टिकों को क्रमबद्ध करने से अधिक अर्थ हो सकता है।
फोग

8

एक अधिक पठनीय विकल्प एक स्ट्रिंग के रूप में क्रमबद्ध करना होगा और TimeSpan.Parseइसे डिसेर्बलाइज करने की विधि का उपयोग करना होगा। आप अपने उदाहरण के रूप में वही कर सकते हैं लेकिन TimeSpan.ToString()गेट्टर और TimeSpan.Parse(value)सेटर में उपयोग कर रहे हैं ।


2

एक अन्य विकल्प यह होगा कि इसे SoapFormatterकक्षा के बजाय कक्षा का उपयोग करके अनुक्रमित किया जाए XmlSerializer

परिणामी XML फ़ाइल कुछ अलग दिखती है ... कुछ "SOAP" -प्रकाशित टैग, आदि ... लेकिन यह कर सकता है।

यहां SoapFormatter20 घंटे और 28 मिनट के समय के धारावाहिक का क्या मतलब है:

<myTimeSpan>P0Y0M0DT20H28M0S</myTimeSpan>

SOAPFormatter वर्ग का उपयोग करने के लिए, System.Runtime.Serialization.Formatters.Soapउसी नाम के नामस्थान का संदर्भ जोड़ने और उपयोग करने की आवश्यकता है ।


यह इस तरह से .net 4.0
Kirk Broadhurst

1

समाधान का मेरा संस्करण :)

[DataMember, XmlIgnore]
public TimeSpan MyTimeoutValue { get; set; }
[DataMember]
public string MyTimeout
{
    get { return MyTimeoutValue.ToString(); }
    set { MyTimeoutValue = TimeSpan.Parse(value); }
}

संपादित करें: यह मानते हुए कि यह अशक्त है ...

[DataMember, XmlIgnore]
public TimeSpan? MyTimeoutValue { get; set; }
[DataMember]
public string MyTimeout
{
    get 
    {
        if (MyTimeoutValue != null)
            return MyTimeoutValue.ToString();
        return null;
    }
    set 
    {
        TimeSpan outValue;
        if (TimeSpan.TryParse(value, out outValue))
            MyTimeoutValue = outValue;
        else
            MyTimeoutValue = null;
    }
}

1

Timespan सेकंड की संख्या के रूप में xml में संग्रहीत है, लेकिन इसे अपनाना आसान है, मुझे उम्मीद है। Timespan मैन्युअल रूप से क्रमबद्ध (IXmlSerializable लागू करने):

public class Settings : IXmlSerializable
{
    [XmlElement("IntervalInSeconds")]
    public TimeSpan Interval;

    public XmlSchema GetSchema()
    {
        return null;
    }

    public void WriteXml(XmlWriter writer)
    {
        writer.WriteElementString("IntervalInSeconds", ((int)Interval.TotalSeconds).ToString());
    }

    public void ReadXml(XmlReader reader)
    {
        string element = null;
        while (reader.Read())
        {
            if (reader.NodeType == XmlNodeType.Element)
                element = reader.Name;
            else if (reader.NodeType == XmlNodeType.Text)
            {
                if (element == "IntervalInSeconds")
                    Interval = TimeSpan.FromSeconds(double.Parse(reader.Value.Replace(',', '.'), CultureInfo.InvariantCulture));
            }
       }
    }
}

अधिक व्यापक उदाहरण है: https://bitbucket.org/njkazakov/timespan-serialization

Settings.cs को देखें। और XmlElementAttribute का उपयोग करने के लिए कुछ मुश्किल कोड है।


1
कृपया उस लिंक से संबंधित जानकारी उद्धृत करें। आपके उत्तर के लिए आवश्यक सभी जानकारी इस साइट पर होनी चाहिए, और फिर आप उस लिंक को स्रोत के रूप में उद्धृत कर सकते हैं।
सुपरबाइडमैन

0

डेटा अनुबंध क्रमांकन के लिए मैं निम्नलिखित का उपयोग करता हूं।

  • अनुक्रमित संपत्ति को निजी रखने से सार्वजनिक इंटरफ़ेस साफ रहता है।
  • क्रमबद्धता के लिए सार्वजनिक संपत्ति के नाम का उपयोग करना XML को साफ रखता है।
Public Property Duration As TimeSpan

<DataMember(Name:="Duration")>
Private Property DurationString As String
    Get
        Return Duration.ToString
    End Get
    Set(value As String)
        Duration = TimeSpan.Parse(value)
    End Set
End Property

0

यदि आप कोई वर्कअराउंड नहीं चाहते हैं, तो System.Runtime.Serialization.dll से DataContractSerializer वर्ग का उपयोग करें।

        using (var fs = new FileStream("file.xml", FileMode.Create))
        {
            var serializer = new DataContractSerializer(typeof(List<SomeType>));
            serializer.WriteObject(fs, _items);
        }

-2

इसे इस्तेमाल करे :

//Don't Serialize Time Span object.
        [XmlIgnore]
        public TimeSpan m_timeSpan;
//Instead serialize (long)Ticks and instantiate Timespan at time of deserialization.
        public long m_TimeSpanTicks
        {
            get { return m_timeSpan.Ticks; }
            set { m_timeSpan = new TimeSpan(value); }
        }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.