티스토리 뷰

개발/C#

[C#/ XML] XML parser 구현

KIBBOMI 2021. 1. 1. 02:17

XML은 데이터 전송에 있어서 중요한 역할을 한다. 어떤 특성을 갖고 있는지, 이런 것에 관해서는 다른 글이나 문서에 아주 정확하게 나와있기 때문에 생략하고, 예전부터 XML, JSON의 형태로 데이터를 많이 주고받는데 과연 어떻게 parsing 할 수 있을지.. 정리가 필요한 것 같아 정리해보았다.

아주 컴팩트하게 데이터를 받을 때, 어떻게 파싱 해서 사용할 것인지에 대해 정리해보았다.


1. C#에서의 XML 파싱

우선 XML에 대한 기본지식은 다 있다고 가정하고 말씀드리겠습니다.

 

1.1) Node가 1개인 예제

다음 xml의 예시가 있다고 하자.(출처는 w3schools.com입니다. note.xml이라는 이름을 가짐.)

<?xml version="1.0" encoding="UTF-8"?>
<note>
  <to>Tove</to>
  <from>Jani</from>
  <heading>Reminder</heading>
  <body>Don't forget me this weekend!</body>
</note>

 

root element로 note라고 되어있는 것을 알 수 있다.

root인 note안에 to, from, heading, body라는 노드를 가진다.

이 xml파일이 같은 project에 있다고 가정하고 값을 parsing 하는 코드를 확인해 보자.

using System;
using System.Collections.Generic;
using System.Collections;
using System.Xml;

namespace ConsoleApp1
{
    class cstest
    {
        static void Main(string[] args)
        {
            XmlDocument XmlFile = new XmlDocument();
            XmlFile.Load("Note.xml");
            //xml형태의 string변수가 있다면 .LoadXML(string)

            XmlNodeList XmlList = XmlFile.GetElementsByTagName("note");
            //XmlList는 <note>...</note>를 하나의 Node로 하는 List를 반환.

            //이 note Node가 여러개일 수 있으니, foreach
            foreach(XmlNode item in XmlList)
            {
                Console.WriteLine($"to : {item["to"].InnerText}");
                Console.WriteLine($"from : {item["from"].InnerText}");
                Console.WriteLine($"heading : {item["heading"].InnerText}");
                Console.WriteLine($"body : {item["body"].InnerText}");
            }

            return;
        }
    }
}

 

 

C#에는 XML기능을 기본으로 제공하고 있다.

using System.Xml을 입력하자.

 

그리고 가장먼저 이 XML 파일을 갖고 있을 XmlDocument 객체가 하나 필요하다.

위의 note.xml을 갖고있기 위해서 XmlDocument객체를 하나 할당하고, Load 메서드를 통해서 값을 불러들인다.

 

위의 예는 PC에 저장되어있는 경우이기 때문에 Load(PATH) 함수를 사용해서 읽어 들였지만, 흔히 api 등을 통해서 값을 전달받을 경우에는 보통 string 변수에 xml내용을 담게 되는데, 그때는 LoadXML 메서드를 이용해서 XmlDocument객체에 넣자.

 

그리고

XmlNodeList XmlList = XmlFile.GetElementsByTagName("note"); 의 의미는

1개가 Node, 여러개의 Node는 NodeList

tag이름이 note인 애들의 List를 반환해주는 의미이다.

지금은 1개밖에 없어서 NodeList에 1개의 Node만 들어있는 구조를 나타낸다.

그래서 출력은 foreach문으로 하고 있지만 1번 반복하면 반복문이 종료될 것이다.

 

실행 결과

위처럼 note tag의 내용을 잘 출력하는 것을 볼 수 있다.

 

1.2) Node가 여러개인 예제

1.1에서는 간단한 예제를 살펴보았다.

이번에는 1개의 root에 여러 개의 node가 있는 예를 보겠다.

(출처.... 밑의 예도 w3schools.com의 예제입니다. / BreakfaseMenu.xml)

<?xml version="1.0" encoding="UTF-8"?>
<breakfast_menu>
  <food>
    <name>Belgian Waffles</name>
    <price>$5.95</price>
    <description>Two of our famous Belgian Waffles with plenty of real maple syrup</description>
    <calories>650</calories>
  </food>
  <food>
    <name>Strawberry Belgian Waffles</name>
    <price>$7.95</price>
    <description>Light Belgian waffles covered with strawberries and whipped cream</description>
    <calories>900</calories>
  </food>
  <food>
    <name>Berry-Berry Belgian Waffles</name>
    <price>$8.95</price>
    <description>Light Belgian waffles covered with an assortment of fresh berries and whipped cream</description>
    <calories>900</calories>
  </food>
  <food>
    <name>French Toast</name>
    <price>$4.50</price>
    <description>Thick slices made from our homemade sourdough bread</description>
    <calories>600</calories>
  </food>
  <food>
    <name>Homestyle Breakfast</name>
    <price>$6.95</price>
    <description>Two eggs, bacon or sausage, toast, and our ever-popular hash browns</description>
    <calories>950</calories>
  </food>
