CodeGym /행동 /C# SELF /XML을 XSD 스키마로 검증하기

XML을 XSD 스키마로 검증하기

C# SELF
레벨 48 , 레슨 4
사용 가능

1. XML 검증이 왜 필요할까

XML은 매우 유연한 포맷이어서 때로는 지나치게 관대해요. 엄격한 타입 데이터와 달리 XML은 오류를 허용하는 경향이 있어서 태그를 닫지 않거나 속성 이름을 잘못 쓰면 파서 단계에서 에러가 나거나, 더 나쁘게는 아무런 문제가 없다고 지나갈 수도 있습니다.

XSD(XML Schema Definition)에 의한 검증은 XML 파일이 미리 정의된 계약(contract)에 완전히 부합하는지 확인하는 방법이에요: 태그 이름, 순서, 타입, 필수 여부, 개수 제한 등. 데이터의 출입 심사(passport control) 같다고 보면 됩니다 — 스키마가 말하죠: "필요한 필드가 없거나 길이가 맞지 않으면 통과 못 한다!"

검증은 엔터프라이즈 시스템, 시스템 간 데이터 교환, API 등에서 중요합니다 — 왜냐하면 구조가 잘못된 데이터를 조용히 받아들이는 걸 원치 않으니까요.

XSD(XML Schema Definition)는 다른 XML의 구조를 형식화한 별도의 XML 문서예요. XSD에서 허용되는 태그, 필수 태그, 속성이나 자식 요소의 타입, 문자열 패턴, 숫자 제약, 가능한 값(enumeration) 등을 정의합니다.

XML XSD (구조 설명)
<person age="23">Ivan</person>
<element name="person" ... />
<item price="1000"/>
<element name="item" type="..." />

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.XmlSystem.Xml.Schema 네임스페이스를 사용해요.

작동 순서:

  1. XML 파일을 로드한다
  2. XSD 스키마를 로드한다
  3. 스키마를 XML 검증에 "연결"한다
  4. 검증을 실행하고 가능한 오류를 처리한다

기본 예제:

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: 오류 수집과 보존을 하지 않음.
오류를 바로 콘솔에 출력하는 건 디버깅용으로는 괜찮지만, 운영 환경에서는 적절하지 않아요. 오류를 리스트로 모아서 사용자에게 적절한 형태로 전달하거나, 대량 파일 검증 시 결과를 저장하는 게 좋습니다.

2
과제
C# SELF, 레벨 48, 레슨 4
잠금
XML 구조 확장 및 다양한 규칙으로 검증하기
XML 구조 확장 및 다양한 규칙으로 검증하기
1
설문조사/퀴즈
XML-데이터 다루기, 레벨 48, 레슨 4
사용 불가능
XML-데이터 다루기
XML 직렬화 설정하기
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION