Home Full Site
XmlSerializer: Serialize(.NET 객체를 XML로)

메모리 상의 .NET 객체를 XML로 만들어 저장하는 것을 XML Serialization이라 부르고, 반대로 XML을 .NET 객체로 복원하는 것을 XML Deserialization이라 부른다. Serialization에서의 XML은 파일로 저장될 수도 있고, 네트워크 스트림으로 만들어져 외부로 보내질 수도 있으며, 혹은 데이타베이스에 저장될 수도 있다.

.NET Framework에서 XML Serialization 기능을 사용하기 위해서는 System.Xml.Serialization 네임스페이스에 있는 XmlSerializer 클래스를 사용하면 된다. 즉, XmlSerializer 클래스의 Serialize() 메서드를 사용하면 .NET 객체를 XML로 변환할 수 있으며, Deserialize() 메서드를 사용하면 반대로 XML을 .NET 객체로 변환할 수 있다.

.NET에서 기본적으로 한 클래스의 모든 public 필드와 속성들은 XML로 Serialization 할 수 있다. 클래스는 public으로 선언되어야 하며, public 필드/속성 이외의 private 필드/속성들은 Serialization 되지 않는다 (주: 만약 private 필드들을 Serialization 해야 한다면, IXmlSerializable 인터페이스를 구현해서 사용하거나 (아래 아티클), 꼭 XML 포맷일 필요가 없으면 BinaryFormatter 클래스를 사용하여 Binary Serialization을 사용할 수 있다.).

아래 예제에서 보이듯이, XmlSerializer 클래스 객체는 Serialization할 타입을 지정하면서 생성한다. 보통 typeof(클래스명) 혹은 객체.GetType()을 통해 해당 타입을 얻게 된다. XmlSerializer 객체가 생성된 후에는 Serialize() 메서드를 호출하면 되는데, 이 메서드의 첫번째 파라미터는 XML을 출력할 위치를 표시하는 것으로 파일스트림, 네트워크스트림 같은 스트림 객체를 넣어 준다. 두번째 파라미터는 XML Serialization을 수행할 .NET 객체를 넣어주면 된다.


예제

using System;
using System.IO;
using System.Xml.Serialization; // XmlSerializer

namespace XmlSerialApp
{    
    public class Employee   // public 이어야 함
    {
        public int Seq;
        public int Id { get; set; }
        public string Name { get; set; }
        public string Dept { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Employee emp = new Employee
            {
                Seq = 1,
                Id = 1001,
                Name = "Tim",
                Dept = "Sales"
            };

            //파일에 출력하는 예
            using (StreamWriter wr = new StreamWriter(@"C:\Temp\Emp.xml"))
            {
                XmlSerializer xs = new XmlSerializer(typeof(Employee));
                xs.Serialize(wr, emp);  
            }

            //콘솔에 출력하는 예
            {
                XmlSerializer xs = new XmlSerializer(typeof(Employee));
                //객체로부터 타입을 얻는 다른 방법
                //XmlSerializer xs = new XmlSerializer(emp.GetType());

                xs.Serialize(Console.Out, emp);
            }
        }
    }
}

/* 출력파일 Emp.xml

<?xml version="1.0" encoding="utf-8"?>
<Employee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Seq>1</Seq>
  <Id>1001</Id>
  <Name>Tim</Name>
  <Dept>Sales</Dept>
</Employee>

*/



XmlSerializer: Deserialize(XML을 .NET 객체로)

XML Serialization을 통해 .NET 객체가 XML로 변형된 후, 이를 다시 XML로부터 .NET 객체로 변형하는 것을 XML Deserialization이라 부른다. Deserialization을 위해서는 Serialization 때와 마찬가지로 먼저 Serialization 타입을 지정하면서 XmlSerializer 객체를 생성한다. 그리고 XmlSerializer 객체의 Deserialize(스트림) 메서드를 호출하면 .NET 객체를 object 타입으로 리턴한다. Deserialize() 메서드가 object 타입으로 리턴하므로 필요한 .NET 타입으로 캐스팅하여 사용한다. 아래 예제는 위에서 생성한 Employee 객체에 대한 XML을 다시 Deserialization하는 코드이다.

예제

using System;
using System.IO;
using System.Xml.Serialization; // XmlSerializer

