2010년 9월 17일 - 독자의 의견에 따라 필자는 Listing 3, 11, 12 및 13에 있는 코드를 업데이트했다.
스키마는 강력한 XML 스키마 정의 언어(XSD, 때로는 W3C Schema라고 함)를 사용하여 다른 XML 데이터를 모델링하고 이 데이터의 유효성을 검증하는 잘 구성된 XML 문서이다. 스키마 파티클(요소, 유형, 속성 및 기타 구조물)을 어떻게 정의하느냐에 따라 이러한 파티클과 관련된 범위가 글로벌/노출됨이나 로컬/숨김이 된다. 스키마 범위를 제대로 설계해야 스키마를 발전시키고 재사용하거나 다른 기술과 상호 운용할 수 있게 된다.
지금부터는 스키마를 사용하려고 하건, 현재의 솔루션에서 더 많은 것을 얻어내려고 하건 관계없이 스키마 범위를 이해하는 것이 성공에 중요하다. 이 기사에서는 먼저, 다양한 스키마 파티클을 대상으로 글로벌이나 로컬 범위를 어떻게 정의하는지 살펴보고 스키마 범위가 파티클의 작동에 어떻게 영향을 주는지 설명한다. 그런 다음, 기본적인 스키마 설계 패턴을 살펴보고 해당 프로젝트의 요구에 맞는 스키마 범위를 설계하는 데 필요한 고려사항과 우수 사례를 탐구한다.
스키마의 상위 레벨 컨테이너 요소는 schema이다. schema 요소의 직접 하위 요소는 글로벌로 정의되며 따라서 이 요소에는 글로벌 범위가 지정된다. 글로벌 요소를
루트 노드로 사용할 수 있으며 스키마의 다른 부분에서 이 요소를 참조할 수도 있다. 일단 schema 요소를 정의하면 스키마 전체에서 이 요소를 재사용할 수 있다.
Listing 1에 있는 스키마 예제에는 하나의 글로벌 요소 postalCode를 사용하는 간단한 데이터 모델이 표시되어 있다.
Listing 1. 하나의 글로벌 요소가 있는 스키마
<xs:schema> <xs:element name='postalCode' type='xs:string'/> </xs:schema> |
Listing 1에 있는 스키마를 사용하여 다음과 같은 데이터 인스턴스의 유효성을 성공적으로 검증할 수 있다.
<postalCode>14534</postalCode> |
이 데이터 인스턴스에서 postalCode는 루트 요소 즉, 데이터 인스턴스 내에 있는 상위 레벨 컨테이너이다. 연관된 스키마에서 가장 상위 레벨에 있는 요소만
데이터 인스턴스의 루트 요소로 역할을 한다. Listing 1에 있는 스키마에서는 하나의 요소만 정의했으므로 postalCode만 데이터 인스턴스의 루트 요소로 역할을
한다는 점을 쉽게 이해할 수 있다.
Listing 2에 있는 예제 스키마에서는 루트 레벨에서 두 개의 요소를 정의했다.
Listing 2. 두 개의 가능한 루트 요소가 있는 스키마
<xs:schema> <xs:element name='postalCode' type='xs:string'/> <xs:element name='zipCode' type='xs:string'/> </xs:schema> |
postalCode나 zipCode는 Listing 2에 있는 스키마로 모델링한 인스턴스의 루트 요소로 역할을 할 수 있다.
요소를 로컬로 정의하면 요소가 스키마의 다른 부분에 노출되지 않는다. 로컬 요소의 컨텍스트는 요소의 현재 위치로 제한되므로 해당 스키마의 다른 부분에서 이 요소를
참조할 수 없다. Listing 3에 있는 예제에서 zipCode 요소는 글로벌로 정의하지 않았다.
그 대신 address 요소의 하위 요소로서 요소 정의의 complexType 안에 정의했다.
Listing 3. 로컬 하위 요소가 있는 하나의 글로벌 요소
<xs:schema>
<xs:element name='address'>
<xs:complexType>
<xs:sequence>
<xs:element name='street' type='xs:string'/>
<xs:element name='city' type='xs:string'/>
<xs:element name='state' type='xs:string'/>
<xs:element name='zipCode' type='xs:string'/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
|
zipCode 요소를 address 요소의 선언 내에 정의했기 때문에 zipCode 요소는 로컬로 정의된 것이며 이 요소의 범위는 address 요소 내로 한정된다. 문서 인스턴스가
유효하려면 zipCode 요소가 Listing 4에서와 같이 address 요소 내에 있어야 한다.
Listing 4. Listing 3에 있는 스키마에 유효한 데이터 인스턴스
<address> <!-- street, city and state hidden for example purposes --> <zipCode>14534</zipCode> </address> |
Listing 4에서는 address 요소가 루트 요소가 된다. zipCode 요소는 스키마 모듈에서 루트 레벨로 글로벌하게 정의되지 않았기 때문에
인스턴스의 루트 요소로 역할을 할 수 없다. 로컬로 정의한 요소는 이 요소가 정의된 요소 정의의 컨텍스트에서만 있을 수 있다.
글로벌로 정의된 요소는 루트 요소로 역할을 할 뿐만 아니라 이 요소를 필요로 하는 로컬 범위에 존재하거나 이 범위에서 참조할 수 있다. Listing 5에 있는 예제에서
글로벌로 정의된 zipCode 요소는 로컬로 범위가 지정된 컨텍스트에 있는 address 요소의 정의 내에서 사용된다.
Listing 5. 로컬 범위에서 참조된 글로벌 요소
<xs:schema>
<xs:element name="address">
<xs:complexType>
<xs:sequence>
<xs:element name='street' type='xs:string'/>
<xs:element name='city' type='xs:string'/>
<xs:element ref='zipCode'/> <!-- reference to globally defined element -->
</xs:sequence>
</xs:complexType>
</xs:element>
<!-- Globally defined element that is referenced in element above -->
<xs:element name='zipCode' type='xs:string'/>
</xs:schema>
|
요소 선언을 노출하면 모듈화와 재사용을 글로벌하게 지원할 수 있다는 점을 알 수 있다. 이 스키마의 다른 부분에서 그리고 이 스키마를 가져올 수 있는
상위 스키마에서 zipCode 요소를 참조할 수 있다.
속성 정의도 같은 방식으로 작동한다. 예를 들면, Listing 6에서 글로벌로 정의된 state 속성은 로컬로 범위가 지정된 컨텍스트에 있는 address 요소 내에서 참조된다.
Listing 6. 로컬 범위에서 참조된 글로벌 속성
<xs:schema> <xs:element name='address'> <xs:complexType> <!--[.. elements removed for readability..]--> <xs:attribute ref="state"/> <!-- referencing globally defined attribute --> </xs:complexType> </xs:element> <xs:attribute name="state" type="xs:string"/> <!--globally defined attribute --> </xs:schema> |
요소와 속성을 글로벌로 정의할 수 있듯이 유형 또한 같은 형태로 정의할 수 있다. 이전 예제에서는 address 요소 정의에 로컬로 정의된 유형을 사용했다. 이 유형 정의를
글로벌로 바꾸려면 로컬 정의에서 이 유형 정의를 제거하고 이 유형 정의에 고유의 이름을 부여한 후, Listing 7과 같이 루트 schema 노드 아래에 삽입한다.
Listing 7. 로컬 범위에서 참조된 글로벌 유형
<xs:schema>
<xs:element name='address' type="address.type"/>
<xs:complexType name="address.type">
<xs:sequence>
<xs:element name='street' type='xs:string'/>
<xs:element name='city' type='xs:string'/>
<xs:element name='state' type='xs:string'/>
<xs:element name='zipCode' type='xs:string'/>
</xs:sequence>
</xs:complexType>
</xs:schema>
|
그러면 유형 정의가 글로벌로 바뀌며 고유 이름(address.type)을 갖게 된다. 이 유형을 요소와 연관시키려면 유형 속성(type="")을 글로벌 유형 이름과
연관시켜서 이 유형을 참조한다. xs:extension 요소를 사용하여 글로벌 유형 정의를 확장하거나 xs:restriction 요소를 사용하여 글로벌 유형 정의를 제한할 수 있다.
스키마 파티클을 로컬이나 글로벌 범위 중 어느 것으로 정의해야 하는지 결정하기가 언제나 쉬운 것은 아니다. 유스 케이스, 네임스페이스 요구사항 및 스키마의 발전에 따라 각 상황에 맞는 최상의 선택을 해야 한다. 일반적으로 스키마 설계에는 다음과 같은 네 가지 기본적인 패턴이 있다.
- Russian doll
- Salami slice
- Venetian blinds
- Garden of Eden
해당 프로젝트에 맞는 최상의 솔루션을 판별하려면 이러한 패턴을 이해해야 한다.
이 패턴은 인형 속에 작은 크기의 인형이 연속해서 들어 있는 유명한 나무 인형인 마트로시카 러시아 인형을 본떠서 이름이 붙여졌다. Russian doll 패턴에서는 모든 하위 요소를 로컬로 정의하며 따라서 각 요소와 요소의 유형은 러시아 인형처럼 해당 상위 요소에 의해 캡슐화된다.
Listing 8에 있는 예제 즉, 홈 어플라이언스용 도움말 문서를 간단히 표현한 예제에서 이 패턴을 확인할 수 있다.
Listing 8. Russian doll 스타일의 스키마
<xs:schema>
<xs:element name="HelpDoc">
<xs:complexType>
<xs:sequence>
<xs:element name="Section">
<xs:complexType>
<xs:sequence>
<xs:element name="Title" type="xs:string"/>
<xs:element name="Body" type="xs:string"/>
</xs:sequence>
<xs:attribute name="name" type="xs:string"/>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:/complexType>
</xs:element>
</xs:schema>
|
연관된 인스턴스는 Listing 9와 같은 형태가 된다.
Listing 9. Russian doll 스키마 모델에 부합하는 인스턴스
<HelpDoc> <Section name="operation_instructions"> <Title>Operating your appliance.</Title> <Body>First, open the packaging and check to see...</Body> </Section> </HelpDoc> |
Listing 8에 있는 모든 하위 요소와 속성 및 유형이 로컬로 정의되어 있음을 알 수 있다. 글로벌 요소는 루트 요소인 HelpDoc이 유일하다. 이 구문은 간결하여
쉽게 판독할 수 있을 것으로 생각하는 사람도 있을 것이다. Russian doll 스타일의 스키마에서는 다른 유형이나 요소, 스키마에 컴포넌트가 노출되지 않기 때문에
이러한 스키마는 분리가 잘 되어 있고 결합력이 우수한 것으로 여겨진다. 다시 말해서 요소와 요소가 전체적으로 서로 독립되어 있으며
관련 요소가 독립적인 하나의 상위 요소 내에서 그룹화되어 있다.
이 패턴은 다른 시스템과 거의 상호작용하지 않고 컴포넌트를 재사용하지도 않도록 설계된 스키마에서 일반적으로 사용한다. 이 방식으로 스키마를 정의하면 구조의 독립성을 유지하고 네임스페이스를 숨길 수 있으며 다른 시스템에 영향을 주는 것을 막을 수도 있다.
Salami slice 패턴을 사용하면 컨텐츠 모델을 노출할 수 있게 된다. 이 패턴에서는 로컬로 정의된 모든 요소를 글로벌 정의로 이동시킨다. Listing 10에는 Listing 8에 있는 Russian doll 스타일의 예제를 Salami slice 패턴에 맞게 수정한 것이 표시되어 있다.
Listing 10. Salami slice 패턴
<xs:schema>
<xs:element name="Body" type="xs:string"/>
<xs:element name="Title" type="xs:string"/>
<xs:element name="Section">
<xs:complexType>
<xs:sequence>
<xs:element ref="Title"/>
<xs:element ref="Body"/>
</xs:sequence>
<xs:attribute name="name" type="xs:string"/>
</xs:complexType>
</xs:element>
<xs:element name="HelpDocs">
<xs:complexType>
<xs:sequence>
<xs:element ref="Section"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
|
Salami slice 패턴에서는 모든 요소가 노출되기 때문에 스키마의 다른 부분에서 요소를 참조하거나 재사용할 수 있지만 다른 스키마에서는 요소를
볼 수 없다. 요소의 재사용 가능성이 커진다는 점이 이 방식의 중요한 장점이다. 그러나 이 때문에 모든 네임스페이스가 전체적으로 노출되며
요소 간의 결합이 증가한다. Listing 10에서는 Section 요소가 Title과 Body 요소에 글로벌로 결합되어 있다. Title과 Body 요소를 수정하면 Section 정의가 영향을 받는다.
Venetian blinds 패턴에서는 모든 요소를 글로벌로 정의하는 대신 Listing 11과 같이 먼저 모든 유형을 글로벌로 정의한다.
Listing 11. Venetian blinds 패턴
<xs:schema>
<xs:complexType name="section.type">
<xs:sequence>
<xs:element name="Title" type="xs:string"/>
<xs:element name="Body" type="xs:string"/>
</xs:sequence>
<xs:attribute name="name" type="xs:string"/>
</xs:complexType>
<xs:complexType name="helpdocs.type">
<xs:sequence>
<xs:element name="Section" type="section.type"/>
</xs:sequence>
</xs:complexType>
<xs:element name="HelpDocs" type="helpdocs.type"/>
</xs:schema>
|
Venetian blinds 스타일에서는 글로벌 유형 정의를 사용하여 재사용 능력을 증대한다. 이 스타일에서는 모든 하위 요소를 로컬화할 수 있기 때문에 네임스페이스를 숨길 수
있다는 장점을 추가로 활용할 수 있다. 이 방식을 이용하면 elementFormDefault 속성을 스위치로 사용하여 네임스페이스를 숨기거나 노출하면서
재사용할 목적으로 구조 정의를 노출할 수 있다. 이 스타일을 사용하면 위에서 살펴본 두 가지 스타일의 장점을 모두 활용할 수 있다.
Garden of Eden 설계 패턴에서는 요소 선언과 유형 선언을 모두 글로벌로 정의하여 최대한 글로벌화한다. Listing 12에는 Garden of Eden 스타일 스키마가 표시되어 있다.
목록 12. Garden of Eden 패턴
<xs:schema>
<xs:attribute name="name" type="xs:string"/>
<xs:element name="Title" type="xs:string"/>
<xs:element name="Body" type="xs:string"/>
<xs:element name="Section" type="section.type"/>
<xs:element name="HelpDocs" type="helpdocs.type"/>
<xs:complexType name="section.type">
<xs:sequence>
<xs:element ref="Title"/>
<xs:element ref="Body"/>
</xs:sequence>
<xs:attribute ref="name"/>
</xs:complexType>
<xs:complexType name="helpdocs.type">
<xs:sequence>
<xs:element ref="Section"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
|
비록 네임스페이스를 강제로 노출시켜야 하지만 가능한 모든 요소, 속성 및 유형을 글로벌로 정의함으로써 내부에서 그리고 스키마 간에서 재사용을 극대화한다. 구조를 완전히 노출하여 스키마가 강력하게 결합되면서도 신속하게 이동될 수 있게 한다. 요소가 독립적이기 때문에 스키마를 전면적으로 변경하는 경우에도 신속하게 변경 사항을 적용할 수 있다.
스키마를 설계할 때는 재사용 가능한 컴포넌트를 노출하고, 네임스페이스를 숨기고, 네임스페이스 노출을 제한하고, 결합(다수의 글로벌 요소나 유형의 상호 의존성)을 줄이면서 밸런싱 작업을 수행하는 경우가 많다. 그림 1에는 네 가지 스키마 패턴의 재사용 가능성이 요약되어 있으며 각 패턴의 상대적인 결합 및 노출 정도가 표시되어 있다.
그림 1. 네 가지 스키마 패턴의 상대적인 결합 및 노출 정도
스키마 컴포넌트의 재사용 가능성이 커지면 앞으로 있을 개발 과정에 소요되는 시간을 줄일 수 있으며 전체적인 변경을 쉽게 수행할 수 있다. 그러나 많은 요소와 유형이 불필요하게 결합되는 경우가 발생할 수도 있다. 스키마가 강하게 결합되면 요소와 유형이 상호 의존하게 되고 그 결과 앞으로 있을 변경 및 추가 작업을 관리하는 데 어려움이 따를 수 있다. 다른 시스템이 일관성이 유지되는 인터페이스에 의존하기 때문에 결합이 강화되면 스키마를 개선하는 데 문제가 발생할 수 있다. 무엇을 얼마나 많이 노출할 것인지 주의해서 선택해야 한다. 일단 선택을 하면 다시 되돌리기는 어렵다.
그럼에도 불구하고 성공적으로 스키마를 설계할 수 있는 방법이 있다. 다음과 같은 방법을 사용하여 스키마 범위를 설계하도록 한다.
- Russian doll 스타일은 간결하고 네임스페이스 숨김을 극대화할 수 있으므로 스키마를 재사용할 필요는 없고 크기는 반드시 줄여야 하는 경우에는 Russian doll 스타일을 사용한다.
- 스키마를 설계할 때 반드시 요소를 대체해야 하거나 다른 스키마에서 요소를 볼 수 없게 해야 하는 경우에는 Salami slice 스타일이나 Garden of Eden을 사용한다.
- 네임스페이스를 숨길 수 있는 가능성을 극대화하거나 재사용 능력을 높이려면 Venetian blinds 스타일을 사용한다. 그런 다음,
elementFormDefault를 전환 스위치로 사용하여 네임스페이스를 노출하거나 숨긴다.
또한, 설계 패턴을 혼합해서 사용할 수도 있다. 특정 스키마에서 다양한 스키마 설계 패턴을 사용하면 많은 장점을 얻을 수 있다. 공개하고 싶지 않거나 숨기고 싶은 구조의 부분에 대해서는 Russian doll 스타일을 사용한다. 이와 동시에 Salami slice나 Garden of Eden 설계를 사용하여 일부 요소를 글로벌로 노출할 수도 있다. 예를 들면, Listing 13에서는 숨겨진 Russian doll 스타일 섹션과 명확하게 노출된 Garden of Eden 스타일 섹션을 함께 사용한다.
Listing 13. 패턴 혼합
<xs:schema>
<!-- Garden of Eden style component -->
<xs:element name="Title" type="xs:string"/>
<xs:element name="Body" type="xs:string"/>
<xs:element name="Section" type="section.type"/>
<xs:element name="HelpDocs" type="helpdocs.type"/>
<xs:complexType name="section.type">
<xs:sequence>
<xs:element ref="Title"/>
<xs:element ref="Body"/>
</xs:sequence>
<xs:attribute name="name"/>
</xs:complexType>
<xs:complexType name="helpdocs.type">
<xs:sequence>
<xs:element ref="Section"/>
<!-- Russian doll style component -->
<xs:element name="Credits">
<xs:complexType>
<xs:sequence>
<xs:element name="Author" type="xs:string"/>
<xs:element name="Year" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:schema>
|
아마도 이 시나리오에서는 사용할 다른 스키마에 HelpDocs, Section, Title 및 Body 요소를 노출해야 한다. 그러나 Credits 요소를 숨겨서
이 요소가 다른 스키마 정의와 결합되지 않도록 하려고 한다.
재사용에 대한 필요성이 크지 않은 경우에는 이 방식으로 스키마를 작성하는 것이 매우 논리적이다. 요소를 글로벌로 정의하면 노출을 확대하기가 쉽다. 그러나 나중에 노출을 제거하기는 매우 어렵다. 이 경우에는 추후 스키마를 설계하는 과정에서 추가로 노출을 해야 하는 경우에도 쉽게 노출을 추가할 수 있다.
스키마 프로젝트를 시작하기 전에는 반드시 스키마를 설계할 때 선택해야 할 사항을 목표에 맞추어야 한다. 스키마 범위를 사용하는 방법을 이해하면 스키마와 컨텐츠를 관리하는 프로세스를 효율화할 수 있다. 그 결과 스키마 라이프사이클을 관리하는 능력이 개선되며 스키마가 다른 시스템과 효과적으로 상호 작용할 수 있게 된다.
교육
- Real-world XML Schema(Paul Golick 및 Richard Mader, developerWorks, 2002년 1월): 다양하게 적용 가능한 17가지 XML 사용 사례를 확인하자.
- The basics of using XML Schema to define elements(Ashvin Radiya 및 Vibha Dixit, developerWorks, 2000년 8월): 스키마의 유연성을 확인하고
XML 스키마 시스템에서 XML 문서의 가장 기본적인 빌딩 블록인 요소를 정의하는 방법을 배우자.
- Tip: When to use local and global declarations(Benoît Marchal, developerWorks, 2003년 9월): 이 팁에서는 요소의 글로벌 선언과 로컬 선언을 비교하고 이 선언을 사용할 시점과 관련된 지침을 제공한다.
- W3C XML Schema primer:W3C의 XML 스키마 권장사항을 확인하자.
- developerWorks의 XML 영역: XML 영역에서 기술 향상에 도움이 되는 참고자료를 얻을 수 있다.
- My developerWorks: developerWorks와 관련된 경험을 개인화할 수 있다.
- IBM XML 인증: XML 및 관련 기술에 대한 IBM 인증 개발자가 되는 방법을 찾아볼 수 있다.
- XML 기술 자료: developerWorks XML 영역에서 다양한 기술 관련 기사와 팁, 튜토리얼, 표준 및 IBM Redbook을 볼 수 있다. 또한 더 많은 XML 팁을 읽어본다.
- developerWorks 기술 행사 및 웹 캐스트: 이러한 세션에 참가하여 최신 기술에 대한 정보를 얻을 수 있다.
- Twitter의 developerWorks 페이지: 오늘 가입하여 developerWorks 트윗을 팔로우하자.
- developerWorks 팟캐스트: 소프트웨어 개발자의 흥미로운 인터뷰와 토론을 확인할 수 있다.
제품 및 기술 얻기
- IBM 제품 평가판: IBM SQA Sandbox의 온라인 시험판을 다운로드하거나 살펴보고 DB2®, Lotus®, Rational®, Tivoli® 및
WebSphere®의 애플리케이션 개발 도구 및 미들웨어 제품을 사용해 볼 수 있다.
토론
- XML 영역 토론 포럼: 여러 XML 관련 토론에 참여해 볼 수 있다.
- developerWorks 포럼 & 블로그를 통해 developerWorks 커뮤니티에 참여하자.

Casey Jordan is an structured/smart data evangelist and the co-founder of Jorsek, a company providing software and services to improve the quality of organizations' data deployment, storage, and human collaboration. Claiming more than 10 years of experience in content management and web services, Casey helps companies align their content strategies with XML technologies such as native XML databases, XQuery, XSLT, XML Schema, and DITA.
Dale Waldt has more than 25 years of experience leading the design and development of XML applications, composition and publishing solutions, and complex Web sites for a wide variety of government, commercial, and nonprofit organizations. Dale frequently works with development teams optimizing processes, designing schemas, leading data and application design and development, evaluating software and services, and training developers in XML, XSLT, and related technologies. For the past 10 years he has been a consultant, instructor, and industry analyst focusing on Web and content technology and open standards adoption. You can reach Dale at dale@axtiveminds.com.