1. XML 검증이 왜 필요할까
XML은 매우 유연한 포맷이어서 때로는 지나치게 관대해요. 엄격한 타입 데이터와 달리 XML은 오류를 허용하는 경향이 있어서 태그를 닫지 않거나 속성 이름을 잘못 쓰면 파서 단계에서 에러가 나거나, 더 나쁘게는 아무런 문제가 없다고 지나갈 수도 있습니다.
XSD(XML Schema Definition)에 의한 검증은 XML 파일이 미리 정의된 계약(contract)에 완전히 부합하는지 확인하는 방법이에요: 태그 이름, 순서, 타입, 필수 여부, 개수 제한 등. 데이터의 출입 심사(passport control) 같다고 보면 됩니다 — 스키마가 말하죠: "필요한 필드가 없거나 길이가 맞지 않으면 통과 못 한다!"
검증은 엔터프라이즈 시스템, 시스템 간 데이터 교환, API 등에서 중요합니다 — 왜냐하면 구조가 잘못된 데이터를 조용히 받아들이는 걸 원치 않으니까요.
XSD(XML Schema Definition)는 다른 XML의 구조를 형식화한 별도의 XML 문서예요. XSD에서 허용되는 태그, 필수 태그, 속성이나 자식 요소의 타입, 문자열 패턴, 숫자 제약, 가능한 값(enumeration) 등을 정의합니다.
| XML | XSD (구조 설명) |
|---|---|
|
|
|
|
XSD는 JSON 세계의 JSON Schema와 유사해요.
2. XSD와 연관된 XML 예제
XML 예제
<person age="23">
<name>Ivan</name>
<email>ivan@example.com</email>
</person>
XSD 예제
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="person">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="email" type="xs:string" minOccurs="0"/>
</xs:sequence>
<xs:attribute name="age" type="xs:positiveInteger" use="required"/>
</xs:complexType>
</xs:element>
</xs:schema>
이 스키마가 설명하는 것:
- 루트 요소 — <person>.
- <person> 내부에는 <name>(필수)과 <email>(선택)이 나와야 해요.
- <person>에는 양의 정수 값인 age 속성이 필수입니다.
3. .NET에서 XSD로 XML 검증하기
.NET에서는 전형적으로 System.Xml과 System.Xml.Schema 네임스페이스를 사용해요.
작동 순서:
- XML 파일을 로드한다
- XSD 스키마를 로드한다
- 스키마를 XML 검증에 "연결"한다
- 검증을 실행하고 가능한 오류를 처리한다
기본 예제:
using System;
using System.IO;
using System.Xml;
using System.Xml.Schema;
// 1. 검증 에러 핸들러
void ValidationCallBack(object? sender, ValidationEventArgs e)
{
Console.WriteLine($"검증 오류: {e.Message}");
}
string xmlPath = "person.xml";
string xsdPath = "person.xsd";
// 2. 스키마 로드
XmlSchemaSet schemas = new XmlSchemaSet();
schemas.Add("", xsdPath);
XmlReaderSettings settings = new XmlReaderSettings();
settings.Schemas = schemas;
settings.ValidationType = ValidationType.Schema;
settings.ValidationEventHandler += ValidationCallBack;
// 3. 설정을 적용해 XML 열기
using XmlReader reader = XmlReader.Create(xmlPath, settings);
while (reader.Read())
{
// 문서를 순회만 하면 검증은 "실시간"으로 일어납니다
}
Console.WriteLine("검증 완료!");
설명:
- 모든 검증 오류는 콜백 ValidationCallBack에서 잡힙니다.
- 오류가 없으면 문서는 스키마에 부합합니다 (ValidationType.Schema).
- 불일치(예: age 누락, 유효하지 않은 email, 불필요한 필드 추가 등)는 콘솔에 표시됩니다.
오류 종류와 피드백
XSD 검증은 여러 이유로 "불평"할 수 있어요. 흔한 시나리오와 오류 예시는 다음과 같습니다:
- 필수 요소 누락(minOccurs="1" 기본값)
- XSD에 정의되지 않은 불필요한 태그
- 잘못된 타입의 속성(예: age="abc" — 숫자여야 함)
- 문자열이 패턴(<xs:pattern>)과 불일치
전형적인 에러:
검증 오류: 'age' 요소의 텍스트 내용 'abc'는 허용되지 않습니다. 기대한 타입은 'xs:positiveInteger'입니다.
4. 더 복잡한 XSD: 타입, 열거형, 패턴
XSD는 허용 가능한 데이터를 기술하는 데 정말 강력해요. 몇 가지 고급 예제를 볼게요:
허용값 열거
<xs:element name="gender">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="male"/>
<xs:enumeration value="female"/>
<xs:enumeration value="diverse"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
문자열 길이 제한
<xs:element name="code">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:length value="8"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
간단한 email 패턴
<xs:element name="email">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:pattern value="\w+@\w+\.\w+"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
자체 타입을 만들고 상속하거나 중첩 요소를 활용할 수 있어요 — 거의 OOP처럼 설계할 수 있습니다.
5. 복잡한 문서 검증
우리 교육용 앱이 학생 목록을 XML로 내보낸다고 가정해볼게요. 코드 예제를 추가합니다!
XML 예제
<students>
<student id="1">
<name>Elena</name>
<grade>5</grade>
</student>
<student id="2">
<name>Alexey</name>
<grade>4</grade>
</student>
</students>
XSD 스키마
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="students">
<xs:complexType>
<xs:sequence>
<xs:element name="student" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="grade">
<xs:simpleType>
<xs:restriction base="xs:integer">
<xs:minInclusive value="1"/>
<xs:maxInclusive value="5"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
<xs:attribute name="id" type="xs:integer" use="required"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
코드에서의 검증(같은 방식):
// 파일 경로
string xmlPath = "students.xml";
string xsdPath = "students.xsd";
XmlSchemaSet schemas = new XmlSchemaSet();
schemas.Add("", xsdPath);
XmlReaderSettings settings = new XmlReaderSettings();
settings.Schemas = schemas;
settings.ValidationType = ValidationType.Schema;
settings.ValidationEventHandler += ValidationCallBack;
using XmlReader reader = XmlReader.Create(xmlPath, settings);
while (reader.Read()) { /* 이전과 동일 */ }
6. 유용한 팁
XML에 스키마를 직접 지정하기(xsi:schemaLocation)
실무에서는 루트 요소에 xsi:schemaLocation이나 xsi:noNamespaceSchemaLocation 속성이 붙어 있는 XML을 자주 봅니다:
<students xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="students.xsd">
...
</students>
이 속성이 있으면 파일이 자동으로 검증되진 않지만, 일부 검증기나 편집기는 스키마를 찾는 데 도움을 받습니다. .NET 검증에서는 필수는 아니지만 형식상 맞는 방법이에요.
스트리밍 검증과 메모리 내 검증 — XDocument 사용
LINQ to XML(XDocument)을 사용한다면 파일을 쓰지 않고 메모리 상에서 검증할 수 있어요:
using System.Xml.Linq;
using System.Xml.Schema;
// 스키마 로드
XmlSchemaSet schema = new XmlSchemaSet();
schema.Add("", "students.xsd");
// XML을 메모리에 로드
XDocument doc = XDocument.Load("students.xml");
// 검증
doc.Validate(schema,
(o, e) => Console.WriteLine($"오류: {e.Message}"),
true // 경고도 검사(보통은 과할 수 있음)
);
프로그래밍으로 XML을 생성하거나 수정할 때, 자신이 만든 문서가 스키마를 어기지 않는지 확인할 때 이 방법이 편합니다.
7. XSD로 XML 검증할 때 흔한 실수
실수 #1: 스키마를 연결하지 않았거나 XSD 경로를 잘못 지정한 경우.
결과적으로 아무 검증도 안 되어, XML 파일이 오류를 품고 있어도 통과할 수 있어요. 상대 경로 때문에 파일을 다른 위치에서 찾지 못하는 경우가 흔하니 테스트 시 절대 경로를 쓰거나 실행 파일 옆에 스키마를 두는 게 안전합니다.
실수 #2: 네임스페이스 불일치.
스키마가 네임스페이스를 사용하면 XmlSchemaSet.Add에 두 번째 인자로 그 네임스페이스를 전달해야 합니다. 그렇지 않으면 XML 구조가 맞아도 검증이 실패합니다. 네임스페이스가 없으면 빈 문자열을 전달하세요.
실수 #3: 요소 순서 불일치.
스키마에 <xs:sequence>가 정해져 있으면 요소의 순서가 중요합니다. 올바른 요소들이라도 순서가 틀리면 오류로 처리됩니다.
실수 #4: XML에 여러 네임스페이스가 선언되어 있음.
문서가 여러 namespace를 사용하면 검증이 의도치 않게 실패할 수 있어요. 다중 네임스페이스를 지원하려면 스키마 쪽을 꼼꼼히 설정해야 합니다.
실수 #5: 오류 수집과 보존을 하지 않음.
오류를 바로 콘솔에 출력하는 건 디버깅용으로는 괜찮지만, 운영 환경에서는 적절하지 않아요. 오류를 리스트로 모아서 사용자에게 적절한 형태로 전달하거나, 대량 파일 검증 시 결과를 저장하는 게 좋습니다.
GO TO FULL VERSION