[Unity][C#] Xml 데이터 쓰기, 읽기, 추가하기, 저장하기 (XmlDocument)
사내 플랫폼과 관련된 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");
}
}
}
}