एक्सएमएल के लिए एक वस्तु को सीरियल करें


292

मेरे पास एक सी # क्लास है जो मुझे विरासत में मिली है। मैंने सफलतापूर्वक ऑब्जेक्ट का "निर्माण" किया है। लेकिन मुझे XML को ऑब्जेक्ट को क्रमबद्ध करना होगा। वहाँ यह करने के लिए एक आसान तरीका है?

ऐसा लगता है कि वर्ग को क्रमांकन के लिए स्थापित किया गया है, लेकिन मुझे यह सुनिश्चित नहीं है कि एक्सएमएल प्रतिनिधित्व कैसे प्राप्त करें। मेरी कक्षा की परिभाषा इस प्रकार है:

[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.1")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.domain.com/test")]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.domain.com/test", IsNullable = false)]
public partial class MyObject
{
  ...
}

यहाँ मैंने सोचा कि मैं क्या कर सकता था, लेकिन यह काम नहीं करता है:

MyObject o = new MyObject();
// Set o properties
string xml = o.ToString();

मुझे इस ऑब्जेक्ट का XML प्रतिनिधित्व कैसे मिलेगा?



1
मैंने इसे हासिल करने के लिए एक सरल पुस्तकालय विकसित किया: github.com/aishwaryashiva/SaveXML
ऐश्वर्या शिव

जवाबों:


510

आपको XML क्रमांकन के लिए XmlSerializer का उपयोग करना होगा। नीचे एक नमूना स्निपेट है।

 XmlSerializer xsSubmit = new XmlSerializer(typeof(MyObject));
 var subReq = new MyObject();
 var xml = "";

 using(var sww = new StringWriter())
 {
     using(XmlWriter writer = XmlWriter.Create(sww))
     {
         xsSubmit.Serialize(writer, subReq);
         xml = sww.ToString(); // Your XML
     }
 }

10
लाइन के बिना पूरी तरह से अच्छी तरह से काम करने लगता हैXmlWriter writer = XmlWriter.Create(sww);
पॉल हंट

15
क्रमबद्ध वस्तु को स्वरूपित करने के लिए: के XmlTextWriter writer = new XmlTextWriter(sww) { Formatting = Formatting.Indented };बजायXmlWriter writer = XmlWriter.Create(sww);
टोनो नाम

4
चूंकि XmlWriterएनकैप्सुलेट करने के लिए StringWriterआपको दोनों को निपटाने की आवश्यकता नहीं है (पहला उपयोग निरर्थक है), है ना? मैं मान रहा हूँ XmlWriterइसे निपटाने का ख्याल ...
लंबा

4
@talles XmlWriterइनकैप्सुलेट नहीं कर रहा है StringWriter, यह आपके पास-इन का उपयोग कर रहा है StringWriterऔर इसके निपटान की कोई अपेक्षा / जिम्मेदारी नहीं है। इसके अलावा, StringWriterयह XmlWriterदायरे से बाहर है , आप अभी भी चाहते हैं कि जब XmlWriterइसे निपटाया जाए, तो यह XmlWriterआपके लिए बुरा व्यवहार होगा StringWriter। एक सामान्य नियम के रूप में, यदि आप किसी ऐसी चीज की घोषणा करते हैं, जिसे निपटाने की जरूरत है तो आप उसे निपटाने के लिए जिम्मेदार हैं। और उस नियम से तात्पर्य है, कुछ भी आप अपने आप को घोषित नहीं करते हैं जिसे आपको निपटाना नहीं चाहिए। अतः दोनों usingही आवश्यक हैं।
अर्काइनेन55

3
System.Xml.Serialization का उपयोग कर; System.IO का उपयोग कर; System.Xml का उपयोग कर;
टिमोथी

122

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

public static string Serialize<T>(this T value)
{
    if (value == null)
    {
        return string.Empty;
    }
    try
    {
        var xmlserializer = new XmlSerializer(typeof(T));
        var stringWriter = new StringWriter();
        using (var writer = XmlWriter.Create(stringWriter))
        {
            xmlserializer.Serialize(writer, value);
            return stringWriter.ToString();
        }
    }
    catch (Exception ex)
    {
        throw new Exception("An error occurred", ex);
    }
}

इसका उपयोग इस तरह होगा:

var xmlString = obj.Serialize();

