'XmlSerializer'에 해당되는 글 2건

Programming/.NET

C#에서는 문자열이나 정수와 같은 타입의 데이터를 byte배열로 변환하는 직렬화를 수행할 수 있으며 물론 그 반대로 가능합니다. 그렇다면 기본 데이터타입이 아닌 직접 만든 클래스와 같은 요소는 어떻게 직렬화를 수행할 수 있을까?

 

System.Runtime.Serialization.Formatters.Binary.BinaryFormatter가 그 답이 될 수 있습니다.

 

예를 들어 아래와 같은 클래스가 있습니다.

 

class Employee
{
    public Employee(string name, string department, int level)
    {
        Name = name;
        Department = department;
        Level = level;
    }

    public string Name
    {
        get;
        set;
    }

    public string Department
    {
        get;
        set;
    }

    public int Level
    {
        get;
        set;
    }
}

 

이 클래스를 직렬화하기 위해서는 우선 [Serializable] 이라는 특성을 클래스에 추가해 해당 클래스가 직렬화가능함을 알려줘야 합니다.

 

[Serializable]
class Employee

 

그리고 직렬화를 수행하려는 클래스에 대해 필요한 적절한 작업을 수행한 뒤

 

Employee e1 = new test.Employee("홍길동", "관리부", 4);

 

BinaryFormatter를 통해 MemoryStream으로 다음과 같이 직렬화를 수행합니다.

 

System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();

MemoryStream ms = new MemoryStream();
bf.Serialize(ms, e1);

 

대부분 네트워크를 통해 다른 시스템으로 개체전체를 전송하고자 할때 직렬화를 많이 수행하는데 문제는 직렬화방식이 내부에 감춰져 있어서 .NET이 아닌 다른 플렛폼에서는 역직렬화가 힘들다는 단점이 있습니다.

 

Employee e1 = new test.Employee("홍길동", "관리부", 4);

System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();

MemoryStream ms = new MemoryStream();
bf.Serialize(ms, e1);

ms.Position = 0;

Employee e2 = (Employee)bf.Deserialize(ms);

Console.WriteLine(e2.Name);

 

역직렬화는 간단합니다. BinaryFormatter의 Deserialize메서드를 호출해 Stream으로 읽기만 하면 됩니다. 물론 이 방법은 타 플렛폼과는 맞추기 힘든 부분이 있지만 같은 .NET환경이라면 비교적 빠르고 간단히 처리할 수 있습니다.

 

BinaryFormatter는 주어진 요소를 Binary로 직렬화하지만 System.Xml.Serialization.XmlSerializer는 문자열형태(기본 UTF8로 인코딩)로 직렬화를 수행합니다. 그런데 이름에서도 알 수 있듯이 그 문자열 포멧 형식이 XML입니다. 다만 XmlSerializer를 사용하려면 클래스를 다음과 같이 바꿔야 합니다.

 

public class Employee
{
    public Employee()
    { }
    public Employee(string name, string department, int level)
    {
        Name = name;
        Department = department;
        Level = level;
    }

    public string Name
    {
        get;
        set;
    }

    public string Department
    {
        get;
        set;
    }

    public int Level
    {
        get;
        set;
    }
}

 

먼저 클래스에 public 접근제한자가 있어야 하며 클래스안에 기본생성자를 포함해야 합니다. 하지만 이전에 추가했던 [Serializable]특성은 필요하지 않습니다.

 

Employee e1 = new test.Employee("홍길동", "관리부", 4);

System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(typeof(Employee));

MemoryStream ms = new MemoryStream();
xs.Serialize(ms, e1);

ms.Position = 0;

Employee e2 = (Employee)xs.Deserialize(ms);

Console.WriteLine(e2.Name);

 

BinaryFormatter와 클래스명만 다를뿐 사용법의 거의 똑같습니다. 차이라면 클래스를 통해 개체를 생성하는 부분에서는 XML스키마 작성을 위해 직렬화하려는 요소의 타입을 명시해야 한다는 것입니다.

 

XmlSerializer는 BinaryFormatter보다는 성능이 떨어지지만 XML이라는 표준포멧으로 직렬화를 수행하기에 타 플렛폼과의 호환성을 확보할 수 있다는 장점이 있습니다. 단, 직렬화되는 요소는 public제한자가 있는 필드만 가능합니다.

 

.NET 아닌 타 플렛폼입장에서 BinaryFormatter은 Binary변환으로 빠르게 처리될 수 있기는 하나 호환성에 문제가 생길 수 있고 XmlSerializer는 다소 긴 XML데이터를 생성하기는 하지만 XML포멧으로 인해 호환성문제는 해결될 수 있습니다. 각각 장단점이 존재하는데 이 둘의 장점만을 결합한 것이 바로 System.Runtime.Serialization.Json.DataContractJsonSerializer입니다. DataContractJsonSerializer는 문자열로 직렬화를 수행하기는 하지만 json포멧이기에 XML보다 훨씬 적은 데이터용량을 가질 수 있고 포멧또한 타 플렛폼에서 많이 다루는 것이므로 호환성도 확보할 수 있습니다.

 

Employee e1 = new test.Employee("홍길동", "관리부", 4);

