Programming/.NET

 1. XmlWriter

 

XmlReader는 XML을 읽지만 XmlWriter는 XML을 직접 생성하는 클래스입니다.

 

XmlWriterSettings xws = new XmlWriterSettings();
xws.Indent = true;
 
Response.ContentType = "text/xml";

using (XmlWriter writer = XmlWriter.Create(Response.OutputStream, xws)) {
    writer.WriteStartDocument();

    writer.WriteStartElement("catalog");
    
    writer.WriteStartElement("book");
    writer.WriteStartAttribute("id");
    writer.WriteValue("bk101");
    writer.WriteEndAttribute();
    writer.WriteElementString("author""Gambardella, Matthew");
    writer.WriteElementString("title""XML Developer's Guide");
    writer.WriteElementString("genre""Computer");
    writer.WriteElementString("price""44.95");
    writer.WriteElementString("publish_date""2000-10-01");
    writer.WriteElementString("description""An in-depth look at creating applications\nwith XML.");
    writer.WriteEndElement();

    writer.WriteEndElement();

    writer.WriteEndDocument();
}

▶ 1-1

 

위 예제는 이전에 샘플로 사용한 XML을 생성하도록 합니다.(bk102와 bk103부분은 생략...)

 

XmlWriterSettings는 XML작성시 작성조건에 대한 설정클래스입니다. 예제에서는 Indent로 들여쓰기를 설정하였습니다.(브라우저에서 XML을 보면 기본적으로 웹 브라우저자체가 보기좋게 정렬시켜 보여주지만 소스보기를 통해 실제 XML구조를 보면 차이가 드러납니다.)

 

또한 출력결과로 XML을 보여줄 것이기 때문에 문서형식을 "text/xml"로 지정하고 aspx단의 모든 태그를 다음과 같이 제거합니다.

 

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="web_form_test._Default" %>

<%--<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        
    </div>
    </form>
</body>
</html>--
%>

 

XML을 생성하는데 사용된 XmlWriter 클래스의 Create메소드에는 인자로 Response.OutputStream을 지정해 브라우저로 XML이 바로 표시되도록 합니다.

 

XML문서의 시작은 WriteStartDocument 메소로 처리하고 새로운 엘리먼트는 WriteStartElement 메소드로 작성됩니다. 속성은 WriteStartAttribute로, 속성의 값은 WriteValue메소를 사용합니다. 이 메소드는 XML문서상에서 종료시점에 각 메소드에 맞는 종료메소드(예:WriteEndAttribute)를 넣어줘야 합니다.

 

각 요소의 엘리먼트와 문자열내용은 WriteElementString 메소드가 사용되는데 이 메소드는 따로 종료메소드가 필요하지 않습니다.

 

 2. 직렬화로 XML작성하기

 

XmlReader과 마찬가지로 XmlWriter에도 클래스의 객체를 통한 직렬화를 구현할 수 있습니다.

 

public class book
{
    [XmlAttribute("id")]
    public string id;

    [XmlElement(ElementName = "author")]
    public string author;
    [XmlElement(ElementName = "title")]
    public string title;
    [XmlElement(ElementName = "genre")]
    public string genre;
    [XmlElement(ElementName = "price")]
    public string price;
    [XmlElement(ElementName = "publish_date")]
    public string publish_date;
    [XmlElement(ElementName = "description")]
    public string description;
}

 

이 클래스는 1-1예제에서 작성되었던 book 요소의 클래스입니다. book 요소에 id값을 주기위해 XmlAttribute 특성이 사용되었으며 그 밖에 각 요소들은 XmlElement 특성을 사용하였습니다.

 

using (XmlWriter writer = XmlWriter.Create(Response.OutputStream, xws)) {
    writer.WriteStartDocument();
    writer.WriteStartElement("catalog");
    
    book b = new book();
    b.id = "bk101";
    b.author = "Gambardella, Matthew";
    b.title = "XML Developer's Guide";
    b.genre = "Computer";
    b.price = "44.95";
    b.publish_date = "2000-10-01";
    b.description = "An in-depth look at creating applications\nwith XML.";

    XmlSerializer xs = new XmlSerializer(typeof(book));

    XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
    ns.Add(string.Empty, string.Empty);

    xs.Serialize(writer, b, ns);

    writer.WriteEndElement();
    writer.WriteEndDocument();
}

▶ 2-1

 

book 클래스의 객체를 생성하고 각 속성에 필요한 값을 부여합니다. 그리고 XmlSerializer로 해당 객체를 전달해 클래스에 맞는 XML요소가 작성되도록 합니다.

 

이러한 방식은 지금 직렬화를 통해 쓰여지고 있는 XML요소가 catalog요소의 하위요소인지의 여부를 판단하지 않으므로 XmlSerializerNamespaces 클래스로 빈속성을 추가해 쓸데없는 xmlns속성이 삽입되지 않도록 처리합니다.

 

 3. Linq to XML로 XML작성하기

 

XmlWriterSettings xws = new XmlWriterSettings();
xws.Indent = true;

Response.ContentType = "text/xml";

XDocument books = new XDocument(
    new XElement("catalog",
        new XElement("book",
            new XAttribute("id""bk101"),
            new XElement("author""Gambardella, Matthew"),
            new XElement("title""XML Developer's Guide"),
            new XElement("genre""Computer"),
            new XElement("price""44.95"),
            new XElement("publish_date""2000-10-01"),
            new XElement("description""An in-depth look at creating applications\nwith XML.")
        )
    )
);

Response.Write(books);

 

1-1과 같은 예제와는 다르게 상당히 간결한데 다른건 필요없고 그저 XDocument를 통해 요소(XElement)와 속성(XAttribute)을 추가해 주기만 하면 됩니다.

 

참고로 Linq to XML사용시에도 직렬화를 통한 XML작성이 가능합니다. 하지만 2-1의 예제에서 처럼 Linq to XML내부에 직접적으로 Serialize를 구현할 수는 없습니다. Linq to XML은 XElement 요소가 반환되어야 하는데 Serialize메소드는 자체동작으로 처리할뿐 반환해주는 요소가 없기 때문입니다.

 

따라서 Serialize메소드를 통해 XML이 작성되면 이 XML을 다시 XElement요소로 반환해주는 방법이 필요합니다. 그래서 다음과 같이 별도의 메소드를 작성하고

 

private XElement xe(XmlSerializer xs, book b)
{
    XDocument x = new XDocument();

    using (XmlWriter xw = x.CreateWriter())
    {
        XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
        ns.Add(string.Empty, string.Empty);

        xs.Serialize(xw, b, ns);
    }

    return x.Root;
}

 

Linq to XML에서 해당 요소가 삽입되어야 하는 부분에 위에서 구현한 메소드를 호출하면 됩니다.

 

XDocument books = new XDocument(
    new XElement("catalog",
        xe(xs, b)
    )
);

 

아니면 확장메소드를 통해 XmlSerializer 클래스에 필요한 별도의 메소드를 추가할 수도 있습니다.

 

static class XmlSerializerExtension
{
    public static XElement SerializeToXElement(this XmlSerializer xs, book b)
    {
        XDocument x = new XDocument();

        using (XmlWriter xw = x.CreateWriter())
        {
            XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
            ns.Add(string.Empty, string.Empty);

            xs.Serialize(xw, b, ns);
        }

        return x.Root;
    }
}

 

XDocument books = new XDocument(
    new XElement("catalog",
        xs.SerializeToXElement(b) //확장메소드 호출
    )
);

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

[ASP.NET] XML - 6  (0) 2016.02.23
[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
0 0