8
बहुत अच्छा समाधान, मुझे यह पसंद है कि आपने इसे एक्सटेशन विधि के रूप में लागू किया है
Spyros

57
एक बात मैं यहाँ सुझाता हूँ: कोशिश को हटाओ ... ब्लॉक को पकड़ो। यह आपको कोई लाभ नहीं देता है और केवल उस त्रुटि को रोकता है जिसे फेंका जा रहा है।
जम्मीकेशंस

7
क्या आपको स्ट्रिंगर पर प्रयोग करने की आवश्यकता नहीं है? उदाहरण: (var stringWriter = new StringWriter ())
Steven Quick

3
@jammycakes नहीं! जब आप एक नया फेंकते हैं Exception, तो आपने स्टैकट्रेस को "सीरियल <>" विधि के साथ बढ़ाया है।
user11909

1
@ user2190035 निश्चित रूप से अगर विस्तार विधि के भीतर टूटना होता तो स्टैक ट्रेस वहां शुरू होता? "स्टैक ट्रेस का विस्तार" कोशिश के साथ अनावश्यक लगता है?
LeRoi

43

निम्न फ़ंक्शन को किसी भी ऑब्जेक्ट में System.Xml नाम स्थान का उपयोग करके XML सहेजें फ़ंक्शन जोड़ने के लिए कॉपी किया जा सकता है।

/// <summary>
/// Saves to an xml file
/// </summary>
/// <param name="FileName">File path of the new xml file</param>
public void Save(string FileName)
{
    using (var writer = new System.IO.StreamWriter(FileName))
    {
        var serializer = new XmlSerializer(this.GetType());
        serializer.Serialize(writer, this);
        writer.Flush();
    }
}

सहेजी गई फ़ाइल से ऑब्जेक्ट बनाने के लिए, निम्न फ़ंक्शन को जोड़ें और [ObjectType] को बनाए जाने वाले ऑब्जेक्ट प्रकार के साथ बदलें।

/// <summary>
/// Load an object from an xml file
/// </summary>
/// <param name="FileName">Xml file name</param>
/// <returns>The object created from the xml file</returns>
public static [ObjectType] Load(string FileName)
{
    using (var stream = System.IO.File.OpenRead(FileName))
    {
        var serializer = new XmlSerializer(typeof([ObjectType]));
        return serializer.Deserialize(stream) as [ObjectType];
    }
}

writer.Flush()एक में अनावश्यक है usingब्लॉक - writerकी Dispose()विधि आपके लिए यह फ्लश होगा।
बावजा

6
मेरे अनुभव ने पाया है कि यह सच नहीं है। बड़े डेटा के साथ, बफर के क्लीयर होने से पहले स्टेटमेंट का उपयोग स्ट्रीम को डिस्पोज़ कर देगा। मैं 100% स्पष्ट रूप से फ्लश बुलाने की सलाह देता हूं।
बेन ग्रिप्का

6
लेखक। फ़्लश () निरर्थक नहीं है, यह अवश्य होगा। फ्लश के बिना, ऐसा हो सकता है कि डेटा का कुछ हिस्सा अभी भी स्ट्रीमराइटर बफर में है और फ़ाइल निपट जाती है और कुछ डेटा गायब है।
टॉमस क्यूब्स

मुझे आपका कोड बहुत पसंद है: छोटा और साफ-सुथरा। मेरी समस्या विभिन्न वर्गों के लिए बार-बार कार्यों की नकल करने के साथ है: क्या यह कोड दोहराव नहीं है? अन्य उत्तर टेम्पलेट विस्तार विधियों के साथ सामान्य पुस्तकालय का सुझाव देते हैं, जिसे मैं गले लगाऊंगा। तुम क्या सोचते हो?
माइकल जी

33

एक्सटेंशन क्लास:

using System.IO;
using System.Xml;
using System.Xml.Serialization;

namespace MyProj.Extensions
{
    public static class XmlExtension
    {
        public static string Serialize<T>(this T value)
        {
            if (value == null) return string.Empty;

            var xmlSerializer = new XmlSerializer(typeof(T));

            using (var stringWriter = new StringWriter())
            {
                using (var xmlWriter = XmlWriter.Create(stringWriter,new XmlWriterSettings{Indent = true}))
                {
                    xmlSerializer.Serialize(xmlWriter, value);
                    return stringWriter.ToString();
                }    
            }
        }
    }
}

