Unity

[Unity][C#] Xml 데이터 쓰기, 읽기, 추가하기, 저장하기 (XmlDocument)

mystic-agit 2024. 3. 25. 14:40

사내 플랫폼과 관련된 Unity 프로젝트를 유지 및 보수하면서 사용자가 지정한 플랫폼 설정을 저장하고 불러오기할 수 있는 데이터 형태를 고민한 결과 XML 데이터를 사용하기로 하였다.

 

기존에 Json 형태의 데이터를 사용하고 있었으나 몇 가지 단점이 있었다.

- Json 파일을 문서 형식으로 불러왔을 때 시각적으로 쉽게 이해할 수 없음

- C# 에서 사용하는 Json 라이브러리에 따라 데이터를 구성하고 불러오기 하는데 구현 차이가 발생

- 내부 데이터 검색 및 삭제에 있어 코드 발생량 증가

- 기타

 

데이터의 복잡도나 양에 따라 어떤 형식을 사용하는게 좋을 지 달라지겠지만 현재 프로젝트에선 XML 데이터라면 가능한 정보를 담고 검색하는데 있어 효율적인 코드 구조를 가질 수 있을것이라 판단하였다.

 

XML 데이터 구성을 위해 XmlDocument 클래스를 사용하였고 이와 관련하여 자주 사용하는 코드 표현을 정리해보았다.

 

 

XmlDocument .NET 레퍼런스 문서

https://learn.microsoft.com/ko-kr/dotnet/api/system.xml.xmldocument?view=net-8.0

 

XmlDocument 클래스 (System.Xml)

XML 문서를 나타냅니다. 이 클래스를 사용하여 문서에서 XML 로드, 유효성 검사, 편집, 추가 및 위치 지정을 수행할 수 있습니다.

learn.microsoft.com

 

 

예제 코드 목차

 

(1) XML 파일 쓰기

(2) XML 파일 읽기

(3) XML 노드 추가하기

(4) XML 노드 삭제하기

 

 

예제 코드

 

(1) Xml 파일 쓰기

private static void writeXml() {
    XmlDocument doc = new XmlDocument();

    XmlElement elFruit = doc.CreateElement("Fruit");
    doc.AppendChild(elFruit);

    // <Fruit>
    // </Fruit>

    XmlElement elAnimal = doc.CreateElement("Animal");
    // doc.AppendChild(elAnimal);      // error, 최상위 xml tag(node)로 2번째 것을 add 할 수 없음

    XmlElement elApple = doc.CreateElement("Apple");
    elApple.SetAttribute("Color", "Red");
    elApple.SetAttribute("Flavor", "Sweet");
    // elApple.SetAttribute("Count", 5);       // error, string 타입으로 input해야함
    // elApple.SetAttribute("isGood", true);   // error, string 타입으로 input해야함
    elFruit.AppendChild(elApple);

    XmlElement elOrange = doc.CreateElement("Orange");
    elOrange.SetAttribute("Color", "Yellow");
    elOrange.SetAttribute("Flavor", "Sour");
    elFruit.AppendChild(elOrange);

    // <Fruit>
    //   <Apple Color="Red" Flavor="Sweet" />
    //   <Orange Color="Yellow" Flavor="Sour" />
    // </Fruit>

    doc.Save("ProjectSettings/MysticAgitTestXml.xml");  // 기존 파일이 있을 경우 덮어쓰기
}

 

(2) Xml 파일 읽기

private static void readXml() {
    XmlDocument doc = new XmlDocument();

    if(File.Exists("ProjectSettings/MysticAgitTestXml.xml")) {

        doc.Load("ProjectSettings/MysticAgitTestXml.xml");

        XmlElement elFruit = doc["Fruit"];

        // 자식 노드가 있는지 확인
        if(elFruit.HasChildNodes) {

            // Fruit 이하의 자식 노드 순회
            foreach(XmlElement innerEl in elFruit.ChildNodes) {

                string name = innerEl.Name;
                Debug.Log("[MysticAgitTest] name : " + name);
                string attrColor = innerEl.GetAttribute("Color");
                Debug.Log("[MysticAgitTest] attr Color : " + attrColor);
                string attrFlavor = innerEl.GetAttribute("Flavor");
                Debug.Log("[MysticAgitTest] attr Flavor : " + attrFlavor);

                // Element 내 특정 Attribute가 있는지 확인
                if(innerEl.HasAttribute("Shape")) {
                    Debug.Log("[MysticAgitTest] attr Shape exist");
                } else {
                    Debug.Log("[MysticAgitTest] attr Shape not exist"); // Shape는 없기에 로그 노출
                }
            }
        }
    }
}

 

(3) Xml 노드 추가하기

private static void addNode(string name, string color, string flavor) {
    XmlDocument doc = new XmlDocument();

    if(File.Exists("ProjectSettings/MysticAgitTestXml.xml")) {

        doc.Load("ProjectSettings/MysticAgitTestXml.xml");

        XmlElement elFruit = doc["Fruit"];

        if(elFruit != null) {
            XmlElement elNewFruit = doc.CreateElement(name);
            elNewFruit.SetAttribute("Color", color);
            elNewFruit.SetAttribute("Flavor", flavor);

            elFruit.AppendChild(elNewFruit);    // 최상위가 아닌 하위 노드의 경우 Name이 동일한 노드를 추가할 수 있음
                                                // (추가 및 삭제 시 Attribute를 확인하여 구분하도록)

            // <Fruit>
            //   <Apple Color="Red" Flavor="Sweet" />
            //   <Orange Color="Yellow" Flavor="Sour" />
            //   ++ add ++
            // </Fruit>

            doc.Save("ProjectSettings/MysticAgitTestXml.xml");
        }
    }
}

 

(4) Xml 노드 삭제하기

private static void removeNode(string removeNodeName) {
    XmlDocument doc = new XmlDocument();

    if(File.Exists("ProjectSettings/MysticAgitTestXml.xml")) {

        doc.Load("ProjectSettings/MysticAgitTestXml.xml");

        XmlElement elFruit = doc["Fruit"];
        XmlElement elRemoveTarget = null;
        bool findsNode = false;

        // 자식 노드가 있는지 확인
        if(elFruit.HasChildNodes) {

            // Fruit 이하의 자식 노드 순회
            foreach(XmlElement innerEl in elFruit.ChildNodes) {
                string name = innerEl.Name;

                if(name.Equals(removeNodeName)) {
                    // 파라메터 노드 이름과 같은 것이 있다면
                    findsNode = true;
                    break;
                }
            }

            if(findsNode) {
                elRemoveTarget = elFruit[removeNodeName];
                elFruit.RemoveChild(elRemoveTarget);    // 노드 제거

                doc.Save("ProjectSettings/MysticAgitTestXml.xml");
            }
        }
    }
}