オブジェクトをXMLにシリアル化する


292

継承したC#クラスがあります。オブジェクトの「ビルド」に成功しました。しかし、オブジェクトをXMLにシリアル化する必要があります。それを行う簡単な方法はありますか?

クラスはシリアル化用に設定されているようですが、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
Aishwarya Shiva

回答:


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);
Tono Nam

4
XmlWriterカプセル化するので、StringWriter両方を廃棄する必要はありません(最初の使用は冗長です)。私はXmlWriterそれを処分することを前提としています...
talles '11 / 10/15

4
@talles XmlWriterはをカプセル化していませんStringWriter。渡されたものを利用しており、破棄StringWriterすることに対する期待/責任はありません。さらにStringWriterXmlWriterの範囲外であり、XmlWriter破棄されたときにそれを必要とする場合がありXmlWriterますStringWriter。原則として、処分が必要なものを宣言した場合は、処分する責任があります。そして、そのルールに暗黙のうちに、あなたが自分で宣言していないものは処分してはいけません。したがって、両方usingが必要です。
Arkaine55

3
System.Xml.Serializationを使用します。System.IOを使用します。System.Xmlを使用します。
timothy 2017

122

以下のようにref変数を使用するのではなく、文字列を返すように変更しました。

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 2013

57
ここで私が提案することの1つは、try ... catchブロックを削除することです。それはあなたに何の利益も与えません、そして投げられているエラーを単に難読化します。
jammycakes 2014年

7
ストリングライターでも使用する必要はありませんか?例:using(var stringWriter = new StringWriter())
Steven Quick

3
@jammycakesいいえ!Exceptionそこで新しいものを投げるとき、あなたはメソッド「Serialize <>」でStackTraceを拡張しました。
user11909 2017年

1
@ user2190035確かに拡張メソッド内で中断した場合、スタックトレースはそこで開始されますか?「スタックトレースの拡張」を試してみる必要はないのでしょうか。
LeRoi 2017年

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ブロック内では冗長です- writerDispose()メソッドはそれをフラッシュします。
bavaza

6
私の経験では、それは真実ではありません。データが大きい場合、usingステートメントは、バッファがクリアされる前にストリームを破棄します。私は100%明示的にフラッシュを呼び出すことをお勧めします。
ベングリプカ2015年

6
writer.Flush()は冗長ではなく、存在する必要があります。Flushを使用しないと、データの一部がStreamWriterバッファーに残っており、ファイルが破棄されて一部のデータが失われる可能性があります。
Tomas Kubes 2015年

私はあなたのコードがとても好きです。短くてすっきりしています。私の問題は、関数をさまざまなクラスに何度もコピーすることです。コードの重複ではありませんか?他の答えは、私が採用するテンプレート拡張メソッドを備えた汎用ライブラリを示唆しています。どう思いますか?
マイケルG

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

まず、Ben Gripkaのコピーの回答から始めます。

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逆シリアル化が機能せず、アプリケーションが起動時にクラッシュする可能性があります。ファイルが大きくない場合は、まずオブジェクトをシリアル化してから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());
    }
}

現実のシナリオでの逆シリアル化は、シリアル化ファイルが破損している場合にカウントされるはずです。Ben Gripkaが提供するロード機能は問題ありません。

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();
    }
}

たとえば電源のシャットダウンなどによって、MemoryStreamをファイルに書き込んでいる間にプロセスが中断されることはありませんか?
John Smith

1
はい、可能です。設定を一時ファイルに書き込んでから元のファイルを置き換えることで、これを回避できます。
Tomas Kubes

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 api支払い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

私はC#を使用してオブジェクトをXMLにシリアル化する簡単な方法があります。それは非常にうまく機能し、再利用性が高いです。私はこれが古いスレッドであることを知っていますが、誰かが役立つと思うかもしれないので、投稿したかったのです。

これが私がメソッドを呼び出す方法です:

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
あなたは、このコードのソースを引用場合はいいだろう:support.microsoft.com/en-us/help/815813/...
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;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.