System.Runtime.Serialization.Json.DataContractJsonSerializer dc = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(Employee));

MemoryStream ms = new MemoryStream();
dc.WriteObject(ms, e1);

ms.Position = 0;

Employee e2 = (Employee)dc.ReadObject(ms);

Console.WriteLine(e2.Name);

 

DataContractJsonSerializer에서 직렬화는 WriteObject()로 역직렬화는 ReadObject()메서드로 처리합니다.

'Programming > .NET' 카테고리의 다른 글

[ASP.NET MVC] 헬퍼메서드(Helper Method)  (0) 2018.07.18
[C#] extern  (0) 2018.07.03
[C#] BinaryFormatter / XmlSerializer / DataContractJsonSerializer  (0) 2018.06.26
[C#] Encoding / BitConverter  (0) 2018.06.19
[C#] fixed  (0) 2018.06.13
[C#] DateTime  (0) 2018.05.29
0 0
Programming/.NET

 1. XML 직렬화 (XmlSerializer)

 

XmlSerializer는 XML 데이터에서 원하는 값에 대해 특정 클래스(Class)로 CLR개체를 생성하는 직렬화를 수행할 수 있습니다.

 

우선 아래와 같이 간단한 클래스 하나를 추가합니다.

 

[XmlRoot(ElementName = "book")]
public class book_titleAndgenre
{
    [XmlElement(ElementName = "title")]
    public string title;
    [XmlElement(ElementName = "genre")]
    public string genre;
}

 

이 클래스는 title과 genre속성에 ElementName 특성을 추가해 XML의 어떤 요소값이 대상이 되는지를 알려주고 있습니다. 이렇게 해두면 샘플 XML에서 book요소를 기준으로 title과 genre값을 가져와 클래스로 직렬화 할 것입니다.

 

NameTable nt = new NameTable();
object book = nt.Add("book");

xrs.NameTable = nt;

XmlSerializerFactory xsf = new XmlSerializerFactory();

using (XmlReader reader = XmlReader.Create(xml_file, xrs)) {
    while (reader.Read()) {
        if (reader.NodeType == XmlNodeType.Element && book.Equals(reader.LocalName)) {
            XmlSerializer xs = xsf.CreateSerializer(typeof(book_titleAndgenre));
            book_titleAndgenre bt = (book_titleAndgenre)xs.Deserialize(reader.ReadSubtree());
            Response.Write(bt.title + ":::" + bt.genre + "<br />");
        }
    }
}

 

NameTable에 book요소를 추가하여 XML데이터를 검색합니다. XML데이터 순회도중 book에 해당하는 요소를 만나면 우선 위에서 생성한 클래스형태의 직렬화개체를 생성하고 ReadSubtree 메소드를 통하여 하위 모든 요소를 가져와 역직렬화를 통해 해당 클래스에 속성을 추가하게 됩니다.

 

ReadSubtree 메소드는 Read 메소드와 비슷하게 현시점에서 하위 모든 XML을 순회하도록 하지만 Read는 bool 타입을 반환하는 반면 ReadSubtree는 새로운 XmlReader개체를 생성합니다.

 

XmlSerializerFactory 클래스의 CreateSerializer 메소드는 Type개체를 인자값으로 받는데 이 인자로 전달한 개체는 어셈블리형태로 생성될 수 있는 개체여야 하기 때문에 직렬화의 대상이 클래스가 되는 것입니다.(참고로 클래스로 직렬화되는 대상은 public 속성만을 대상으로 합니다.)

 

 2. Linq를 사용한 CLR 개체생성

 

CLR개체를 생성하는 거라면 Linq를 사용해 위에서 보다 더 간단히 구현할 수 있습니다.

 

string xml_file = Server.MapPath("books.xml");

XDocument xd = XDocument.Load(xml_file);

var titleAndgenre = from book in xd.Descendants("book")
                    select new book_titleAndgenre
                    {
                        title = book.Element("title").Value,
                        genre = book.Element("genre").Value
                    };

foreach (book_titleAndgenre bt in titleAndgenre)
    Response.Write(bt.title + ":::" + bt.genre + "<br />");

 

Linq를 사용하는 방법은 실제 읽어들인 XML에서 select 구문으로 원하는 부분의 데이터를 읽어오도록 처리합니다. 위에서 보여진 예제와는 사뭇 다른데 특정 데이터값만을 대상으로 하는 Linq쿼리를 직접 다루게 되므로 직렬화나 역질화에 필요한 클래스를 사용하지 않습니다.

 

그렇다 보니 기존 클래스와의 타입 대조절차가 빠지게 되므로 개체생성 대상이 되는 클래스조차 별다른 특성없이 간단하게 작성될 수 있습니다.

 

public class book_titleAndgenre
{
    public string title;
    public string genre;
}

 

'Programming > .NET' 카테고리의 다른 글

[ASP.NET] XML - 5  (0) 2016.02.18
[ASP.NET] XML - 4  (0) 2016.02.11
[ASP.NET] XML - 3  (0) 2016.02.01
[ASP.NET] XML - 2  (0) 2016.01.26
[ASP.NET] XML - 1  (0) 2016.01.18
[ASP.NET] Command Object  (0) 2016.01.13
0 0
1
블로그 이미지

클리엘