उपयोग:

Foo foo = new Foo{MyProperty="I have been serialized"};

string xml = foo.Serialize();

बस नाम स्थान फ़ाइल में अपने विस्तार विधि पकड़े संदर्भ आप में इसका उपयोग करना चाहते हैं और यह काम करता हूँ (मेरे उदाहरण में यह होगा: using MyProj.Extensions;)

ध्यान दें कि यदि आप एक्सटेंशन विधि को केवल एक विशेष वर्ग (जैसे। Foo) के लिए विशिष्ट बनाना चाहते हैं, तो आप एक्सटेंशन विधि में Tतर्क को प्रतिस्थापित कर सकते हैं , जैसे।

public static string Serialize(this Foo value){...}


31

आप किसी भी ऑब्जेक्ट से क्रमबद्ध XML प्राप्त करने के लिए नीचे दिए गए फ़ंक्शन का उपयोग कर सकते हैं।

public static bool Serialize<T>(T value, ref string serializeXml)
{
    if (value == null)
    {
        return false;
    }
    try
    {
        XmlSerializer xmlserializer = new XmlSerializer(typeof(T));
        StringWriter stringWriter = new StringWriter();
        XmlWriter writer = XmlWriter.Create(stringWriter);

        xmlserializer.Serialize(writer, value);

        serializeXml = stringWriter.ToString();

        writer.Close();
        return true;
    }
    catch (Exception ex)
    {
        return false;
    }
}

आप इसे क्लाइंट से कॉल कर सकते हैं।


21

किसी वस्तु को क्रमबद्ध करने के लिए:

 using (StreamWriter myWriter = new StreamWriter(path, false))
 {
     XmlSerializer mySerializer = new XmlSerializer(typeof(your_object_type));
     mySerializer.Serialize(myWriter, objectToSerialize);
 }

यह भी याद रखें कि XmlSerializer काम करने के लिए, आपको एक पैरामीटर रहित निर्माता की आवश्यकता है।


2
यह मुझे पागल कर रहा था। मैं यह पता नहीं लगा सका कि यह हमेशा खाली क्यों था। तब मुझे एहसास हुआ कि आपके उत्तर को पढ़ने के बाद मेरे पास कोई पैरामीटर नहीं है। धन्यवाद।
एंडी

19

मैं बेन ग्रिपका के प्रतिलिपि उत्तर से शुरू करूंगा:

public void Save(string FileName)
{
    using (var writer = new System.IO.StreamWriter(FileName))
    {
        var serializer = new XmlSerializer(this.GetType());
        serializer.Serialize(writer, this);
        writer.Flush();
    }
}

मैंने पहले इस कोड का उपयोग किया था। लेकिन वास्तविकता से पता चला कि यह समाधान थोड़ा समस्याग्रस्त है। आमतौर पर अधिकांश प्रोग्रामर सिर्फ सेव पर सेटिंग को सीरियलाइज करते हैं और लोड पर सेटिंग्स को डिसेर्बलाइज करते हैं। यह एक आशावादी परिदृश्य है। एक बार क्रमांकन विफल हो जाने के कारण, किसी कारण से, फ़ाइल आंशिक रूप से लिखी गई है, XML फ़ाइल पूर्ण नहीं है और यह अमान्य है। परिणाम में XML deserialization काम नहीं करता है और आपका एप्लिकेशन प्रारंभ में क्रैश हो सकता है। यदि फ़ाइल बहुत बड़ी नहीं है, तो मेरा सुझाव है कि पहले ऑब्जेक्ट को क्रमबद्ध करें और MemoryStreamफिर फाइल पर स्ट्रीम लिखें। यह मामला विशेष रूप से महत्वपूर्ण है अगर कुछ जटिल कस्टम क्रमांकन है। आप कभी भी सभी मामलों का परीक्षण नहीं कर सकते।

public void Save(string fileName)
{
    //first serialize the object to memory stream,
    //in case of exception, the original file is not corrupted
    using (MemoryStream ms = new MemoryStream())
    {
        var writer = new System.IO.StreamWriter(ms);    
        var serializer = new XmlSerializer(this.GetType());
        serializer.Serialize(writer, this);
        writer.Flush();

        //if the serialization succeed, rewrite the file.
        File.WriteAllBytes(fileName, ms.ToArray());
    }
}