namespace XmlSerialApp
{    
    public class Employee
    {
        public int Seq;
        public int Id { get; set; }
        public string Name { get; set; }
        public string Dept { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {            
            using (var reader = new StreamReader(@"C:\Temp\Emp.xml"))
            {
                XmlSerializer xs = new XmlSerializer(typeof(Employee));
                Employee emp = (Employee) xs.Deserialize(reader);
                
                Console.WriteLine("{0}, {1}", emp.Id, emp.Name);
            }            
        }
    }
}



IXmlSerializable 인터페이스 구현

표준 포맷의 XML Serialization을 사용하지 않고 개발자가 임의로 정의한 포맷으로 XML Serialization을 수행하기 위해서는 Serialization할 .NET 클래스에서 IXmlSerializable 인터페이스를 구현한다. IXmlSerializable 인터페이스를 구현하면, private 필드/속성을 XML Serialization에 추가할 수도 있고, 또한 public 필드/속성을 필요하다면 XML Serialization에서 제외할 수도 있다. 또한, Serialization 포맷이 디폴트로는 속성들이 Element로 추가되는데, 어떤 속성은 Attribute로, 또 다른 속성은 Element로 추가하는 등 커스텀 포맷을 만들어 Serialization 할 수 있게 된다.

IXmlSerializable 인터페이스는 GetSchema(), WriteXml(), ReadXml() 라는 3개의 메서드를 갖고 있다. 여기서 GetSchema()는 Reserved 메서드로서 항상 null 을 리턴하면 되며, 실제로는 WriteXml과 ReadXml 메서드만 구현하면 된다.

WriteXml() 메서드는 .NET Framework에서 이미 기초 작업을 모두 하고 XmlWriter 객체를 넘겨주는데, 개발자는 해당 객체의 필드/속성들을 Attribute 혹은 Element 등으로 쓰는 작업만을 하면 된다. 또한 ReadXml() 메서드 역시 Framework에서 이미 기초 작업을 모두 하고 XmlReader 객체를 넘겨주는데, 이 Reader 객체를 가지고 Attribute 혹은 Element 등을 읽는 작업을 하게 된다.

아래 예제는 Employee 클래스에서 IXmlSerializable 인터페이스를 구현한 예로서, WriteXml() 메서드에선 public 필드인 Seq 를 Serialization에서 의도적으로 제외하였으며, 또한 code 라는 private 필드를 Serialization에 추가하였다. 그리고, Id 속성과 code 필드는 Attribute로 추가하였고, Name과 Dept속성을 Element로 추가하였다.

이러한 포맷에 맞춰 ReadXml() 메서드에서는 Id 속성과 code 필드를 Attribute에서 읽어 들였고, Name과 Dept속성을 Element에서 각각 읽어 들였다.


예제

using System;
using System.IO;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization; // XmlSerializer

namespace XmlSerialApp
{    
    public class Employee : IXmlSerializable
    {
        private int code = 10;

        public int Seq;
        public int Id { get; set; }
        public string Name { get; set; }
        public string Dept { get; set; }

        public XmlSchema GetSchema()
        {
            return null; // 항상 null 리턴 (Reserved)
        }

        public void WriteXml(XmlWriter writer)
        {
            // 1. Seq를 의도적으로 쓰지 않음. Seq는 출력 안됨
            // 2. code는 private 필드지만 출력함.
            writer.WriteAttributeString("Id", this.Id.ToString());
            writer.WriteAttributeString("Code", this.code.ToString());
            writer.WriteElementString("Name", this.Name);
            writer.WriteElementString("Dept", this.Dept);
        }

        public void ReadXml(XmlReader reader)
        {
            reader.MoveToContent();
            this.Id = int.Parse(reader.GetAttribute("Id"));
            this.code = int.Parse(reader.GetAttribute("Code"));
            reader.Read();
            this.Name = reader.ReadElementContentAsString("Name", "");
            this.Dept = reader.ReadElementContentAsString("Dept", "");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Employee emp = new Employee
            {
                Seq = 1,
                Id = 1001,
                Name = "Tim",
                Dept = "Sales"
            };

            // Serialization
            using (StreamWriter wr = new StreamWriter(@"C:\Temp\Emp.xml"))
            {
                XmlSerializer xs = new XmlSerializer(typeof(Employee));
                xs.Serialize(wr, emp);
            }

            // Deserialization
            using (var reader = new StreamReader(@"C:\Temp\Emp.xml"))
            {
                XmlSerializer xs = new XmlSerializer(typeof(Employee));
                Employee e = (Employee)xs.Deserialize(reader);

                Console.WriteLine("{0}, {1}, {2}", e.Id, e.Name, e.Dept);
            }
        }
    }
}

/* 출력파일 Emp.xml

<?xml version="1.0" encoding="utf-8"?>
<Employee Id="1001" Code="10">
  <Name>Tim</Name>
  <Dept>Sales</Dept>
</Employee>

*/



© csharpstudy.com