</breakfast_menu>

breakfast_menu의 root안에 food노드가 5개가 있다.

이런 경우도 1개일 때와 다른 것이 거의 없다.

NodeList 객체가 갖고있는 Node의 수가 5개가 된다는 점만 다르다.

 

using System;
using System.Collections.Generic;
using System.Collections;
using System.Xml;

namespace ConsoleApp1
{
    class cstest
    {
        static void Main(string[] args)
        {
            XmlDocument XmlFile = new XmlDocument();
            XmlFile.Load("BreakfastMenu.xml");
            //xml형태의 string변수가 있다면 .LoadXML(string)

            XmlNodeList XmlList = XmlFile.GetElementsByTagName("food");
            //XmlList는 <food>...</food>를 하나의 Node로 하는 List를 반환.

			//food node가 5개 -> 5번 반복함.
            foreach(XmlNode item in XmlList)
            {
                Console.WriteLine("---Food---");
                Console.WriteLine($"name : {item["name"].InnerText}");
                Console.WriteLine($"price : {item["price"].InnerText}");
                Console.WriteLine($"description : {item["description"].InnerText}");
                Console.WriteLine($"calories : {item["calories"].InnerText}\n");
            }

            return;
        }
    }
}

코드는 거의 똑같다.

Node와 NodeList의 관계

그냥 NodeList에 Node의 개수가 늘어난 것 뿐이다.

 

 

실행 결과

보면 이 예도 잘 출력하고 있는 것을 알 수 있다.

 

3. 특별한 구조

이 예를 뭐라고 말해야 할지 모르겠지만.. 구조체 변수라고 생각하면 될 것 같은데 그건 아니고.. 

이런 구조를 XML에서 정확히 뭐라고 부르는지 용어는 잘 모르겠으나 여튼 이런 경우가 있을 수도 있다.

<?xml version="1.0" encoding="UTF-8"?>
<circles>
	<circle>
		<point>
			<x>5</x>
			<y>4</y>
		</point>
		<radius>3</radius>
		<area>3*3*PI</area>
	</circle>
</circles>

이런 구조처럼 "circle"이라는 node안에 Point라는 또 다른 구조체(?) 같은 게 있다. point.x , point.y처럼 접근하고 싶게 생긴..

 

이럴 땐 어떻게 parsing 하면 좋을까?

using System;
using System.Collections.Generic;
using System.Collections;
using System.Xml;

namespace ConsoleApp1
{
    class cstest
    {
        static void Main(string[] args)
        {
            XmlDocument XmlFile = new XmlDocument();
            XmlFile.Load("Circle.xml");

            XmlNodeList XmlList = XmlFile.GetElementsByTagName("circle");

            foreach(XmlNode item in XmlList)
            {
                Console.WriteLine("Point");
                Console.WriteLine($"x : {item["point"]["x"].InnerText}");
                Console.WriteLine($"y : {item["point"]["y"].InnerText}");
                Console.WriteLine($"radius : {item["radius"].InnerText}");
                Console.WriteLine($"area : {item["area"].InnerText}");
            }

            return;
        }
    }
}

 

이처럼 ["point"]["x"] 이런 형식으로 접근하면 된다.

 

결과

잘 동작하는 것을 볼 수 있다.

 


그래서 결론은,

xml파싱은 C#에서 기본으로 제공하고 있기 때문에 간편하게 할 수 있다.

파싱 하기 위해서는 xml의 구조를 미리 알고 있어야 한다.

라는 점을 내릴 수 있겠다.

 

여러 블로그들을 살펴보다가 각 블로그 쓰신 분들마다 방법이 달라서 정리를 했다.

MSDN에도 잘 나와있다.

docs.microsoft.com/ko-kr/dotnet/api/system.xml.xmldocument?view=net-5.0

 

XmlDocument 클래스 (System.Xml)

XML 문서를 나타냅니다.Represents an XML document. 이 클래스를 사용하여 문서에서 XML 로드, 유효성 검사, 편집, 추가 및 위치 지정을 수행할 수 있습니다.You can use this class to load, validate, edit, add, and posit

docs.microsoft.com

사전에 xml의 구조를 알고 있는 상태에서 xml파일을 파싱 하는 것은 위에 포스팅한 코드가 가장 간결하고 편리한 것 같다.

위 코드들은 foreach를 사용해서 처음부터 끝까지 훑는 것 밖에 안 하지만, list안에 node가 여러 개 있고 그중에 몇 번째에 어느 값에 접근하고 싶을 때까지도 응용해서 사용할 수 있겠다.

개발을 하면서 xml에 대해서 더 필요한 부분이 있다거나 하면 그때 더 내용을 추가하겠습니다. ^_^

 

도움이 되었으면 좋겠습니다.

지적, 댓글 환영입니다.

댓글
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Total
Today
Yesterday