वास्तविक दुनिया के परिदृश्य में deserialization को भ्रष्ट क्रमांकन फ़ाइल के साथ गिना जाना चाहिए, यह कभी-कभी होता है। बेन ग्रिपका द्वारा प्रदान किया गया लोड फ़ंक्शन ठीक है।

public static [ObjectType] Load(string fileName)
{
    using (var stream = System.IO.File.OpenRead(fileName))
    {
        var serializer = new XmlSerializer(typeof([ObjectType]));
        return serializer.Deserialize(stream) as [ObjectType];        
    }    
}

और इसे कुछ रिकवरी परिदृश्य द्वारा लपेटा जा सकता है। यह सेटिंग्स फ़ाइलों या अन्य फ़ाइलों के लिए उपयुक्त है जिन्हें समस्याओं के मामले में हटाया जा सकता है।

public static [ObjectType] LoadWithRecovery(string fileName)
{
    try
    {
        return Load(fileName);
    }
    catch(Excetion)
    {
        File.Delete(fileName); //delete corrupted settings file
        return GetFactorySettings();
    }
}

क्या फ़ाइल को मेमोरीस्ट्रीम लिखते समय प्रक्रिया को बाधित करना संभव नहीं है, उदाहरण के लिए पावर शटडाउन द्वारा?
जॉन स्मिथ

1
हाँ यह संभव है। आप एक अस्थायी फ़ाइल में सेटिंग्स लिखकर इससे बच सकते हैं और फिर मूल को बदल सकते हैं।
टॉमस क्यूब्स

18

ऊपर दिए गए सभी उत्तर सही हैं। यह सिर्फ सबसे सरल संस्करण है:

private string Serialize(Object o)
{
    using (var writer = new StringWriter())
    {
        new XmlSerializer(o.GetType()).Serialize(writer, o);
        return writer.ToString();
    }
}

9

यह ToStringकक्षा की पद्धति को कॉल करने की तुलना में थोड़ा अधिक जटिल है , लेकिन बहुत अधिक नहीं।

यहां एक सरल ड्रॉप-इन फ़ंक्शन है जिसका उपयोग आप किसी भी प्रकार की वस्तु को क्रमबद्ध करने के लिए कर सकते हैं। यह क्रमबद्ध XML सामग्री युक्त स्ट्रिंग देता है:

public string SerializeObject(object obj)
{
    System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument();
    System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(obj.GetType());
    using (System.IO.MemoryStream ms = new System.IO.MemoryStream()) {
        serializer.Serialize(ms, obj);
        ms.Position = 0;
        xmlDoc.Load(ms);
        return xmlDoc.InnerXml;
    }
}


4
    string FilePath = ConfigurationReader.FileLocation;   //Getting path value from web.config            
    XmlSerializer serializer = new XmlSerializer(typeof(Devices)); //typeof(object)
            MemoryStream memStream = new MemoryStream();
            serializer.Serialize(memStream, lstDevices);//lstdevices : I take result as a list.
            FileStream file = new FileStream(folderName + "\\Data.xml", FileMode.Create, FileAccess.ReadWrite); //foldername:Specify the path to store the xml file
            memStream.WriteTo(file);
            file.Close();

आप वांछित स्थान पर xml फ़ाइल के रूप में परिणाम बना और संग्रहीत कर सकते हैं।


4

मेरा काम कोड। रिटर्न utf8 xml खाली नेमस्पेस सक्षम करता है।

// override StringWriter
public class Utf8StringWriter : StringWriter
{
    public override Encoding Encoding => Encoding.UTF8;
}

private string GenerateXmlResponse(Object obj)
{    
    Type t = obj.GetType();

    var xml = "";

    using (StringWriter sww = new Utf8StringWriter())
    {
        using (XmlWriter writer = XmlWriter.Create(sww))
        {
            var ns = new XmlSerializerNamespaces();
            // add empty namespace
            ns.Add("", "");
            XmlSerializer xsSubmit = new XmlSerializer(t);
            xsSubmit.Serialize(writer, obj, ns);
            xml = sww.ToString(); // Your XML
        }
    }
    return xml;
}

उदाहरण रिटर्न प्रतिक्रिया Yandex एपीआई भुगतान Aviso url:

<?xml version="1.0" encoding="utf-8"?><paymentAvisoResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" performedDatetime="2017-09-01T16:22:08.9747654+07:00" code="0" shopId="54321" invoiceId="12345" orderSumAmount="10643" />

4

मेरे पास XML को C # का उपयोग करके किसी ऑब्जेक्ट को क्रमांकित करने का एक सरल तरीका है, यह बहुत अच्छा काम करता है और यह अत्यधिक पुन: प्रयोज्य है। मुझे पता है कि यह एक पुराना धागा है, लेकिन मैं इसे पोस्ट करना चाहता था क्योंकि किसी को यह मददगार लग सकता है।

यहां बताया गया है कि मैं विधि को कैसे कहता हूं:

var objectToSerialize = new MyObject();
var xmlString = objectToSerialize.ToXmlString();

यहाँ वह वर्ग है जो काम करता है:

नोट: चूँकि ये विस्तार विधियाँ हैं, इसलिए इन्हें स्थिर वर्ग में होना चाहिए।

using System.IO;
using System.Xml.Serialization;

public static class XmlTools
{
    public static string ToXmlString<T>(this T input)
    {
        using (var writer = new StringWriter())
        {
            input.ToXml(writer);
            return writer.ToString();
        }
    }

    private static void ToXml<T>(this T objectToSerialize, StringWriter writer)
    {
        new XmlSerializer(typeof(T)).Serialize(writer, objectToSerialize);
    }
}

4

उपरोक्त समाधानों के आधार पर, यहां एक विस्तार वर्ग आता है, जिसका उपयोग आप किसी भी वस्तु को क्रमबद्ध करने और उसका उपयोग करने के लिए कर सकते हैं। कोई अन्य XML अटेंशन आपके ऊपर है।

बस इसे इस तरह उपयोग करें:

        string s = new MyObject().Serialize(); // to serialize into a string
        MyObject b = s.Deserialize<MyObject>();// deserialize from a string



internal static class Extensions
{
    public static T Deserialize<T>(this string value)
    {
        var xmlSerializer = new XmlSerializer(typeof(T));

        return (T)xmlSerializer.Deserialize(new StringReader(value));
    }

    public static string Serialize<T>(this T value)
    {
        if (value == null)
            return string.Empty;

        var xmlSerializer = new XmlSerializer(typeof(T));

        using (var stringWriter = new StringWriter())
        {
            using (var xmlWriter = XmlWriter.Create(stringWriter, new XmlWriterSettings { Indent = true }))
            {
                xmlSerializer.Serialize(xmlWriter, value);
                return stringWriter.ToString();
            }
        }
    }
}

2

या आप इस विधि को अपनी वस्तु में जोड़ सकते हैं:

    public void Save(string filename)
    {
        var ser = new XmlSerializer(this.GetType());
        using (var stream = new FileStream(filename, FileMode.Create))
            ser.Serialize(stream, this);
    }

1

यहाँ एक मूल कोड है जो C # ऑब्जेक्ट को xml में क्रमांकित करने में मदद करेगा:

using System;

public class clsPerson
{
  public  string FirstName;
  public  string MI;
  public  string LastName;
}

class class1
{ 
   static void Main(string[] args)
   {
      clsPerson p=new clsPerson();
      p.FirstName = "Jeff";
      p.MI = "A";
      p.LastName = "Price";
      System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(p.GetType());
      x.Serialize(Console.Out, p);
      Console.WriteLine();
      Console.ReadLine();
   }
}    

6
यह अच्छा होगा यदि आप इस कोड के स्रोत का समर्थन करते हैं
MaLiN2223

0
public string ObjectToXML(object input)
{
    try
    {
        var stringwriter = new System.IO.StringWriter();
        var serializer = new XmlSerializer(input.GetType());
        serializer.Serialize(stringwriter, input);
        return stringwriter.ToString();
    }
    catch (Exception ex)
    {
        if (ex.InnerException != null)
            ex = ex.InnerException;

        return "Could not convert: " + ex.Message;
    }
}

//Usage
var res = ObjectToXML(obj)

आपको निम्न वर्गों का उपयोग करने की आवश्यकता है:

using System.IO;
using System.Xml;
using System.Xml.Serialization;
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.