XML/XSD - 외래키처럼 참조 제한 거는 방법
DB처럼, XML 노드 사이에서 primary/foreign key와 같은 제약 사항을 거는 방법에 대해서 기록을 남겨봅니다. 사실, xs:key/xs:keyref가 그러한 역할을 하는데, 네임스페이스 여부에 따라 주의해야 할 사항이 있더군요.
아래의 MSDN 웹 사이트의 내용으로 한번 시작해 볼까요?
Understanding the Interrelationship between Constraints and Relationships
; https://docs.microsoft.com/en-us/previous-versions/dotnet/netframework-1.1/5z124f36(v=vs.71)
위에서 소개된 XSD 예제대로 간단하게 다음과 같이 XSD를 만들고,
==== test.xsd ====
<xs:schema id="Root" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Root">
<xs:complexType>
<xs:sequence>
<xs:element name="PKItem" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="id" use="required" type="xs:string" />
</xs:complexType>
</xs:element>
<xs:element name="FKItem" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="id" use="required" type="xs:string" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:key name="ID">
<xs:selector xpath="./PKItem" />
<xs:field xpath="@id" />
</xs:key>
<xs:keyref name="IDREF" refer="ID">
<xs:selector xpath="./FKItem" />
<xs:field xpath="@id" />
</xs:keyref>
</xs:element>
</xs:schema>
그다음, XML을 일부러 참조값 하나를 틀리게 만들어 줍니다.
==== test.xml ====
<?xml version="1.0"?>
<Root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<PKItem id="1" />
<PKItem id="4" />
<FKItem id="1" />
<FKItem id="5" />
</Root>
이제 유효성 확인을 하는 코드를 제작해도 되지만, 간단하게 Visual Studio 2010에서 test.xsd, test.xml을 로드해서 확인하는 것도 가능합니다. 2개의 파일을 로드한 다음 "XML" / "Schemas" 메뉴를 선택하고 아래와 같이 test.xsd를 명시적으로 유효성 확인에 사용할 스키마로 지정해 주면 줍니다. (대개의 경우, 로드되어 있는 xsd 파일이 선택되어져 있긴 합니다.)
그럼, 곧바로 다음과 같이 파란색의 물결 무늬로 유효성에 문제가 있음을 알 수 있게 되고, 마우스로 가져가면 그 원인을 파악할 수 있습니다.
"The key sequence '5' in Keyref fails to refer to some key."
이번에는 XML에 네임스페이스를 추가시켜 볼까요?
<?xml version="1.0"?>
<Root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://www.sysnet.pe.kr/test.xsd">
<PKItem id="1" />
...[생략]...
</Root>
그럼, XSD에도 네임스페이스를 동일하게 추가시켜 주어야 합니다.
<xs:schema id="Root" elementFormDefault="qualified"
xmlns="https://www.sysnet.pe.kr/test.xsd"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Root">
...[생략]...
</xs:element>
</xs:schema>
어찌된 일인지, 위와 같이만 해주면 더 이상의 참조 관계 제약에 대한 체크가 되지 않습니다. 이 문제 해결하느라 ^^; 시간이 좀 흘렀는데요. 답을 다음의 글에서 발견할 수 있었습니다.
XSD key/keyref beginner question
; http://stackoverflow.com/questions/2015059/xsd-key-keyref-beginner-question
그리하여 해결책은, key/keyref에 지정하는 selector/@xpath의 경로에도 동일하게 네임스페이스를 지정해 주어야 한다는 것! 따라서 XSD의 key/keyref를 다음과 같이 변경해 주어야 합니다.
<xs:schema id="Root" elementFormDefault="qualified"
xmlns:my="https://www.sysnet.pe.kr/test.xsd"
xmlns="https://www.sysnet.pe.kr/test.xsd"
targetNamespace="https://www.sysnet.pe.kr/test.xsd"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Root">
...[생략]...
<xs:key name="ID">
<xs:selector xpath="./my:PKItem" />
<xs:field xpath="@id" />
</xs:key>
<xs:keyref name="IDREF" refer="ID">
<xs:selector xpath="./my:FKItem" />
<xs:field xpath="@id" />
</xs:keyref>
</xs:element>
</xs:schema>
첨부한 파일은 위의 테스트 XSD/XML 파일과 유효성 체크를 하는
C# 콘솔 프로그램 소스 코드를 포함합니다.
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]