공간정보/표준2018. 5. 27. 00:39

장면 1

우리나라 정부가 생산 관리하는 데이터를 공개하는 곳인 공공데이터 포털

- 동일한 제목의 자료를, 올린 지자체도 있고, 안올린 곳도 있다.
- CSV, Excel, XML 등 포맷이 제각기.
- 동일한 자료에 대해서도 데이터 제작 주체에 따라 구조가 달라지기도 한다.
    - 예를 들어 열의 갯수가 모두 다른 경우
    - 열로 분리, 콤마로 분리, 분리 안한 것 등등

*참고 : 영국의 경우 www(월드와이드웹)의 창시자 팀버너스리 경(Sir Tim berners-Lee)이 주도하는 ODI(Open Data Institute)와 공동으로, XML 기반으로 데이터 공유 

장면 2

국가 공간정보를 공개하는 국가공간정보포털. (사례 : 버스노선)

- 지도데이터는 존재하지 않고, "공간정보목록정보"에만 존재
    - 목록에 존재하는 지자체는 21개. (군산시는 버스노선마다 따로따로 올려서 51개)
    - 데이터의 내용 및 구조에 관한 정보가 없는 경우 많음(예: 버스노선)
    - 고유주소 없음(예 : 동두천시를 검색한 주소를 복사한후 새창에 붙이면 동작하지 않음
- "국가공간정보포털개방목록"에 BRM 분류가 있으나, 막상 클릭하면 아무것도 없는 항목 다수
- 지방자치단체에서 작성한 데이터는 거의 없는 듯

장면 3

지방자치단체간 데이터 교환

- A 지자체에서 인접한 B 지자체에 도로데이터 요청한다.
- B 지자체는 A 지자체에서 요청하는 포맷으로 변환하여 전송한다.
- A 지자체는 B 지자체의 데이터를 받은 후 그냥 사용할 수 없다. 왜그럴까?

도입

우리나라에서 데이터 교환 또는 유통체계에서 벌어지는 사례를 몇 가지 들었습니다. 공공데이터 포털에서 제공되는 데이터는, 공간정보보다 훨씬 간단한 text 정보임에도 제대로 공개/유통되지 못하고 있다고 많은 사람들이 지적하고 있습니다. 이걸 생각해보면 이보다 훨씬 구조가 복잡한 공간정보에 대한 유통 체계가 문제가 있는 것은 어쩌면 당연할 수도 있습니다.

정보공개/데이터 유통과 관련된 모든 문제는 데이터 유통체계가 미비하기 때문에 발생하는 것입니다. 유통체계가 뭐가 잘못된 것인지를 말하는 대신, 데이터 유통체계가 완벽하게 이루어지면 어떻게 데이터공개/교환/유통이 이루어질 수 있는지를 생각해 보겠습니다.

1. 개인정보보호, 보안 등 현행법에 저촉되지 않는 모든 데이터가 공개된다.
2. 모든 공개된 데이터의 상세한 내용및 구조가 별도의 데이터로서 공개된다.
3. 동일한 이름의 데이터에는 내용과 구조가 완전히 동일하다.
4. Machine Readable 한 포맷으로 공개된다.
5. 공개된 데이터의 구조도 함께 공개되며, 이 구조를 사용하여 자동 검증이 가능하다.
6. 이미 공개된 데이터가 일부 수정된 경우, 수정된 부분에 대해서 즉시 공개된다.
7. 공개된 데이터는 관련자에게 즉시 통지(notification)된다.
8. 해당 데이터의 사용자/기관은 (사람이 개입하지 않고) 자동으로 갱신된 데이터를 읽어오고,
   이 데이터를 사용하여 자신의 데이터를 자동으로 수정한다.

대략 이렇게 정리할 수 있을 것 같습니다. 즉, 데이터를 어느 사이트에 올려 놓는다고 하여 유통이 되는 것이 아니라, 이런 식으로 기계간 통신(Machine to Machine)으로, 사람이 개입하지 않고 자동으로 처리될 수 있어야만 "궁극적"으로 데이터 유통이 된다고 할 수 있습니다. 이렇게만 되면, 어느 생산자든 데이터를 수정하면 그 데이터를 사용하는 사람의 데이터도 자동 수정되어, 결국 "실시간 갱신" 시스템이 완성될 수 있을 것입니다.

이러한 체계를 갖추기는 물론 매우 어렵습니다. 하지만, 불가능한 것은 아닙니다. 데이터 공급자의 의지와 노력 (+ 제도적 뒷받침), 그리고 공간정보 표준을 준수하면 이러한 체계를 갖출 수 있습니다. 그중에서 오늘 제가 할 이야기는 공간정보 표준, 그중에서도 유통과 밀접한 관련이 있는 "데이터의 내용과 구조"에 대한 내용입니다.

데이터의 내용과 구조(응용스키마)

"데이터의 내용 및 구조"를 이야기하면 보통 데이터 교환 포맷을 떠올립니다. 텍스트 위주의 DB라면 CSV나 XML 등이 교환포맷으로 많이 사용됩니다. Excel 파일로 올리는 곳도 많지만요. 공간정보 DB는 Shape 파일이나 GML 등의 포맷이 많이 이용됩니다. 물론 아직 DXF를 선호하는 분들도 있고요. 사실 데이터 포맷 자체는 큰 문제가 아닙니다. 한글파일이나 스캐닝한 영상을 올리지만 않고, 적절한 구조를 지원만 한다면 어떤 포맷을 사용해도 데이터 교환에는 그다지 큰 문제는 없습니다. 즉, (정확한 내용 및 구조를 가지고 있다면) 데이터 교환에 어떤 포맷을 사용해도 문제는 없다는 뜻입니다. 널리 알려지지 않은 포맷이라면 불편함이 더 많아질 뿐입니다.

하지만, 현재 국가공간정보포털에 올려진 파일은, 공각정보분야에서 일하는 사람이라면 누구나 잘 알고 있는 Shape 포맷으로 올려져 있는데, 왜 바로 가져다 쓸 수 없을까요? 그것이 바로 "데이터의 내용 및 구조"에 관한 문제입니다. 

이종 시스템 간의 상호 작용을 성취하기 위해서는 두 가지 근본 문제가 결정되어야 한다. 첫 번째 문제는 공간 데이터의 내용의 의미와 논리적 구조를 정의하는 것이다. 이것은 응용 스키마에서 이루어져야 한다. 두 번째 문제는 응용 스키마와 관련된 데이터를 표현할 수 있으며, 시스템과 플랫폼 독립적인 데이터 구조를 정의하는 것이다."

이 글은 "KSXISO 19118 지리정보 - 인코딩" 표준의 6절에 있는 내용입니다. 이종 시스템간의 데이터 교환을 위해서는 첫번째 "공간데이터의 내용 및 구조" 정의, 두번째 "데이터 포맷" 정의가 필요하다는 뜻입니다.

데이터 포맷은 위에서 언급한 것처럼, 사실 데이터 교환에 참여하는 자들끼리 동일한 포맷을 사용한다면 큰 문제가 아니라고 말씀드렸습니다. 하지만, "데이터의 내용 및 구조"는 완전히 다른 문제입니다. 예를 들어 두개의 기관에서 도로데이터를 각각 다음과 같이 정의하였다고 해보겠습니다. 

A 지자체(좌측)은 모든 도로를 하나의 "Road" 클래스로 분류하고, 5가지 속성을 갖는 것으로 정의했습니다.(이중 두개의 속성은 도형정보입니다.) B 지자체는 추상클래스인 Road 를 MainRoad 클래스와 AuxRoad 클래스가 상속받도록 정의했습니다. 물론 MainRoad와 AuxRoad는 구조가 다릅니다. 도로중심선(CenterLine)은 A 지자체에서만 정의하였고, 속성들이 서로 조금씩 다른 것도 있고 아얘 빠진 것들도 있습니다. (가상이니 심각하게 받아들이지 마시길...)

A 지자체에서 B 지자체에게 도로 데이터를 Shape 포맷으로 요청하면 어떻게 될까요. 당연히 B 지자체는 자신의 현재 구조 그대로 Shape 포맷으로 변환해서 넘겨줄 것입니다. 이 데이터를 받은 A 지자체는 다음과 같은 처리가 필요할 것입니다. 

- B 지자체에서는 MainRoad와 AuxRoad로 분리되어 있는 클래스를 Road 클래스로 합쳐야 합니다.
- RoadCover 는 RoadSurface와 동일하므로 클래스명만 수정합니다.
- CenterLine은 존재하지 않으므로 RoadSurface를 사용하여 자동 생성합니다.
- DateOpen는 MainRoad에만 있으므로, AuxRoad 클래스는 임의의 날짜를 부여합니다.
- Name은 동일하므로 그대로 가져옵니다.
- Admin 도 DateOpen 과 동일한 방식으로 처리합니다.

결국 데이터는 넘겨받았지만, 모든 클래스들을 일일이 검사하고, 수정을 거쳐야만 사용할 수 있게 됩니다. 새로 처음부터 만드는 것보다야 훨씬 편하지만, 엄청 많은 수고가 필요합니다. 넘겨받을 클래스의 수가 많을 수록 더 많은 노력이 필요하겠죠.

U 라는 사업체가 있어서 이들 도로데이터를 가져와서 사용하는 경우엔 어떨까요? 먼저 A 지자체에서 데이터를 받아와 데이터를 불러들이는 프로그램을 짰습니다. 이제 B 지자체에서 데이터를 받아오면 새로 프로그램을 짜야 합니다. 또다른 데이터를 받아오면? 또다시 새로운 프로그램을 짜야죠. 이처럼 모든 기관별로 응용스키마가 조금씩 다르기 때문에 매번 조금씩 달리 편집해서 사용해야 합니다. 물론 데이터를 제공해준다는 가정하에요. 예전에 내비게이션용 도로지도를 제작하던 어떤 업체 관계자는, 매 지자체별로 별도로 접촉해서 자료를 얻어야 했는데 공개하지 않는다는 곳도 많았지만, 기껏 공개를 해도 이처럼 많은 편집/가공이 필요하다고 푸념했던 기억이 납니다.

이처럼 현재 공개된 자료들은 모두 사용하려는 사람들이 구조를 일일이 검사하고, 변환하는 프로시져를 만들고, 테스트하는 과정을 걸쳐야만 사용할 수 있습니다. 심지어는 텍스트 정보만 제공되는 공공데이터 포털도 마찬가지입니다. 어떤 한 기관에서 제공하는 자료라면 그나마 다행이지만, 여러 기관의 데이터를 취합해야 하는 경우 정말 많은 자원이 소요됩니다. 게다가 담당자가 바뀌거나, 시스템이 변경되면 모든 과정을 새로 밟아야 합니다.

관리기관별로 데이터 내용 및 구조(응용스키마)가 다른 이유는 자신의 목적에 따라 시스템을 구축하기 때문입니다. 처음 측량을 통해 생산한 원시데이터는 동일하더라도, 시스템을 구축할 때는 내부의 목적, 사용하는 하드웨어/소프트웨어의 종류 등에 따라 달라질 수 밖에 없습니다. 응용스키마가 원래 그런 성격이니까요.

공통 응용스키마

그럼 이처럼 데이터 생산/관리 기관별로 구조가 다른 상태에서 어떻게 데이터를 교환해야 할까요? 이것이 "KSXISO 19118 지리정보 - 인코딩" 표준에서 다루는 문제입니다. 아래는 이 표준의 그림 1 "두 시스템간의 데이터 교환의 개요"입니다.

이 그림을 간단하게 설명하면, 다음과 같습니다.

1. 다수의 시스템에 대하여 공통 응용스키마 I 를 정의해야 한다.
2. 내부 DB는 이 공통 응용스키마를 적용한 임시 내부 데이터베이스 M_AI 를 생성한다.
3. 이 표준에 따른 인코딩 서비스 R을 사용하여 자료를 공통포맷으로 변환한다.
4. 이렇게 만들어진 파일/스트림을 상대측에 전송한다.

즉, 자산의 내부 DB를 그냥 변환하는 것이 아니라, 공통 응용스키마를 적용하고, 공통 포맷을 적용하여 변환해야 한다는 것입니다. 물론 읽어들일 때는 이 반대의 수순을 밟으면 되고요.

여기에서 볼 수 있는 것처럼, 데이터 공유에 있어 가장 중요한 것은 데이터 공개/유통에 참여하는 모든 참여자가 공유하는 "공통 응용스키마"입니다. 공통 응용스키마를 사용하고 그것이 정확하게 지켜지기만 한다면, 어떤 포맷을 사용해도 문제없이 데이터를 공유할 수 있습니다.

XML 인코딩

그런데, KSXISO 19000 표준군에서는 모든 종류의 공간정보 교환에 XML 포맷으로 인코딩 할 것을 권장하고 있습니다. KSXISO 19118 인코딩에서는 데이터를 XML로 변환하는 규칙을 제시하고 있고, KSXISO 19136 지리마크업언어(GML)에서는 이 XML 변환규칙을 보다 정확하게 규정하고 있으며, KSX1SO 19139 메타데이터 XML 구현에서는 메타데이터를 XML 로 변환하고 공유하는 규칙을 다루고 있습니다. 즉, 데이터 교환은 가능한한 XML 을 이용하라는 것입니다.

그런데 XML(또는 GML)은 데이터 그 자체일 뿐입니다. XML을 사용한다고 하여 데이터 교환이 순조롭게 이루어질 수 없습니다. 데이터의 내용 및 구조(응용스키마)의 공유, 준수가 필수적으로 뒤따라야 합니다.

XML 스키마는 XSD(XML Schema definition)로 정의됩니다. XSD는 말그대로 XML 파일의 스키마를 정의하는 문법입니다. 일반 XML 파일은 <tag1> </tag1> 등과 같은 형태로 태그만 맞춰주면 어떠한 데이터도 추가할 수 있으습니다. 그러나, XSD를 정의하면 XSD에 정의되어 있는 항목외에는 들어갈 수 없고, XML에 XSD 정의항목이 빠졌다면 오류가 발생하게 됩니다. 즉, XML 과 XSD는 쌍으로 움직이고, 일정한 내용과 구조를 갖출 수 있게 됩니다.

이와 같이 XML 은 XSD가 존재하기 때문에 데이터와 응용스키마를 함께 공개/교환 할 수 있습니다. Shape 등 다른 포맷은 응용스키마를 일치시킨다고 해도, 해당 데이터가 응용스키마에 일치하는지 여부는 별도의 어플리케이션을 작성해야만 검증할 수 있습니다. 하지만, XSD+XML은 이 자체만으로 데이터 구조의 일관성을 유지할 수 있습니다.

19118 인코딩 표준에서는 UML로 작성된 응용스키마를 XSD로 변환하는 규칙도 제공합니다. 다음 그림은 이 표준의 "그림 C.1 - XML 기반의 변환규칙" 입니다.(일부 수정) 이 그림에서 말하는 것은, 공간정보 응용스키마는 XSD로 인코딩하고, 공간데이터(응용데이터)는 이 XSD를 기준으로 XML(GML) 로 변환한 후, 이 두개의 파일을 모두 제공하라는 것입니다. 이것이 ISO 표준에 따르는 것이죠.

따라서, 국가공간정보포털과 같은 데이터 교환장소에는 데이터를 GML(XML) 포맷으로 제공하는 외에도 다음과 같은 응용스키마 관련 정보를 함께 제공해야 합니다. 이중 위의 두가지는 사람들이 편하게 이해하기 위한 용도이고, 마지막 XSD는 컴퓨터가 직접 해석하기 위한 용도입니다. (이 이외에도 메타데이터에 관한 내용도 XML로 제공해야 하지만, 이는 생략합니다.)

- 응용스키마 (UML)
- 데이터딕셔너리 - 응용스키마 객체의 상세 해설
- XSD - XML 용 스키마

기존 공간정보를 다루는 입장에서 볼 때, Shape 파일 등이 널리 사용되고 있으므로, 이런 포맷을 사용하는 것이 더 낫다는 의견도 있을 수 있습니다. 하지만, XML 포맷을 사용하면 다음과 같은 장점이 있어서, 단순한 Shape 파일보다 월등한 편의성을 누릴 수 있습니다.

- XML 포맷은 사람들도 어렵지 않게 읽을 수 있지만, 무엇보다 컴퓨터 처리에 좋다.

- XML을 처리하기 위한 다양한 라이브러리가 존재하기 때문에(오픈 소스도 다수 존재함)
  GIS 소프트웨어를 사용하지 않아도 일관성 검증이나 통계 등 간단한 데이터 처리가 가능하다.
    - XML Validator
    - XML DOM Parser

- XML 은 W3C에서 정의한 정보 교환/처리를 위한 표준으로 Web/IT 분야에 널리 사용되고 있으며,
  특히 공간정보를 모르는 사람들도 장벽없이 처리할 수 있다.

- XML 파일의 스키마(구조)를 정확하게 정의하는 XSD (XML Schema Defintion)를 함께 제공하면,   
  데이터 구조의 검증이 아주 쉬워진다. 즉, 일관된 구조가 100% 유지할 수 있다. 

이러한 장점이 있기 때문에, 데이터 공개/교환은 XML(GML)을 사용해야 한다는 것이 제 생각입니다. 아니 다른 포맷으로는 이러한 장점을 대체할 수 없으므로, 반드시 XML(GML)을 사용해야 합니다.

결론

이제 마무리를 지어야 할 때가 왔습니다. 제가 처음에 언급했던 "완벽한 데이터 유통체계"에 대해 다시 생각해보겠습니다. 

1. 개인정보보호, 보안 등 현행법에 저촉되지 않는 모든 데이터가 공개된다.
2. 모든 공개된 데이터의 상세한 내용및 구조가 별도의 데이터로서 공개된다.
3. 동일한 이름의 데이터에는 내용과 구조가 완전히 동일하다.
4. Machine Readable 한 포맷으로 공개된다.
5. 공개된 데이터의 구조도 함께 공개되며, 이 구조를 사용하여 자동 검증이 가능하다.
6. 이미 공개된 데이터가 일부 수정된 경우, 수정된 부분에 대해서 즉시 공개된다.
7. 공개된 데이터는 관련자에게 즉시 통지(notification)된다.
8. 해당 데이터의 사용자/기관은 (사람이 개입하지 않고) 자동으로 갱신된 데이터를 읽어오고, 
   이 데이터를 사용하여 자신의 데이터를 자동으로 수정한다.

동일한 데이터에 대해 공통 응용스키마를 갖도록 하고 이를 XSD, GML 로 공개하는 체계가 갖추어진다는 것은, 이 여덟가지 중에서 2,3,4,5 항목에 해당합니다. 1번 항목은 제도적으로 해결해야 할 부분이며, 6,7,8 항목은 공개된 데이터를 실시간으로 전달할 수 있는 시스템의 구축이 필요합니다. 물론 이러한 내용도 일부(개념적 수준에서는) 표준에 정의되어 있습니다. 

현재 국토지리정보원에서는 일부 지형지물에 대해 완공이 되는 즉시 측량을 실시하는 실시간 갱신작업을 실시하고 있는 것으로 압니다. 그런데, 이러한 측량이 완료되는 시점에서 국민에게 전달될 때까지의 시간 - 즉, 네이버/다음 등의 포털지도에 나타나기 까지의 시간은 최소 6개월 이상 걸릴 것으로 생각됩니다. 제가 지금까지 말씀드린 "데이터의 내용 및 구조"라고 통칭한 이러한 기술을 적용하여, 정말 실시간으로 데이터를 공유할 수 있는 날이 빨리 오기를 소망합니다.

민, 푸른하늘


Posted by 푸른하늘이

댓글을 달아 주세요

공간정보/표준2018. 3. 30. 23:07

Aaron Skonnard

DevelopMentor

May 2003

Summary : XML Schema 정의 언어(XSD)는 include와 import와 같은 포함 메커니즘을 통해 코어 라이브러리의 재사용 및 장기 관리를 가능하게 한다. 아울러 스키마 정의를 여러개의 파일 및 네임스페이스로 분할하여 관리할 수 있다. 오늘날 사용되는 프로그래밍 언어 방식의 유형 계층을 모델링할 수 있는 스키마 라이브러리의 설계방법에 대해 배워보자.

개요

XML Schema 정의 언어(XSD)는 XML 문서를 설명하는 언어중 대세가 되고 있다. XML Schema는 simple 및 complex 유형을 정의할 수 있다. Simple 유형은 문자만의 요소/속성에 맞춤식 값공간을 정의할 수 있으며, Complex 유형은 이러한 값 공간을 배열하여 구조체를 만들수 있다. XML 스키마는 매우 표현이 뛰어나고 XML 기반 응용에 강력한 서비스를 제공할 수 있다. 특히 웹 서비스 도메인에 유용하다. 이러한 서비스로는 검증, reflection, 자동 직렬화(type mapping) 원격 메소드 발동 등이 지원되며, XML을 위한 IntelliSense와 같은 기능을 잘 지원해줄 수 있다.

나의 첫번째 글 XML Schema의 이해에서는 핵심적인 XSD 언어 구성과 사용법에 대해 다루었다. XSD는 사실 이 글에서 다루었던 것 보다 훨씬 더 강력한 기능을 제공한다. Complex 유형 정의에서는 확장이나 제한을 사용한 유도 유형을 지원함으로써, complex 유형 계층을 정의할 수 있다. complex 유형 계층이 있으면, 인스턴스 문서에서 대체 기법을 사용할 수 있게 된다. XSD는 또한 schema 정의를 여러개의 파일과 네임스페이스로 분할 한 뒤, include 혹은 import 하는 방법을 사용함으로써, 재사용과 간편한 유지보수를 가능하게 한다. 이러한 좀더 고급 설계중심의 주제가 이 글의 주제이다.

유형 계층 (Type Hierarchies)

XML Schema의 이해에서 XSD에 내장된 simple 데이터 유형의 종류를 보였다. (그림 1) 이들 데이터유형은 유형 계층으로 정의된다. 그림 1에서 화살표는 제한에 의한 유도(derivation by restriction)를 나타낸다. 즉, byte는 short을 제한함으로서 유도되는데, 이는 byte의 값공간이 short의 값공간의 부분집합이라는 의미이다. 이러한 계층성을 유형간의 관계로 생각할 수 있다. 예를 들어, 제한에 의한 유도를 사용할 때, 유도된 유형의 인스턴스는 기반 유형의 인스턴스이기도 하다는 뜻이다. (즉, byte는 short의 일종이며, short은 int의, int는 long의 일종 등등이다.)


<그림 1> XSD 내장 데이터유형

XSD를 사용하면 이 계층을 확장하여 맞춤형 simple 유형을 정의할 수 있다. 새로운 simple 유형을 정의할 때, 기본적으로 내장 데이터유형으로부터 유도된 새로운 유형을 정의하고, 하나 이상의 facet을 제한하게 된다. 다음의 예에서 tns:PersonAge 는 xsd:byte로부터 유도하여, 값공간을 0에서 100까지로 제한한다.

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns:tns="http://example.org/person"
   targetNamespace="http://example.org/person">
   ...
   <xsd:simpleType name="PersonAge">
      <xsd:restriction base="xsd:byte">
         <xsd:minInclusive value="0"/>
         <xsd:maxInclusive value="100"/>
      </xsd:restriction>
   </xsd:simpleType>
   ...
</xsd:schema>

이제 tns:PersonAge 와 xsd:byte 사이에는 유형 관계가 있다. tns-PersonAge는 xsd:byte의 유효한 인스턴스이기도 하며, xsd:byte는 xsd:short 의 유효한 인스턴스이고, xsd:short는 xsd:int의 유효한 인스턴스인다. 이러한 관계는 제한을 통한 유도 유형에서는 항상 성립한다. Simple 유형의 제한에 관한 자세한 내용은 XML Schema의 이해를 참고하라.

Complex 유형의 경우, 위의 예에서 보인 것처럼 유형 계층을 정의할 때 제한 혹은 확장에 의하여 유형을 유도할 수 있다. 하지만, 제한과 확장을 동시에 적용할 수 없다. 하나의 유형정의에서는 제한과 확장 두가지 중 하나만 사용하여 유도할 수 있다. 따라서 기본 유형을 제한하고 확장하고 싶다면, 두번을 별도로 유형 정의해야 한다.

제한에 의한 Complex 유형 유도

Simple 유형과 마찬가지로, 제한에 의하여 Complex 유형을 유도할 수 있다. 이는 기존의 Complex 유형으로부터 그 구조체를 형성하는 요소나 속성을 제한함으로써 새로운 Complex 유형을 유도할 수 있다는 것이다. 예를 들어, 사람을 표현하는 아래의 Complex 유형을 살펴보자.

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns:tns="http://example.org/person"
   targetNamespace="http://example.org/person">
   ...
   <xsd:complexType name="Person">
      <xsd:sequence>
         <xsd:element name="name" type="xsd:string"/>
         <xsd:element name="age" type="xsd:byte " minOccurs="0"/>
         <xsd:element name="phone" type="xsd:string" minOccurs="1" maxOccurs="5"/>
      </xsd:sequence>
      <xsd:attribute name="id" type="xsd:string "/>
   </xsd:complexType>
   <xsd:element name="person" type="tns:Person"/>
   ...
</xsd:schema>

다음의 XML 문서는 tns:Person 유형의 유효한 인스턴스를 담고 있다. 참고로 로컬 요소 및 속성은 정규화되어 있지 않다. (로컬 요소와 속성은 기본이 비정규화(unqualified)임) 또한 age 요소는 생략되어 있으며, phone 요소는 세번 들어가 있다. 이는 모두 유형 정의에서 허용된 것이다.

<tns:person xmlns:tns="http://example.org/person"
   id="333-22-4444">
   <name>Bob Smith</name>
   <phone>801-444-5555</phone>
   <phone>801-555-6666</phone>
   <phone>801-666-7777</phone>   
</tns:person>

만약 tns:PersonType을 구성하는 일부 요소 및 속성을 제한하려고 한다면, xsd:complexContent와 xsd:restriction 요소를 사용하여, 제한(restriction)에 의한 새로운 complex 유형을 유도할 수 있다.

...
<xsd:complexType name="RestrictedPerson">
   <xsd:complexContent>
      <xsd:restriction base="tns:Person">
        <!-- redefine base type's particles here -->
        ...
      </xsd:restriction>
   </xsd:complexContent>
</xsd:complexType>
...

xsd:complexContent 요소는 해당 complex 유형이 다른 complex 유형으로 유도된 것을 나타낸다. xsd:restriction 요소는 원래 제한하기 전의 기본 유형과, 모든 기본 유형(base type)의 particle(compositor, 요소 정의, wildcard 등)에 대한 새로운 정의를 포함한다. 이렇게 할 때에는 반드시 기본유형의 모든 particle을 나열해야 하며, 기본유형의 부모가 있을 경우, 해당 내용도 포함시켜야 한다.

기본유형은 두가지 방법으로 제한할 수 있다. 한가지는 값공간을 더 좁게 제한하는 것. 또다른 하나는 particle의 출현빈도(occurrence constraint)를 강하게하는 것이다. "값공간을 좁계"하는 것은 기본 유형에서 사용된 simple 유형으로부터 유도된 다른 유형으로 유형을 변경하면 된다. 예를 들어, tns:PersonType에서 age 요소는 xsd:byte 유형이다. age 요소의 유형을 tns:PersonAge으로 변경하면 age의 값 공간을 더 제한할 수 있다.

base 유형의 출현빈도 제한을 더 강하게 지정하는 방식으로 제한할 수도 있다. "강한 출현빈도 제한"이란, 새로운 출현빈도 제한이 기본유형의 출현빈도 제한 범위이내에 한다는 것을 의미한다. 예를 들어, 위의 phone 요소는 최소 1번에서 최대 5번 등장할 수 있다고 정의되어 있다. 유도 유형에서 이 요소를 제한 할 때, phone 요소의 minOccurs를 1보다 작게하거나, maxOccurs를 5보다 크게 바꿀 수는 없다. 하지만, 아래처럼 두면 해당요소가 반드시 2번 나타나도록 횟수제한을 강하게 하고 있다. (여전히 기본 유형의 횟수제한에 유효하다)

...
   <xsd:element name="phone" type="xsd:string"
                minOccurs="2" maxOccurs="2"/>
...

이러한 방식으로 작동되므로, 어떤 요소가 기본 유형에서 필수로 정의되어 있다면(name, phone 등), 유도 유형에서는 이를 삭제시킬 수 없다. (참고 : minOccus 와 maxOccurs의 기본값은 1이다) 하지만, 기본 유형에서 선택적 요소인 경우(age), maxOccurs=0으로 두어 출현하지 못하도록 막거나, minOccurs=1로 두어 필수 요소로 만들 수 있다. 여기에서도, 유도 유형의 횟수제한은 기본유형에서 정의된 범위 내에 있을 때만 적법하다.

속성에서도 이와 동일하다. 속성이 기본유형에서 선택적일 경우(기본값임), 필수로 만들거나, 금지시킬 수 있다.('prohibited'는 제한에서만 적용되며, 그렇지 않은 경우 무시됨) 예를 들어 다음의 속성 정의는 유도 유형에서 id 속성을 금지시키는 방법을 나타낸다.

...
<xsd:attribute name="id" type="xsd:string" use="prohibited" />
...

이제 제한된 complex 유형의 완전한 예를 살펴보자, 아래의 예제는 xsd:string을 pattern facet으로 제한한 새로운 simple 유형을 정의하고 있다. 이들 유형은 base 유형에 사용되는 일부 요소및 속성 정의를 제한하는데 사용된다. 아울러 여러 요소 및 속성 선언의 횟수제한을 제한하고 있다.

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns:tns="http://example.org/person"
   targetNamespace="http://example.org/person">
   <xsd:simpleType name="PersonAge">
      <xsd:restriction base="xsd:byte">
         <xsd:minInclusive value="0"/>
         <xsd:maxInclusive value="100"/>
      </xsd:restriction>
   </xsd:simpleType>

   <xsd:simpleType name="Phone">
      <xsd:restriction base="xsd:string">
         <xsd:pattern value="\d{3}-\d{3}-\d{4}"/>
      </xsd:restriction>
   </xsd:simpleType>

   <xsd:complexType name="Person">
      <xsd:sequence>
         <xsd:element name="name" type="xsd:string"/>
         <xsd:element name="age" type="xsd:byte " minOccurs="0"/>
         <xsd:element name="phone" type="xsd:string"
                      minOccurs="1" maxOccurs="5"/>
      </xsd:sequence>
      <xsd:attribute name="id" type="xsd:string "/>
   </xsd:complexType>

  <xsd:complexType name="RestrictedPerson">
      <xsd:complexContent>
         <xsd:restriction base="tns:Person">
            <!-- redefine base particles here -->
            <xsd:sequence>
               <xsd:element name="name" type="xsd:string"/>
               <xsd:element name="age" type="tns:PersonAge" 
                            minOccurs="1"/>
               <xsd:element name="phone" type="tns:Phone"
                            minOccurs="1" maxOccurs="1"/>
            </xsd:sequence>
           <xsd:attribute name="id" use="prohibited" />
         </xsd:restriction>
      </xsd:complexContent>
   </xsd:complexType>

   <xsd:element name="person" type="tns:Person"/>
   <xsd:element name="resPerson" type="tns:RestrictedPerson"/>
...
</xsd:schema>

이 예에서 우리는 새롭게 정의한 simple 유형(tns:PersonAge와 tns:Phone)을 사용하여 age와 phone 요소의 값공간을 제한하였다. 아울러 age 요소에 대해 횟수제한을 강화하였다. (이제 필수요소가 됨) phone 요소는 이제 정확하게 한번만 출현해야 하고, id 속성의 경우 선택적이 아니라 금지되었다. 아래의 문서는 tns:RestrictedPerson의 유효한 인스턴스를 담고 있다.

<tns:resPerson xmlns:tns="http://example.org/person">
   <name>Bob Smith</name>
   <age>33</age>
   <phone>333-333-4444</phone>
</tns:resPerson>

이 새로운 유형의 모든 측면은 기본 유형을 제한한 것이므로, tns:RestrictedPerson의 유효한 인스턴스는 tns:Person의 유효한 인스턴스이기도 하다. 그러나 그 반대는 참이 아니다. tns:Person의 유효한 인스턴스라고 하여 반드시 tns:RestrictedPerson의 유효한 인스턴스는 아니다.

확장에 의한 Complex 유형 정의

제한에 의한 유도가 중요하고, XML 스키마의 핵심요소이기는 하지만, 대부분의 프로그래밍 언어에서는 지원되지 않는다. 따라서, 스키마 정의를 프로그램 유형으로 매핑할 때, 마지막 예제에 있는 대부분은 프로그램의 클래스로 자연스럽게 변환되지 않는다. 하지만 확장에 의한 유도는 대부분의 객체지형 프로그래밍 언어에서 상당히 널리 사용되며, XSD에서도 지원된다.

Complex 유형만이 확장에 의한 유도가 지원된다. (즉, 기존의 simple 유형을 확장하여 새로운 simple 유형을 만드는 것은 불가능하다.) 하지만, 기존의 simple 유형 또는 complex 유형을 확장하여 새로운 complex 유형을 유도할 수 있다. 어느 유형으로부터 유도하는지는 xsd:simpleContent 또는 xsd:complexContent 요소를 사용하여 지정하며, xsd:extension을 중첩사용하여, 확장에 의한 유도를 표시한다.

simple 유형으로부터 확장에 의한 유도를 할 때에는, 새로운 유형에 속성 만 추가할 수 있다. (요소를 추가하면 더이상 simple 유형이 아니다.) 다음의 예는 기존의 simple 유형인 tns:Phone 으로부터 속성을 추가하여 새로운 complex 유형인 tns:PhoneWithLabel을 정의하는 방법을 나타낸다.

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns:tns="http://example.org/person"
   targetNamespace="http://example.org/person">
...
   <xsd:simpleType name="Phone">
      <xsd:restriction base="xsd:string">
         <xsd:pattern value="\d{3}-\d{3}-\d{4}"/>
      </xsd:restriction>
   </xsd:simpleType>
   <xsd:complexType name="PhoneWithLabel">
      <xsd:simpleContent>
         <xsd:extension base="tns:Phone">
           <!-- add attributes here -->
           <xsd:attribute name="label" type="xsd:string" use="required" />
         </xsd:extension>
      </xsd:simpleContent>
   </xsd:complexType>
   <xsd:element name="phone" type="tns:PhoneWithLabel"/>
...
</xsd:schema>

xsd:simpleContent는 xsd:complexType의 자식으로서 나타난다. 이는 새로운 유형의 내용이 character 데이터만 있고 다른 child 요소가 없음을 표시한다. 이 경우, 유형에 속성을 추가만 했으며, 이로 인해 새로운 유형은 complex 유형이 되었다. (simple 유형은 어떠한 구조도 가질 수 없다. 속성조차). 아래는 tns:PhoneWithLabel 의 유효한 인스턴스이다.

<tns:phone xmlns:tns="http://example.org/person"
   label="mobile">333-333-4444</tns:phone>

이미 존재하는 complex 유형으로부터 확장하는 것도 동일한 방법으로 가능하다. 다만, xsd:complexContent를 사용하여, 새로운 유형의 내용에 character 데이터 외에도 다른 내용(예를 들어 추가적인 child 요소)이 존재함을 표시한다. 아래의 예는 tns:Person으로부터 새로운 complex 유형을 유도하는 방법을 나타낸다.

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns:tns="http://example.org/person"
   targetNamespace="http://example.org/person">
...
   <xsd:complexType name="Person">
      <xsd:sequence>
         <xsd:element name="name" type="xsd:string"/>
         <xsd:element name="age" type="xsd:byte "  minOccurs="0"/>
         <xsd:element name="phone" type="xsd:string"  minOccurs="1" maxOccurs="5"/>
      </xsd:sequence>
      <xsd:attribute name="id" type="xsd:string "/>
   </xsd:complexType>

   <xsd:element name="person" type="tns:Person"/>

   <xsd:complexType name="ExtendedPerson">
      <xsd:complexContent>
         <xsd:extension base="tns:Person">
            <xsd:sequence>
               <xsd:element name="sex" type="xsd:string"/>
               <xsd:element name="weight" type="xsd:double"/>
               <xsd:element name="height" type="xsd:double"/>
            </xsd:sequence>
         </xsd:extension>
      </xsd:complexContent>
   </xsd:complexType>
...
</xsd:schema>

확장에 의하여 유도할 때에는 base 유형에 어떠한 변화도 만들 수 없다. base 유형에 새로운 particle을 추가하는 것만 가능하다. base 유형을 변경시킬 수 없으므로, 제한에 의한 유도에서처럼 particle을 재정의 할 필요가 없다. 그 대신, 그냥 새로운 내용을 정의하면 base 유형의 내용의 뒤에 추가된다. 새로운 내용은 논리적으로 base 유형 내용의 뒤에 추가되어, 아래와 같이 마치 두개의 내용 모델이 하나의 xsd:sequence 요소 내에 둘러싸여진 것처럼 작동된다. 

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns:tns="http://example.org/person"
   targetNamespace="http://example.org/person">
...
   <!-- the logical content model of the derived type -->
   <xsd:complexType name="ExtendedPerson">
      <xsd:sequence>
         <!-- base type's content model -->
         <xsd:sequence>
            <xsd:element name="name" type="xsd:string"/>
            <xsd:element name="age" type="xsd:byte " minOccurs="0"/>
            <xsd:element name="phone" type="xsd:string" minOccurs="1" maxOccurs="5"/>
         </xsd:sequence>
         <!-- derived type's content model -->
         <xsd:sequence>
            <xsd:element name="sex" type="xsd:string"/>
            <xsd:element name="weight" type="xsd:double"/>
            <xsd:element name="height" type="xsd:double"/>
         </xsd:sequence>
         <xsd:attribute name="id" type="xsd:string "/>
      </xsd:sequence>
   </xsd:complexType>
...
</xsd:schema>

다음은 tns:ExtentedPerson의 유효한 인스턴스의 예이다.

<tns:extPerson xmlns:tns="http://example.org/person"  id="333-22-4444">
   <name>Bob Smith</name>
   <phone>801-444-5555</phone>
   <phone>801-555-6666</phone>
   <phone>801-666-7777</phone>   
   <sex>M</sex>
   <weight>175</weight>
   <height>72</height>
</tns:extPerson>

제한에 의한 유도와는 달리, 확장된 유형의 인스턴스는 base 유형의 유효한 인스턴스가 아닌 경우가 많다. 여기에서 보는 것처럼 tns:extPerson은 절대 tns:Person의 유효한 인스턴스가 아니다.

 There are a few restrictions to derivation by extension when it comes to xsd:all compositors. If a complex type uses xsd:all as its top-level compositor, you can't extend it by adding new particles—you can only add attributes in this case. Also, you can't extend another complex type with an xsd:all unless it has an empty content model. 확장에 의한 유도에서 xsd:all compositor를 사용할 때에는 몇가지 제한이 있다. complex 유형이 최상위 compositor로서 xsd:all을 사용하면, 새로운 particle을 추가하는 방식으로 확장할 수 없다. - 이 경우에는 속성 추가만 가능하다. 또한, xsd:all이 있는 complex 유형은 내용모델이 비어있지(empty) 않는한 확장할 수 없다.

유도 방지(Blocking Derivation)

'봉인(sealed)' 클래스 정의와 비슷하게, 특정한 유형으로부터 새로운 유도를 방지하고자 할 경우가 있다. XSD에서는 xsd:complexType에 final 속성을 통하여 가능하다. (참고로, substitution 구릅을 사용할 때 요소선언에서 final 속성을 사용할 수도 있다.) final을 사용하면, 특정유형으로부터 유도 메커니즘이 금지된다. final 속성의 값은, extension, restriction, #all 등 세가지이다. 예를 들어, 다음의 complex 유형 정의는 tns:Person 기본유형으로부터 제한에 의한 유도 및 확장에 의한 유도 모두를 금지한다.

...
   <xsd:complexType name="Person" final="#all">
      ... <!-- omitted for brevity -->
   </xsd:complexType>
...

아래의 예와 같이 xsd:schema에 finalDefault 속성을 사용하면, 스키마 전체에서 final 속성을 기본값으로 지정할 수 있다.

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns:tns="http://example.org/person"
   targetNamespace="http://example.org/person"
   finalDefault="restriction">
...


이렇게 하면 기본값으로, complex 유형간에서 제한에 의한 유도가 허용되지 않는다. 위에서 보인 final 속성을 사용하여 이 설정을 덮어씌워야만 변경이 가능하다.

추상 유형(Abstract Types)

대부분의 객체지향 언어에서는 추상 유형을 정의할 수 있다. 이 문맥에서 추상유형이란 인스턴스화 할 수 없는 것을 말한다. 추상 base 클래스와 추상 base 인터페이스가 이러한 유형의 예이다. One purpose of abstract types is to define a contract that other derived types will implement. 추상유형의 목적은 다른 유도 유형이 수행된다는 계약을 정의하는 것이다. This makes it possible to build applications around abstract interfaces, supporting numerous possible implementations. The assumption is that some derived type will be substituted for the abstract type at runtime. 

아울러 XSD는 추상 complex 유형을 정의할 수 있다. 아래와 같이 xsd:complexType 요소에 abstract 속성(boolean)을 사용하면 된다.

...
   <xsd:complexType name="Person" abstract="true">
      ... <!-- omitted for brevity -->
   </xsd:complexType>
...

이 속성의 기본값은 false로서, complex 유형은 구체적이라는 것이다. 추상 스키마 유형은 XML 인스턴스 문서에서 유형으로 나타날 수 없다는 것을 의미한다. 그대신 추상유형이 있어야 할 곳에 반드시 유도된 유형이 대체되어 나타나야 한다.

xsi:type을 사용한 대체(substitution)

유형계층을 정의하면 좋은 장점은 유도된 유형의 인스턴스를 대체할 수 있는 능력이다. 객체지향 기술에서 폴리모피즘과 같이, base 유형이 와야할 곳에 유도 유형을 대체할 수 있다. XML 문서에서 이를 실행할 수 있는 방법중 하나가 xsi:type을 사용하는 방법이다.

xsi:type을 사용하면 요소의 유형을 명시적으로 지정할 수 있다. 이렇게 함으로써 스키마에서 요소선언이 없을 경우에 조차, 어떤 요소가 특정 유형이라고 주장하는 것이 가능해진다. 이 속성은 유도된 유형의 인스턴스를 기반유형이 와야 할 곳에 사용할 때 가장 널리 사용된다. 이 경우, 스키마 프로세스는 xsi:type 속성에서 지정한 유형이 기대된 기반유형으로부터 유도되는 것을 보증한다. 예를 들어, 아래의 tns:Family라는 complex 유형 정의를 고려해 보자. 이 유형은 tns:Person 유형의 여러개의 person 요소 목록을 포함하고 있다. 

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns:tns="http://example.org/person"
   targetNamespace="http://example.org/person">
...
   <xsd:complexType name="Family">
      <xsd:sequence>
         <xsd:element name="person" type="tns:Person"
                      maxOccurs="unbounded"/>
      </xsd:sequence>
   </xsd:complexType>
   <xsd:element name="family" type="tns:Family"/>
...
</xsd:schema>

아래의 문서는 tns:Family의 유효한 인스턴스를 담고 있다. 주목할 점은 tns:RestrictedPerson 과 tns:ExtendedPerson 의 인스턴스가 tns:Person의 인스턴스가 와야할 곳에 대체되었다는 점이다.

<tns:family xmlns:tns="http://example.org/person"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema">
   <person id="333-22-4444">
      <name>Bob Smith</name>
      <phone>801-444-5555</phone>
      <phone>801-444-6666</phone>
   </person>
   <person xsi:type="tns:RestrictedPerson">
      <name>Mary Smith</name>
      <age>33</age>
      <phone>333-333-4444</phone>
   </person>
   <person xsi:type="tns:ExtendedPerson" id="333-22-5555">
      <name>Jenny Smith</name>
      <phone>801-444-5555</phone>
      <phone>801-444-6666</phone>
      <sex>F</sex>
      <weight>105</weight>
      <height>65</height>
   </person>
</tns:family>

이상과 같이 이런 대체 스타일은 유형이름에 기반하며, 요소 이름에 기반하는 것이 아니다. 즉, 유형을 결정할 때 요소 이름만 봐서는 안된다는 것이다. 하지만 XSD에는 요소 이름에만 완전히 기반하는 대체유형도 존재한다.

대체 그룹(Substitution Groups)

대체그룹은 요소기반의 대체를 허용한다. 대체그룹을 형성하려면, 전역적 요소선언이 그룹의 'head'로서 작용한다. (어떤 전역 요소이든 특별한 무언가가 필요없이 'head'로서 작동한다.) 그래서 다른 전역요소 선언은 substitutionGroup 속성을 사용하고 아래와 같이 head 요소의 이름을 지정함으로써, 대체 그룹에 참여할 수 있다. 

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns:tns="http://example.org/person"
   targetNamespace="http://example.org/person">
...
   <xsd:element name="person" type="tns:Person"/>
   <xsd:element name="resPerson" type="tns:RestrictedPerson"
                substitutionGroup="tns:person" />
   <xsd:element name="extPerson" type="tns:ExtendedPerson"
                substitutionGroup="tns:person" />
...
</xsd:schema>

대체그룹의 멤버는 반드시 head 요소의 유형에 관련되어야 한다. 즉, 멤버요소는 head 요소와 동일한 유형일 수도 있고, 제한/확장 유형일 수도 있다. 이 법칙은 대체된 요소가 head 요소의 위치에 사용될 때 의미가 있다는 것을 보장한다.

For example, with the above substitution group in place, we can change the complex type definition for tns:Family to reference the global tns:person element: 예를 들어, 위의 대체그룹에서 우리는 tns:Family에 대한 complex 유형 정의를 전역적 tns:person 요소를 참조하도록 변경시킬 수 있다.?

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns:tns="http://example.org/person"
   targetNamespace="http://example.org/person">
...
   <xsd:complexType name="Family">
      <xsd:sequence>
         <xsd:element ref="tns:person" maxOccurs="unbounded"/>
      </xsd:sequence>
   </xsd:complexType>
   <xsd:element name="family" type="tns:Family"/>
...
</xsd:schema>

그러면 다음과 같이 이 위치에 tns:person 대체그룹의 어떤 멤버도 대체할 수 있다.

<tns:family xmlns:tns="http://example.org/person">
   <tns:person id="333-22-4444">
      <name>Bob Smith</name>
      <phone>801-444-5555</phone>
      <phone>801-444-6666</phone>
   </tns:person>
   <tns:resPerson>
      <name>Mary Smith</name>
      <age>33</age>
      <phone>333-333-4444</phone>
   </tns:resPerson>
   <tns:extPerson id="333-22-5555">
      <name>Jenny Smith</name>
      <phone>801-444-5555</phone>
      <phone>801-444-6666</phone>
      <sex>F</sex>
      <weight>105</weight>
      <height>65</height>
   </tns:extPerson>
</tns:family>

주목할 점은 tns:person, tns:resPerson, tns:extPerson은 모두 전역 요소로서 스키마의 target 네임스페이스에 의해 정규화(qualified)되어야 한다는 점이다. 아울러, 요소기반의 대체를 사용하기 때문에, 더이상 유형정보를 지정하기 위해 xsi:type 을 사용할 필요가 없다는 점도 주목해야 한다. 이제 요소의 유형은 이름만으로부터 끌어낼 수 있다.

대체 방지(Blocking Substitution)

유도와 마찬가지로, 특정 유형에서 대체가 사용되는 것을 막고 싶거나 대체그룹에서 요소가 사용되는 것을 막고 싶을 경우가 있을 수 있다. xsd:complexType 또는 xsd:element에 block 속성을 사용하면 특정 유형/요소에 대한 대체를 막을 수 있다. The block attribute allows you to specify what derived types/elements may be used in place of the type/element at hand. block 속성을 사용하면, 유도된 유형/요소가 직접적으로 그 유형/요소에 사용될 것인지 지정할 수 있다. block 속성에 허용되는 값은 extension, restriction, substitution, #all 등이다. 예를 들어 아래의 complex 유형 정의는 확장된 유형을 tns:Person이 필요한 자리에 대체될 수 없도록 방지한다.

...
   <xsd:complexType name="Person" block="extension">
      ... <!-- omitted for brevity -->
   </xsd:complexType>
...

또한 xsd:schema 요소에 blockDefault 속성을 사용함으로써, block 속성에 대한 기본값을 지정할 수 있다. 아래의 예는 이 스키마에서 기본값으로 모든 종류의 대체가 금지된다. (특별한 complex 유형이 block 속성을 사용하여 이 설정을 바꾸지 않는한)

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns:tns="http://example.org/person"
   targetNamespace="http://example.org/person"
   blockDefault="#all">
...

xsd:complexType과 마찬가지로, xsd:element의 abstract 속성과 final 속성을 사용하여, 대체그룹에서 요소가 어떻게 사용될지를 제어하는 것도 가능하다.

재사용(Reuse)

스키마 라이브러리를 설계할 때, 아마도 다양한 스키마에서 공유되어야 할 필요가 있는 글로벌 유형이 있을 것이다. 이러한 경우, 이러한 유형을 별도의 스키마 파일에 정의를 한 후, 다른 스키마 파일에 include 혹은 import 시키고 싶을 수 있다. 여러개의 스키마 파일로 부터 스키마를 만드는 것은 매우 흔한 일이다.

XSD에서는 xsd:include와 xsd:import 요소를 통해 이러한 재사용이 가능하다. xsd:include는 별도의 파일에 있는 스키마를 포함시킬 수 있다. 이 경우, 두개의 스키마 파일의 target 네임스페이스가 동일해야 한다. 하지만, target 네임스페이스가 없는 스키마 파일을 include 시키는 것도 가능하다. 이 경우, 포함된 construct들은 새로운 target 네임스페이스의 일부가 된다. 아래는 xsd:include의 작동방법 예시이다.

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns:tns="http://example.org/person"
   targetNamespace="http://example.org/person"
>
   <xsd:include schemaLocation="globals.xsd"/>
   ...

xsd:include가 어떤 경우에는 편리할 수 있지만, 실재로는 xsd:import가 더 널리 사용된다. xsd:import는 다른 네임스페이스에서 새로운 스키마로 유형을 'import'시킬 수 있다. 이경우, import된 유형은 여전히 원래의 네임스페이스에 존재하지만, 새로운 네임스페이스에서 새로운 유형을 구축하는데 사용될 수 있다. 예를 들어, 다음의 스키마 정의에는 tns:Person 유형이 포함되어 있다.

<!-- personBase.xsd -->
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns:tns="http://example.org/person"
   targetNamespace="http://example.org/person">


   <xsd:complexType name="Person">
      <xsd:sequence>
         <xsd:element name="name" type="xsd:string"/>
         <xsd:element name="age" type="xsd:byte " 
                      minOccurs="0"/>
         <xsd:element name="phone" type="xsd:string"
                      minOccurs="1" maxOccurs="5"/>
      </xsd:sequence>
      <xsd:attribute name="id" type="xsd:string "/>
   </xsd:complexType>
</xsd:schema>

우리는 이 스키마를 새로운 스키마로 import하며, 이 유형을 기본유형으로 하여 새로운 complex 유형을 정의하는데 사용할 수 있다.

<!-- person.xsd -->
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns:basetns="http://example.org/person"
   xmlns:tns="http://example.org/person/derived"
   targetNamespace="http://example.org/person/derived">

   <xsd:import namespace="http://example.org/person"
               schemaLocation="personBase.xsd"/>

   <xsd:complexType name="ExtendedPerson">
      <xsd:complexContent>
         <xsd:extension base="basetns:Person">
            <xsd:sequence>
               <xsd:element name="sex" type="xsd:string"/>
               <xsd:element name="weight" type="xsd:double"/>
               <xsd:element name="height" type="xsd:double"/>
            </xsd:sequence>
         </xsd:extension>
      </xsd:complexContent>
   </xsd:complexType>
</xsd:schema>

다른 네임스페이스에 있는 유형을 import 할 때에는 제한에 의한 유도(derivation by restriction)을 주의깊게 사용해야 한다. import된 Complex 유형에 정규화된(qualified) 지역요소가 있고(즉, elementFormDefault="qualified"), 새로이 제한된 complex 유형을 정의할 경우, 지역요소의 네임스페이스를 바꾸게 됨으로써, 제한이 invalid하게 된다. import 된 유형의 지역 요소가 비정규화 요소일 경우, 새롭게 제한된 유형이 네임스페이스를 변경하지 않으므로, 이런 일이 발생하지 않는다.

결론

As you can see, XSD is a powerful and flexible language capable of representing many of the type hierarchies commonly used in today's object-oriented systems. Even better, XSD makes it possible for applications to take advantage of type relationships through XML substitution techniques. This makes it possible to model not only the type hierarchies themselves, but also how they're used in practice. 이상과 같이 XSD는 현재 객체지향시스템에서 널리 사용되는 유형 계층의 상당 부분을 표현할 수 있는 강력하고도 유연한 언어이다. 아울러, XSD를 사용하면 응용에서 XML 대체기법을 통해 유형 관계를 이용할 수 있다. 따라서, 유형 계층화 그자체 뿐만아니라, 실재로 어떻게 사용되는지를 모델링할 수 있다.

XSD의 포함 메카니즘(즉, include 와 import)를 사용하면 핵심 라이브러리를 재사용하고 장기간 유지관리가 쉽게 된다. XSD가 완벽한 건 아니지만, 현재 사용되는 다양한 프로그래밍 언어 고유의 유형을 모델링할수 있는 스키마 라이브러리를 설계하기 위한 확고한 기반을 제공한다. XML 스키마에 관한 좀 더 많은 정보는 Essential XML Quick Reference 등 아래에 있는 기타 문헌을 참고하라.

참고문헌

XML Schema Part 0: Primer 

XML Schema Part 1: Structures 

XML Schema Part 2: Datatypes 

Essential XML Quick Reference

===

원문 : https://msdn.microsoft.com/en-us/library/aa468549.aspx

Posted by 푸른하늘이

댓글을 달아 주세요

공간정보/표준2018. 3. 19. 17:15

Aaron Skonnard
DevelopMentor 

2002년 7월 갱신

아론 스코나드의 "XML 네임스페이스의 이해(Understanding XML Namespaces)" 는 2001년 7월 MSDN 매거진에 최초 게재되었다. 여기에서는 저자의 허락을 받아 갱신된 버전을 싣는다.

Copyright © 2001 Microsoft Corp. and CMP Media LLC.

네임스페이스(Namespace)는 XML에서 많은 혼란을 야기한다. 특히 이 기술에 대해 처음 접한 사람들은 많이 어려워 한다. 독자나 학생, 컨퍼런스 참석자가 요청한 질문의 대부분은 어떤 방식으로든 네임스페이스와 관련이 있다. 사실 아이러니한 상황이다. XML 권고사항에서의 네임스페이스(Namespaces in XML Recommendation)는 짧은 XML 사양중의 하나로, 부속서를 제외하면 10쪽 이하이기 때문이다. 하지만, 혼란은 사양에 의해 서술된 문법이 아니라, 네임스페이스 의미론에 관계있다. XML 네임스페이스를 완전하게 이해하려면, 네임스페이스가 무엇이고, 어떻게 정의하며, 어떻게 사용하는지를 알아야 한다.

이 글은 이러한 세가지 질문에 대하여, 구문적으로, 추상적으로 답을 한다. 이 글을 마칠 때쯤이면, 네임스페이스가 XML 관련 기술들에게 어떻게 영향을 미치는지 이해하게 될 것이다.

네임스페이스란 무엇인가?

네임스페이스란 모든 이름이 유일한 이름들의 집합이다. 예를들어 우리집 아이들의 이름들, C++의 타입 식별자의 이름 또는 인터넷 도메인명 등은 네임스페이스라고 볼 수 있다. 각각의 이름이 유일해야 하고, 논리적으로 관련있는 모든 집합은 네임스페이스이다.

네임스페이스는 유일한 이름이 필요한 상황을 쉽게 해결할 수 있다. 우리집 아이들의 이름들을 지구상에서 유일하게 해야 한다면 얼마나 어려울지 상상해 보라. 우리집으로 그 범위를 한정하는 등, 유일성의 의미를 제한된 상황으로 한정하면 일이 엄청나게 간단해진다. 다음번에 태어난 아이의 이름을 지을 때 고려해야 할 것은 내가 이미 사용한 이름들만 사용하면 되지 않기 때문이다. 다른 부모들은 내가 사용한 이름과 동일한 이름을 선택할 수 있겠지만, 그러한 이름들은 별도의 네임스페이스에 속하기 때문에 쉽게 구분될 수 있다.

새로운 이름을 어떤 네임스페이스에 추가하기 전에, 네임스페이스 관리자는 반드시 새로운 이름이 해당 네임스페이스에 이미 존재하지 않는다는 것을 보장해야 한다. 경우에 따라서는 이는 아이들 이름 짓기처럼 간단할 수 있다. 반면 매우 복잡한 경우도 있다. 오늘날 인터넷 주소 관리기관이 많이 있다는 것이 좋은 예이다. 하지만, 이러한 단계를 생략하면 중복된 이름으로 인해 결국 네임스페이스를 망가뜨리게 되고, 모호함없이 이름을 참조하는 것이 불가능하게 된다. 이러한 일이 발생하면 이러한 이름 집합은 공식적으로 네임스페이스로 인정받지 못한다. - 정의에 의해 네임스페이스는 반드시 소속원에 대한 유일성을 보장해야 하기 때문이다.

네임스페이스 그 자신도 이름이 있어야만 유용하다. 네임스페이스가 이름을 가지면, 그 소속원을 참조할 수 있게 된다. 예를 들어 그림1에 있는 두 개의 박스로 표현한 네임스페이스의 예를 생각해보자. 이 예제 네임스페이스의 이름은 각각 Microsoft와 AcmeHardware 이다. 이들 네임스페이스에 동일한 로컬명이 포함되어 있지만, 네임스페이스 적격 이름(namespace-qualified name)을 통해 이들을 명확하게 참조할 수 있다.


<그림 1> 애매함이 없는 네임스페이스

물론 이것은 네임스페이스 이름도 유일하다는 것을 가정한다. 이것이 보장되지 못한다면, 실제의 네임스페이스 이름 그 자체도 그들 자체의 네임스페이스에 넣을 수 있다. 예를 들어 AcmeHardware 판매점이 여럿 있다면 (캘리포니아에 하나, 유타에 하나 등), AcmeHardware 이름을 별도의 네임스페이스에 넣음으로써 충돌을 해결할 수 있다. 아래가 그 예이다.

California.AcmeHardware.Paint
Utah.AcmeHardware.Paint

이 형태는 필요에 따라 네임스페이스 이름의 유일성을 보장할 수 있을 때까지 계속할 수 있다. 이것이 인터넷 네임 시스템(DNS)가 작동하는 방식이다. - DNS는 그냥 네임스페이스에 대한 큰 하나의 네임스페이스이다.

이러한 유형의 네임스페이스 분할이 없었다면, 아래와 같이 유일성을 담보하기 위해 (일반적이지 않은) 매우 긴 이름을 사용해야 했을 것이다.

MicrosoftWindowsOperatingSystemPaintApplication

분리할 수 없는 단 하나의 전세계적 네임스페이스만 존재한다고 할 때의 복잡성과 그로 인한 혼란을 상상해보라. 사람들은 매일 매일의 사회적 상호관계에서 네임스페이스에 깊게 의존한다. 대부분의 경우 명시적으로 네임스페이스인지도 모른다. 그러나 소프트웨어 개발에서 네임스페이스를 사용하기 위해서는 정확한 문법에 따라 네임스페이스를 명시적으로 만들어야 한다. XML에서의 네임스페이스에 대해 논하기 전에, 먼저 오늘날 널리 사용되고 있는 프로그래밍 언어에서의 네임스페이스 문법의 예를 살펴보자.

프로그래밍 언어에서의 네임스페이스

프로그램언어에서 네임스페이스를 사용하기 위해서는 네임스페이스를 정의하는 문법과, 네임스페이스에 속한 무언가를 참조하는 문법에 익숙해져야 한다. C++, Java, C#을 포함하여 오늘날의 많은 언어들이 네임스페이스를 지원한다. C++에서는 아래의 예와 같이 네임스페이스는 네임스페이스 블록(namespace block)을 통해 정의된다.

namespace foo1
{
    class bar
    {   ....    };
    class baz
    {   ....    };
}

namespace foo2
{
    class bar
    {   ....    };
    class baz
    {   ....    };
}

이 예제에서는 두개의 네임스페이스, foo1 및 foo2를 정의한다. 각각은 두개의 이름, bar 및 baz를 정의한다. (이 경우 이들 이름은 클래스 식별자이다)

foo1::bar b1;        // foo1에 있는 클래스 bar를 참조함
foo2::bar b1;        // foo2에 있는 클래스 bar를 참조함

특정한 네임스페이스에 속한 클래스 bar를 참조하려면, 식별자 bar에 주어진 네임스페이스 식별자로 적격(qualified)해야 한다. 

아울러 주어진 소스 파일에서 특정한 네임스페이스를 사용한다고 선언할 수 있다. 이는 기본적으로 어떤 네임스페이스를 해당 소스파일의 기본 네임스페이스로 만드는 것이다. 그러면 특별한 네임스페이스 소속원에 대해 완전히 자격을 부여할 필요가 없다. 물론 모호성을 피하기 위해 절대적으로 필요한 경우는 예외이다.

using namespace foo1;
bar b1;        // foo1 네임스페이스에 속한 클래스 bar를 참조함

보는 바와 같이 C++에서 네임스페이스를 정의하고 사용하는 문법은 간단하고 직관적이다. C#의 경우 약간의 차이는 있지만 거의 비슷한 방식으로 동작한다. Java에서의 네임스페이스 문법은 상당히 다르지만, 그 개념은 동일하다.

많은 프로그램 언어에서 네임스페이스는 이름 충돌을 방지하기 위하여 사용된다. 이것과 동일한 유형의 해법이 XML 1.0 사양을 완성하기 위하여 필요하다. 

XML에서의 네임스페이스

많은 개발자들은 XML 1.0 사양이 네임스페이스를 지원하지 않아 불완전하다고 느끼고 있다. 그 결과 XML 문서에 있는 모든 이름이 하나의 글로벌 네임스페이스에 속하게 되어 유일한 이름을 마주하기 매우 힘들게 되었다.

XML 1.0 저작자를 포함한 많은 개발자들은 이것이 결과적으로 대형 XML 기반 배포 시스템에서 너무나 많은 모호성을 초해할 것이라는 것을 알았다. 예를 들어, 다음과 같은 XML 문서를 고려해 보자.

<student>
  <id>3235329</id>
  <name>Jeff Smith</name>
  <language>C#</language>
  <rating>9.5</rating>
</student>

이 문서는 여러가지 이름을 사용하고 있으며, 대부분은 평범한 이름들이다. student 요소는 소프트웨어 교육코스의 수강생을 모델링하고 있다. id, language, rating 요소들은 수강생들의 데이터베이스 레코드번호, 선호하는 프로그래밍 언어, 수강생의 해당 코스 성적(10점 만점) 등을 나타낸다. 이러한 이름들은 틀림없이 동일한 의미를 갖지 않는 다른 상황에서도 사용될 수 있을 것이다. 

예를 들어, 아래는 동일한 이름을 완전히 다른 방법으로 사용하는 XML 문서의 예이다.

<student>
  <id>534-22-5252</id>
  <name>Jill Smith</name>
  <language>Spanish</language>
  <rating>3.2</rating>
</student>

이 경우 student 요소는 초등학교 학생을 모델링한다. 여기에서 id는 학생의 사회보장번호, language는 모국어, rating은 현재의 평균 학점(만점 4)를 각각 나타낸다. 이들 두 문서의 제작자들은 유일성을 확보하는데 도움이 되도록 좀 더 길고 평범하지 않은 이름을 사용할 수도 있지만, 결국 유일성을 확실하게 보장할 수 없으며, 사용하기 힘들게 된다.

비록 사람들은 이 두 문서를 들여다 보고 차이를 구분할 수 있을지도 모르지만, 소프트웨어에게는 완전히 동일하게 보일 것이다. 당신이 학생 관리 응용프로그램을 구축을 맡게 되었고, 많은 학생 관련 XML 문서를 지원해야 한다고 가정해 보자. 코드를 짜면서 어떻게 (프로그램적으로) 전문적 수강생과 초등학교 학생, 혹은 또다른 종류의 학생을 구분할 수 있을 것인가? 신뢰성있게 구분할 수 있는 방법은 존재하지 않는다. 

별도의 XML 어휘집(vocabulary)에 속한 요소와 속성들이 동일한 문서나 응용에서 사용될 때에는 반드시 이름 충돌이 발생한다. XSLT를 생각해보자. XSLT는 그 자체로 변환을 정의하기 위한 XML 어휘집이다. 주어진 변환에서 사용자정의 문자열(literal)을 출력할 수 있다. 따라서, XSLT 어휘집에는 template라는 요소가 포함되어 있는데, 사용자 정의 literal 요소가 template라는 이름을 가졌다면 어떻게 출력할 수 있을 것인가? 

<!-- this is the template element from XSLT -->
<template match="foo">
  <!-- I want to output this template element -->
  <template match="foo"/>
</template>

XSLT와 XML Schema 와 같이 XML 어휘집을 많이 섞어 사용하는 언어에서는 이름 충돌의 가능성은 명백하다. 하지만, 이러한 문제점들은 XML이 네임스페이스를 지원하게 되면서 쉽게 해결될 수 있었다.

XML 권고사항(Recommendation)에서 네임스페이스는 XML 1.0 이름에 관한 문제에 대한 W3C의 해결책이다. 이 사양에서는 네임스페이스를 지원하기 위하여 XML 1.0의 견고한 문법을 확장하는 방법을 정의하고 있다. 대부분의 개발자들은 이 추가사항이 근본적이고 절대적으로 필요하다고 생각하기 때문에 공식 XML 1.0 부속서로서 생각하고 있다. (사실은 아니다) 사실 오늘날의 많은 개발자들은 동일한 이유때문에 XML 1.0 만을 참조하기를 거부하고, "XML 1.0 + Namespaces"를 참조하고 있다.

XML 권고사항중 네임스페이스는 XML 네임스페이스를 명명하기 위한 문법과, XML 네임스페이스에 속한 무언가를 참조하기 위한 문법을 정의한다. 하지만, XML 네임스페이스에 무엇이 있는지에 대해 정의하는 문법은 언급하지 않는다. 이것은 다른 사양, 즉 XML Schema에 남겨져 있다. 이들 분야의 각각에 대해 약간의 설명이 필요하다.

네임스페이스 명명 (Naming Namespaces)

C++과 같은 프로그램언어에서 네임스페이스를 정의할 때는, 이름에 사용할 수 있는 문자에 제한이 있다. XML 네임스페이스 식별자도 특정한 문법을 준수해야 한다. 바로 Uniform Resource Identifier(URI) 참조를 위한 문법이다. 이는 XML 네임스페이스 식별자가 반드시 RFC2396에서 정의한 URI에 대한 일반 문법을 따라야 함을 의미한다.

URI는 추상적 또는 물리적 자원을 식별하기 위해, 압축적인 문자열로 정의된다. 대부분의 경우, URI 참조는 물리적 자원(웹페이지, 다운로드용 파일 등)을 식별하는데 사용하지만, XML 네임스페이스의 경우, URI 참조는 추상적인 자원, 특별히 네임스페이스를 구별하기 위한 용도이다.

URI 사양에 따르면, URI에는 URL(Uniform Resource Locators)와 URN(Uniform Resource Names) 등 두가지 일반적 형태가 있다. 네임스페이스 식별자로 두가지중 어떤 것을 사용해도 무방하다. 아래는 네임스페이스 식별자로 사용될 수 있는 URL의 예이다.

http://www.develop.com/student
http://www.ed.gov/elementary/students

아래는 네임스페이스 식별자로 사용할 수 있는 URN의 예이다.

urn:www-develop-com:student
urn:www.ed.gov:elementary.students
urn:uuid:E7F73B13-05FE-44ec-81CE-F898C4A6CDB4

네임스페이스 식별자의 가장 중요한 속성은 유일하다는 것이다. 저작자들은 인터넷 명명 관리기관에 도메인 명을 등록함으로써 URL의 유일성을 보장할 수 있다. 그러면 도메인 명 뒤쪽에 사용되는 모든 문자열의 유일성을 확보하는 것은 저작자의 책임이다.

URN도 동일한 방식으로 작동된다. 아래는 기본적인 URN 문법 이다.

urn:<namespace identifier>:<namespace specific string>

URN의 유일성을 보장하기 위해서는 저작자들은 반드시 자신들의 네임스페이스 식별자를 인터넷 명명 관리기관에 등록해야 한다. 그다음 저작자들은 유일한 네임스페이스 고유의 문자열을 생성하기 위한 체계를 따라야 할 책임이 있다. 

XML 네임스페이스를 정의하는 기관은 반드시 새로운 네임스페이스 명을 생성하는 일관된 체계를 개발해야 한다. 예를 들어 W3C에서는 계속 새로운 XML 네임스페이스를 정의하고 있다. 그들은 현재의 년도와 워킹그룹의 이름을 사용하는, 상당히 직관적이고 경험적인 문제 해결법을 사용한다. 그림2는 W3C에서 사용하고 있는 행태를 나타낸다.


<그림 2> W3C URI 구조

정의에 의해 URI 는 유일하므로, XML 네임스페이스 식별자위에 추가적인 네임스페이스를 올릴 필요는 없다. 네임스페이스 저작자가 네임스페이스 식별자의 유일성을 보장하는 한, 하나의 네임스페이스 자격자(qualifier)만을 사용하여 XML에 포함된 무언가를 유일하게 식별하는 것은 항상 가능하다. 이를 통해 XML에서 네임스페이스와 관련된 작업이 대단히 간단해진다.

XML 프로세서는 네임스페이스 식별자를 불투명한 문자열로 취급하며, 분해할 수 있는 자원으로 취급하지 않는다. 다시 반복하자면, 네임스페이스 식별자는 그냥 문자열일 뿐이다! 두개의 네임스페이스 식별자가 동일하다고 간주되는 것은 이들을 구성하는 모든 문자가 정확하게 똑같을 때 뿐이다. 

결국, 어떤 형태의 URI 참조를 사용할지는 전혀 문제가 안된다. 많은 개발자들이 URL를 선호하는 것은 읽고 기억하기 쉽다는 것이며, URN을 좋아하는 사람들은 유연성이 높다는 것 때문이다. 어떤 쪽을 선택하던, 반드시 알아야 할 것은 유일성을 보장하는 방법이다.

네임스페이스 정의

XML 권고사항의 네임스페이스는 네임스페이스 속에 무엇이 있는지 정의하는 문법은 제공하지 않는다. 대부분의 경우, 이러한 유형의 문법적 정의는 별로 필요하지도 않다. 오늘날 대부분의 XML 네임스페이스는 형식적 사양 문서에서 정의된다. 이 사양문서는 요소(element), 속성의 이름과 구문을 기술한다. 이것이 모든 W3C 네임스페이스가 공식적으로 정의된 방법이다. (예를 들어 http://www.w3.org/TR/xslt에서 XSLT 1.0 사양을 보라.)

네임스페이스가 일단 정의되면, 소프트웨어 개발자들은 그 네임스페이스를 사양에서 기술한 것처럼 구현한다. 예를 들어 MSXML 3.0, Xalan, Saxon은 모두 XSLT 1.0 사양의 구현이다. 이들 구현들은 XSLT 1.0 네임스페이스 (http://www.w3.org/1999/XSL/Transform)에 속한 요소를 찾기 위해 하드코딩되어 있다. 이러한 구현을 사용하려면, XSLT 1.0 네임스페이스로부터 이름들을 올바르게 사용하는 XML 문서를 제공할 필요가 있다. (자세한 내용은 다음 절에서 다룸) XSLT 1.0 네임스페이스에서 어떤 변화가 발생한다면, 지원하는 소프트웨어는 갱신되어야 한다.

XML Schema 워킹 그룹 (http://www.w3.org/XML/Schema)에서는 새로운 사양(XML Schema)을 하나로 합쳤다. 여기에서는 요소(element), 속성(attribute) 및 유형(type)를 하나의 네임스페이스에 정의하기 위한 XML 기반의 문법을 정의한다. XML Schema는 아래에서 보는 것처럼 드디어 네임스페이스에 대한 구문적 정의를 제공할 수 있게 된 것이다.

<schema xmlns='http://www.w3.org/2000/10/XMLSchema'
   targetNamespace='http://www.develop.com/student'
   elementFormDefault='qualified' >
  <element name='student'>
     <complexType>
         <sequence>
            <element name='id' type='long'/>
            <element name='name' type='string'/>
            <element name='language' type='string'/>
            <element name='rating' type='double'/>         
         </sequence>
     </complexType>
   </element>
</schema>

이 예제에서는 네임스페이스 http://www.develop.com/student 를 student, id, name, language, rating 4가지 요소를 포함하는 것으로 정의한다. 네임스페이스를 제공하는 것 뿐만 아니라, 이 스키마는 student의 child 요소의 순서, 유형 등 추가적인 메타데이터도 제공한다. 

XML Schema에서 제공되는 것과 같은 구문적 네임스페이스 정의를 사용하면, 실행시킬 때 이름과 유형 정보를 활용하는 좀 더 복합한 소프트웨어도 제작할 수 있게 된다. XML 스키마는 아직 정의된 요소와 속성의 의미론을 정의하지 않으며, 따라서 추가적인 사양이 필요할 것이다. 미래에는 대부분의 XML 네임스페이스가 사양과 스키마 정의 등 두 가지를 통해 정의될 것이다.

네임스페이스 사용법

나는 XML 문서에 있는 주어진 네임스페이스로부터 하나 이상의 요소 또는 속성을 사용하는 절차로서 네임스페이스를 사용하여 정의한다. 이렇게 하려면 XML 권고사항에서의 네임스페이스에서 정의된 구문을 이해해야 한다. 네임스페이스 식별자가 있는 요소이름 및 속성이름의 자격부여(qualifying)을 위해서이다.

요소명과 속성명은 실제로 두가지 부분으로 구성된다. 네임스페이스명과 로컬명이다. 이 두 부분 이름을 적격한 이름(qualified name), 또는 QName이라고 한다.

XML 문서에서 우리는 요소 및 속성의 로컬명에 자격부여를 위하여 네임스페이스 접두사를 사용한다. 접두사는 그냥 네임스페이스 식별자(URI)에 대한 축약어일 뿐이다. 접두사는 네임스페이스 선언을 통해 네임스페이스 식별자로 먼저 매핑된다. 네임스페이스 선언 문법은 다음과 같다.

xmlns:<prefix>='<namespace identifier>'

네임스페이스 정의는 속성 정의처럼 보이지만, 논리적 문서 구조의 관점에서는 공식적으로 속성으로 취급되지 않는다. (즉, DOM을 사용할 때 요소의 속성 콜렉션에 나타나지 않는다.)

A namespace prefix is considered in-scope on the declaration element as well as on any of its descendant elements. Once declared, the prefix can be used in front of any element or attribute name separated by a colon (such as s:student). This complete name including the prefix is the lexical form of a qualified name (QName):

네임스페이스 접두사는 선언요소 및 그 하위요소에서 in-scope로 간주된다. 접두사가 선언되면, 접두사는 어떤 요소나 속성이든 콜론으로 분리하여 사용할 수 있다. (s:student 와 같은 형태로) 이렇게 함으로써 접두사를 포함한 이름이 적격한 이름(QName, qualified name)의 사전적 형태를 완성한다.

QName = <prefix>:<local name>

접두사는 요소와 속성을 현재 scope에서 접두사에 매핑되어 있는 네임스페이스 식별자에 연결시킨다.

개발자가 XSLT 1.0 네임스페이스를 사용한다고 생각해보자. 그는 임의의 접두사를 공식 XSLT 1.0 네임스페이스 식별자(http://www.w3.org/1999/XSL/Transform)로 매핑하는 네임스페이스 선언을 제공해야 할 것이다. 그후, 그 개발자가 XSLT 1.0 네임스페이스로부터 사용하고자 하는 각각의 요소와 속성은 간단히 다음의 예와 같이 적절하게 접두사를 부여할 필요가 있다.

<x:transform version='1.0'
   xmlns:x='http://www.w3.org/1999/XSL/Transform' >
   <x:template match='/'>
      <hello_world/>
   </x:template>
</x:transform>

앞의 예는 네임스페이스 내에 있는 요소를 참조하는 문법을 나타낸다. 접두사 "x"를 가진 모든 요소는 http://www.w3.org/1999/XSL/Transform 네임스페이스에 속한 요소이며, 이 접두사가 없는 요소는 네임스페이가 없는 요소이다. (예 : hello_world 요소). 이제 프로세서는 XSLT 1.0 프로그래밍 구성체와 hello_world와 같이 출력물용 문자열 요소를 구분할 수 있게 된다. XSLT 1.0 네임스페이스가 한 글자라도 잘못 입력되면, XSLT 1.0 프로세서는 이 문서를 자신이 이해할 수 있는 어휘로 인식할 수 없게 된다.

본질적으로 각각의 요소는 이제 두 부분의 이름, 즉 네임스페이스 식별자와 로컬명을 가진다. 이 두가지 이름의 조합을 종종 네임스페이스 이름이라고 언급한다. (참고 : 이는 QName 와는 다르다. QName은 접두사와 로컬명의 조합이다.) 

또 다른 예로, 다음의 XML 문서는 이 문서의 앞에서 보인 XML Schema 정의에 있는 요소들을 사용하는 방법을 나타낸 것이다.

<d:student xmlns:d='http://www.develop.com/student'>
  <d:id>3235329</d:id>
  <d:name>Jeff Smith</d:name>
  <d:language>C#</d:language>
  <d:rating>9.5</d:rating>
</d:student>

주목할 점은, 네임스페이스가 어떻게 정의되었느냐에 관계없이, 그를 참조하는 문법은 동일하다는 것이다. 

문서가 여러개의 네임스페이스에서 요소나 속성을 사용할 경우, 아래의 예와 같이 주어진 요소에 여러개의 네임스페이스 선언을 갖는 것이 일반적이다.

<d:student xmlns:d='http://www.develop.com/student'
  xmlns:i='urn:schemas-develop-com:identifiers'
  xmlns:p='urn:schemas-develop-com:programming-languages' >
  <i:id>3235329</i:id>
  <name>Jeff Smith</name>
  <p:language>C#</p:language>
  <d:rating>9.5</d:rating>
</d:student>

여기에서 student와 rating은 동일한 네임스페이스 소속이지만, id와 language는 각각 다른 네임스페이스 소속이고 name은 어떤 네임스페이스에도 속하지 않는다.

네임스페이스 접두사는 아래의 예와 같이 중첩된 scope에서 접두사를 재정의함으로써 override 될 수 있다.

<d:student xmlns:d='http://www.develop.com/student'>
  <d:id>3235329</d:id> 
  <d:name xmlns:d='urn:names-r-us'>Jeff Smith</d:name>
  <d:language>C#</d:language>
  <d:rating>35</d:rating>
</d:student>

이 예에서 name 요소를 제외한 모든 요소들이 동일한 네임스페이스 소속이다. name요소는 urn:names-r-us 네임스페이스 소속이다. 네임스페이스 접두사를 이처럼 재정의하는 것은 가능하지만, 네임스페이스 정의를 무로 돌리는 것은 불가능하다. 예를 들어 다음은 규정에 어긋난다.

<d:student xmlns:d='http://www.develop.com/student'>
  <d:id xmlns:d=''>3235329</d:id> 
   ...
</d:student>

XML 네임스페이스에서 접두사 방식의 문법으로 참조하는 것은 대부분의 소프트웨어 개발자에게 상당히 직관적이다. 네임스페이스에 대한 XML 권고사항이 여기에서 멈췄다면 네임스페이스는 훨씬 덜 혼란스러웠을 것이다.

기본 네임스페이스

네임스페이스 식별자를 요소 명에 연계시키는 데 사용할 수 있는 또다른 형태의 네임스페이서 선언이 있다. 이를 기본 네임스페이스 선언 (default namespace declaration)이라고 하며, 다음과 같은 문법을 사용한다.

xmlns='<namespace identifier>'

보시다시피 접두사가 없다. 기본 네임스페이서 선언이 요소에 사용되면, 해당 scope에 있는 모든 비적격(unqualified) 요소 명은 자동적으로 지정된 네임스페이스 식별자에 연계된다. 하지만, 기본 네임스페이스 선언은 속성에는 전혀 효과가 없다. 속성을 네임스페이스 식별자에 연계시키는 유일한 방법은 접두사를 사용하는 것이다.

다음의 예를 살펴보자.

<d:student  xmlns:d='http://www.develop.com/student'
     xmlns='urn:foo' id='3235329'>
  <name>Jeff Smith</name>
  <language xmlns=''>C#</language>
  <rating>35</rating>
</d:student>

여기에서 "student"는 http://www.develop.com/student 네임스페이스 소속이지만, "name"과 "rating"은 기본 네임스페이스인 urn:foo 소속이다. id 속성은 아무런 네임스페이스에 속하지 않는다. 속성은 기본 네임스페이스 식별자에 자동으로 연계되지 않기 때문이다.

이 예는 또한 기본 네임스페이스의 정의를 무로 돌릴 수 있음을 보이고 있다. language 요소에서 기본 네임스페이스 식별자를 공백 문자열로 되돌리기만 하면 된다. (단, 접두사 선언은 무로 돌릴 수 없다는 점 기억하라.) 그 결과 language 요소도 아무런 네임스페이스에 속하지 않게 된다.)

기본 네임스페이스는 편의성을 위해 설계되었지만, 그 가치에 비해 혼란을 더 많이 초래하는 경향이 있다. 이러한 혼란은 전형적으로 요소와 속성이 다르게 취급된다는 점, 그리고 중첩된 요소가 기본 네임스페이스 식별자에 지정되는지 즉각적으로 알기 힘들다는 점 때문에 발생한다. 그럼에도 불구하고 종국적으로 접두사와 기본 네임스페이스의 선택은 거의 스타일의 문제가 된다.(속성은 없다는 전제하에)

네임스페이스 추상화

XML 문서의 추상적 뷰로부터 네임스페이스를 다루는 것은 방금 서술한 사전적 문제를 다루는 것보다 훨씬 간단하다. XML 정보 셋(Infoset)은 XML 문서의 추상적 구조를 정의하는데, 이상에서 서술한 네임스페이스 문법과 같은 포맷 직렬화의 복잡성으로부터 개발자를 방어해 준다.

Inforset에서 따르면, 각각의 요소와 속성은 네임스페이스 식별자와 로컬명 등 두가지 이름 속성이 있다. 그림3은 네임스페이스 적격이름(namespace-qualified name)을 포함한 XML 문서의 논리적 구조를 표시한 것이다. student, id, language는 모두 동일한 네임스페이스 소속이지만, ratings는 다른 네임스페이스 소속이고 name은 네임스페이스가 없다. 이 문서는 이전 절에서 서술한 기법들중 하나를 사용하여 직절화시킬 수 있다.


<그림3> 네임스페이스 적격 XML 문서

Consider how today's mainstream APIs, SAX and DOM, implement this abstract data model. SAX models elements through the startElement/endElement method calls of ContentHandler:

현재의 주류 API인 SAX와 DOM이 이들 추상 데이터 모델을 어떻게 구현하는지 고려해보자. SAX 모델 은 ContentHandler의 startElement/endElement 메소드 콜을 통해 요소화한다.

public interface contentHandler
{
    ...
void startElement(String namespaceURI, String localName, 
   String qName, Attributes atts) throws SAXException;
void endElement(String namespaceURI, String localName, 
   String qName) throws SAXException;
    ...
}

주목할 점은, 요소들이 네임스페이스 식별자와 로컬명 (옵션으로 QName)의 조합으로 식별된다는 것이다. 속성도 속성 인터페이스에 있는 네임스페이스-인지 메소드의 집합을 통해 식별된다. 네임스페이스 이름을 제공하고 문서 stream을 배달하는 것은 SAX 파서( 또는 다른 producer application)에게 달려있다. 즉, SAX를 사용하면 다른 종류의 student 요소를 프로그램적으로 간단하게 구분할 수 있다.

...
void startElement(String namespaceURI, String localName, 
   String qName, Attributes atts)
{
    if ( namespaceURI.equals("urn:dm:student") &&
         localName.equals("student") )
       {
        // process Developmentor student element here
    }
    else if ( namespaceURI.equals("urn:www.ed.gov:student") 
         && localName.equals("student") )
       {
        // process elementary school student element here
    }
}
...

네임스페이스 이름 (네임스페이스 식별자 + 로컬명)은 SAX 파서가 자동적으로 해결해주므로, 소스 문서에 있는 특정 요소나 속성에 어떠한 접두사가 사용되었는지는 문제가 안된다. 하지만, 그렇다고 하여 파싱이 완료된 후 접두사를 던져버릴 수 있다는 것은 아니다. 다음의 XML 문서를 생각해보자.

<student xmlns:xsd='http://www.w3.org/2000/10/XMLSchema'
xmlns:xsi='http://www.w3.org/2000/10/XMLSchema-instance'>
  <age xsi:type='xsd:double'>35.0</age>
</student>

Notice that the XML Schema xsi:type attribute on age contains a QName value. Any time a QName is used in element or attribute content, the consuming application is required to deal with it manually. The only way the consuming application can interpret this value correctly is if it knows what namespace identifier "xsd" is bound to. For this reason, the Infoset also maintains the set of in-scope namespace declarations for each element in the document. SAX models this information through the startPrefixMapping and endPrefixMapping method calls.

age에 XML Schema xsi:type 속성에는 QName 값이 포함되어 있음에 주목하라. 요소나 속성에서 QName 이 사용될 때마다 이를 사용하는 어플리케이션은 수동으로 처리할 필요가 있다. 이를 사용하는 어플이 이 값을 올바르게 해석하는 유일한 방법은, 식별자 "xsd"가 어떠한 네임스페이스에 연결되어 있는지를 아는 것이다. 이러한 이유로 Infoset은 문서에 있는 각각의 요소에 대해 in-scope 네임스페이스 선언 집합도 유지관리한다. SAX는 이러한 정보를 startPrefixMapping과 endPrefixMapping 메소드 호출을 통해 모델링한다.

DOM API는 Infoset의 또다른 구현이다. DOM의 노드 인터페이스는 요소/속성 노드의 기본 식별성을 두가지 이름 특성 (namespaceURI 와 localName)을 통해 모델링한다. 아울러 노드의 QName과 접두사를 NodeName과 prefix 특성을 통해 모델링한다. 아래에 있는 Java 코드는 DOM을 사용하여 두가지 다른 student 요소를 구별하는 방법을 표시한다.

void processStudent(Node n)
{
    if ( n.getNamespaceURI().equals("urn:dm:student") &&
         n.getLocalName().equals("student") )
       {
        // process Developmentor student element here
    }
    else if ( 
        n.getNamespaceURI().equals("urn:www.ed.gov:student") 
        && n.getLocalName().equals("student") )
       {
        // process elementary school student element here
    }
}

SAX와 마찬가지로 DOM 트리를 만드는 XML 파서는 네임스페이스 특성을 적절히 정착시킬 책임이 있다. 따라서 DOM에서도 논리적 문서를 다루는 한, 소스 문서에서 네임스페이스가 어떻게 선언되었는지 신경쓸 필요가 없다. DOM API를 통하여 문서를 생성할 경우, 작업자가 각각의 요소와 속성에 네임스페이스 식별자를 공급하여야 한다.

void generateStudentDocument(Document doc)
{
   Node docEl = doc.createElementNS("urn:dm:student", "student");
   doc.appendChild(docEl);
   Node n = doc.createElementNS("", "name");
   docEl.appendChild(n);
   ...
}

보시는 바와 같이 이 코드를 사용하면 논리적 구조를 직접 생성할 수 있다. 이후 네임스페이스 선언을 XML 1.0문서로 직렬화하는 방법을 알아내는 것은 DOM 구현에 달려있다. 이 예의 DOM 트리는 아래와 같이 직렬화될 수 있다.

<student xmlns='urn:dm:student'>
   <name xmlns=''/>
</student>

(SAX/DOM API를 통해) XML 문서의 추상 뷰를 처리할 때에는, 기본 네임스페이스라는 표현이 없다는 것을 알아야 한다. 앞서 인용했던 예에서 "student"를 위해 createElementNS를 호출한 후, urn:dm:student가 마술처럼 기본 네임스페이스가 되지 않는다. "name"을 위해 네임스페이스를 주지 않고 createElementNS를 호출하면, name 요소에 빈 네임스페이스가 지정된다. (urn:dm:student가 지정되는 게 아님). SAX에서 startElement/endElement 메소드 호출 시퀀스에서도 동일하게 적용된다. 각각의 요소/속성 노드는 항상 이름 정보에 대해 독립적으로 취급된다.

XPath는 추상 문서 구조에서 노드를 식별할 수 있는 방법을 정의한 또다른 XML 사양이다. XPath 표현을 사용하면 요소와 속성을 네임스페이스 적격 이름에 의해 식별할 수 있다. XPath 이름 테스트는 간단한 문자열 표현이기 때문에, XPath 이름 테스트를 네임스페이스 식별자에 연결시키는 유일한 방법은 네임스페이스 접두사를 사용하는 방법이다.

XPath 노드 테스트를 QName 유형이라고 생각할 수도 있다. 즉, 어떤 노드테스트가 접두사를 표함하지 않는다면 주어진 이름을 "아무런 네임스페이스에도 포함시키지 않도록" 요청하는 것이다. 예를 들어 다음과 같은 XPath 표현을 살펴보자.

/student/name

이 표현은 아무런 네임스페이스에도 속하지 않는 최상위 student요소의 자식 중에서 아무런 네임스페이스에 속하지 않는 모든 name 요소를 식별한다. urn:dm:student 네임스페이스에 속한 student와 name 요소를 식별하려면, 먼저 네임스페이스 접주사를 urn:dm:student 에 연계시킬 필요가 있다. 그다음 접두사를 XPath 표현에 사용될 수 있다.

"dm"이 XPath 문맥에서 urn:dm:student 에 연계되었다고 가정할 때, 다음과 같은 표현은 이제 urn:dm:store 네임스페이스에 속한 최상위 student 요소의 자식 중에서 urn:dm:storm 네임스페이스에 속한 name 요소를 식별한다. 

/dm:student/dm:name

If the queried document looked like the code that follows, then the previous expression would identify all three name elements that are children of student, regardless of their prefixes, because they're all from the same namespace in question.

만약 질의된 문서가 다음 코드와 같다면, 위의 표현식은 접두사에 관계없이 student의 자식인 모든 세개의 name 요소를 식별하게 될 것이다. 이들 모두가 문제의 네임스페이스와 동일한 네임스페이스 소속이기 때문이다.

<x:transform version='1.0'
   xmlns:x='http://www.w3.org/1999/XSL/Transform'
   xmlns:d='urn:dm:student'>
   <x:template match='d:student'>
     <!-- transform student here -->
     <x:apply-templates select='d:name'/>
   </x:template>
   ...
</x:transform>

첫번째 template는 urn:dm:student 네임스페이스 소속의 student 요소에 매치됨을 주목하라. 매치된 값이 단순히 "student"라면, 아무런 네임스페이스도 없는 student 요소에만 매치된다. 그다음 apply-templates 요소는 또다시 urn:dm:student 네임스페이스에 속한 모든 자식 name 요소를 처리한다.

As you can see, understanding how namespaces work both lexically and abstractly is crucial to understanding the entire family of XML specifications. You will encounter many situations similar to these scattered throughout the emerging XML specifications.

보는 것처럼, 네임스페이스가 문법적, 추상적 양쪽에서 어떻게 작동하는 지 이해하는 것은, XML 사양의 전체 가족을 이해할 때 매우 중요하다. 여러분은 앞으로 나타날 XML 사양 전반에 걸쳐, 이것과 비슷한 상황을 많이 마주하게 될 것이다.

요약

네임스페이스는 모든 이름이 유일한 이름의 집합이다. XML에서 네임스페이스를 사용하면 요소와 속성에 유일한 이름을 부여할 수 있다. 네임스페이스가 많은 혼란을 일으키는 경향이 있기는 하지만, 문법적, 추상적 양쪽에서 어떻게 정의되고 사용되는지에 친숙해지면, 이해하는 것은 어렵지 않다. 네임스페이스에 관한 더 많은 정보가 필요하다면 XML 권고사항에서 네임스페이스예제로 본 XML네임스페이스를 참고하라.

Aaron Skonnard는 DevelopMentor의 교수이자 연구원으로서 XML 커리큘럼을 개발하는 업무를 담당하고 있다. Aaron은 Essential XML (Addison-Wesley Longman, 2000)의 공동저자이며, Essential Winlnet(Addison-Wesley Longman, 1998)을 저술하였다. Aaron의 연락처는 http://staff.develop.com/aarons에서 찾을 수 있다.

====

원문 : https://msdn.microsoft.com/en-us/library/aa468565.aspx

Posted by 푸른하늘이

댓글을 달아 주세요

공간정보/표준2017. 12. 24. 14:29

XML Schema란?

  • XML Schema는 XML 문서의 구조를 설명함.
  • XML Schema 언어는 XSD(XML Schema Definition) 이라고도 한다.
  • XML 스키마의 목적 : XML 문서의 합법적 기본구성요소를 정의
    • 문서에 어떤 요소와 속성이 나타나야 하는가?
    • 하위 요소들의 수와 순서
    • 요소와 속성의 데이터 유형
    • 요소와 속성의 기본값/고정값
  • 왜 XML 스키마를 배워야 하는가?
    • 이미 수백가지의 표준화된 XML 포맷이 사용중이다.
    • 수많은 XML 표준은 XML Schema로 정의되어 있다.
    • XML Schema는 XML기반이며, DTD를 대체할 수있으며 훨씬 강력하다.
  • XML 스키마는 데이터유형을 지원한다.
    • 허용되는 내용을 쉽게 설명가능
    • 데이터의 정확성 검증가능
    • 데이터에 대한 제한을 정의가능
    • 데이터 패턴(포맷)을 쉽게 정의가능
    • 다른 유형으로 쉽게 변환 가능
  • XML Schema는 XML 문법을 사용함. 따라서
    • 새로운 언어를 배울 필요 없으며
    • XML 에디터로 스키마파일을 편집할 수 있고
    • XML parser로 스키마파일을 파싱할 수 있고
    • XML DOM으로 처리할 수 있으며
    • XSLT로 스키마를 변환할 수 있다.
    • XML Schema는 확장가능하다. 따라서
      • 다른 스키마를 재사용가능하다.
      • 표준 유형에서 새로운 데이터유형을 생성할 수 있다.
      • 동일한 문서에서 여러개의 스키마를 참조할 수 있다.
  • XML 스키마를 사용하면 안전한 데이터 통신이 가능하다.
    • 데이터를 보낼때, 내용에 대한 동일한 이해가 가능하다.
    • 수신자가 이해할 수 있는 방법으로 데이터를 설명할 수 있다.
    • "3-11-2004" 와 같이 데이터 해석이 달라질 염려를 없앨 수 있다.
  • Well-Formed 문서만으로는 부족하다.
    • Well-Formed 된 문서도 오류가 있을 수 있다.
    • XML Schema를 사용하면 에러를 검증할 수 있다.

XSD 사용법

  • XML 문서는 XML Schema에 대한 참조를 가질 수 있다.
  • 예제 XML 문서 : note.xml

<?xml version="1.0" encoding="utf-8"?>
<note>
    <to>Tove</to>
    <from>Jani</from>
    <body>Don't forget me this weekend!</body>
</note>

  • 이 문서에 대한 XML Schema : note.xsd

<?xml version="1.0" encoding="utf-8"?>
<xs:schema
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    targetNamespace="https://www.w3schools.com"
    xmlns="https://www.w3cschools.com"
    elementFormDefault="qualified">

<xs:element name="note">
    <xs:complexType>
        <xs:sequence>
            <xs:element name="to" type="xs:string" />
            <xs:element name="from" type="xs:string" />
            <xs:element name="body" type="xs:string" />
        </xs:sequence>
    </xs:complexType>
</xs:element>

</xs:schema>

  • 이 note.xsd를 참조하여 note.xml을 다시 작성하면

<?xml version="1.0"? encoding="utf-8">
<note 
xmlns="https://www.w3schools.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://www.w3schools.com/xml/note.xsd">
    <to>Tove</to>
    <from>Jani</Jani>
    <body>Don't forget me this weekend!</body>
</note>

XSD- <schema> 요소

  • <schema> 요소는 모든 XML Schema 문서의 root 요소이다.
  • <schema> 요소는 속성을 가질 수 있다.
    • xmlns:xs="http://www.w3.org/2001/XMLSchema" 
      • 이 schema에 사용되는 데이터유형이 w3.org 네임스페이스에서 왔음을 의미함
      • 이 데이터유형들을 사용할 때 xs: 를 사용해야 함
    • targetNamespace="https://w3schools.com"
      • 이 스키마에서 정의되는 요소(note, to, body)는 "w3school" 네임스페이스에서 왔음
    • xmlns="https://www.w3schools.com"
      • 네임스페이스 기본값이 "https://www.w3schools.com" 임
    • elementFormDefault="qualified"
      • 이 스키마에서 선언되는 XML 인스턴스 문서에 사용되는 모든 요소는 네임스페이스에 한정되어야 한다(namespace qualified)
  • XML 문서에서 스키마를 참조할 때...
    • xmlns="https://www.w3schools.com"
      • 기본 네임스페이스 선언. 이 문서에서 사용된 모든 요소들은 w3schools 네임스페이스에 선언되었음을 의미함
    • xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      • 먼저 이렇게 XML schema instance 네임스페이스를 가져오면, 아래의 schemaLocation 속성을 사용할 수 있게됨.
    • xsi:schemaLocation="https://www.w3schools.com note.xsd"
      • schemaLocation 속성은 두개의 값이 들어가며, 첫번째값은 사용할 네임스페이스, 두번째는 해당 네임스페이스에서 사용하고자하는 XML 스키마의 위치임.

XSD Simple 요소

  • simple 요소는 텍스트만 담을 수 있는 요소. 
    • 하지만, 텍스트는 여러가지 유형이 있음. XML Schema definition에는 boolean, string, data 등의 유형이 정의되어 있고, 사용자가 정의할 수도 있다.
    • 내용을 제한하기 위해 데이터유형에 제한(facets)를 걸 수도 있고, 특정한 패턴만 요구할 수도 있음
  • Simple 요소 정의방법
    • <xs:element name="xxx" type="yyy" />
      • xxx는 이름. 
      • yyy는 다음과 같은 여러가지를 사용할 수 있음
        • xs:string
        • xs:decimal
        • xs:integer
        • xs:boolean
        • xs:date
        • xs:time
  • 예제 xml 요소

<lastname>Heo</lastname>
<age>35</age>
<dateborn>1970-03-27</dateborn>

  • 이에 대한 simple 요소 정의

<xs:element name="lastname" type="xs:string"/>
<xs:element name="age" type="xs:integer"/>
<xs:element name="dateborn" type="xs:date"/>

  • 기본값(default)과 고정값(fixed)
    • 기본값
      • <xs:element name="color" type="xs:string" default="red">
    • 고정값
      • <xs:element name="Rcolor" type="xs:string" fixed="red">

XSD 속성

  • 속성을 정의하는 방법
    • <attribute name="xxx" type="yyy" />
    • 여기서 "yyy" 데이터 유형은 element와 동일
    • <lastname lang="EN">Smith</lastname>을 정의하려면

<xs:element name="lastname" type="xs:string" />
<xs:attribute name="lang" type="xs:string" />

  • 기본값과 고정값을 부여하는 방법은 요소의 경우와 동일하다.
  • 필수/선택은 "use" attribute를 사용한다.
    • <xs:attribute name="lang" type="xs:string" use="required" />

XSD Restrictions

  • 이상과 같이 type을 지정하면 들어올 수 있는 내용을 제한하게 된다.
  • 여기에 사용자가 원하는 제한을 더 가할 수 있다. 이것을 facets라고 한다.
  • 최대값 최소값 : 아래의 예는 값의 범위를 정하는 방법

<xs:element name="age">
    <xs:simpleType>
        <xs:restriction base="xs:integer">
            <xs:minInclusive value="0" />
            <xs:maxInclusive value="120" />
        </xs:restriction>
    </xs:simpleType>
</xs:element>

  • 값 목록을 지정할 경우

<xs:element name="car">
    <xs:simpleType>
        <xs:restriction base="xs:string">
            <xs:enumeration value="Audi" />
            <xs:enumeration value="BMV" />
            <xs:enumeration value="Golf" />
        </xs:restriction>
    </xs:simpleType>
</xs:element>

  • 아래는 위와 동등한 내용
    • 이 경우, "carType"은 다른 항목에도 사용할 수 있다.
    • 재활용이 가능하므로, 대부분 이런 형태로 정의한다.

<xs:element name="car" type="carType" />

<xs:simpleType name="carType">
    <xs:restriction base="xs:string">
        <xs:enumeration value="Audi" />
        .........
</xs:simpleType>

  • 기타 여러가지 제한
    • <xs:pattern value="[a-z]" />    : 소문자로 한글자.
    • <xs:pattern value="[A-Z][A-Z][A-Z]" /> : 대문자로 세글자
    • <xs:pattern value="[a-zA-A][a-zA-A][a-zA-A]" />: 세글자
    • <xs:pattern value="[xyz]" />            : "x" 또는 "y" 또는 "z"
    • <xs:pattern value="[0-9][0-9][0-9][0-9][0-9]" />        : 5자리 숫자
    • <xs:pattern value="([a-z])*" />        : 소문자만. 글자수는 0 이상
    • <xs:pattern value="([a-z][A-Z])+" /> : 소문자+대문자쌍으로. 글자수는 2이상
    • <xs:pattern value="male|female" /> : "male" 또는 "female" 만
    • <xs:pattern value="[a-zA-Z0-9]{8}" />    : 영숫자 8글자
    • <xs:whiteSpace value="preserve" />      : 공백문자(LF, CR, Tab등)을 그대로 유지
    • <xs:whiteSpace value="replace" />        : 모든 종류의 공백문자들을 space로 바꿈
    • <xs:whiteSpace value="collapse" />       : 앞뒤, 여러개의 공백을 하나의 space로
    • <xs:length value="8" />                      : 8글자
    • <xs:minLength value="5" /> <xs:maxLength value="8" />   5글자에서 8글자까지
  • 기타 데이터 유형에 관한 제한
    • enumeration : 허용되는 값의 목록을 정의함
    • factionDigits : 소숫점이하 자릿수 지정(0 이상)
    • length : 문자의 수 또는 목록의 경우 목록의 수(0 이상)
    • maxExclusive : 허용되는 숫자형의 상한값(미만)
    • maxInclusive : 허용되는 숫자형의 상한값(이하)
    • maxLength : 최대 문자수 또는 최대 목록수
    • minExclusive : 허용되는 숫자형의 하한값(초과)
    • minInclusive : 허용되는 숫자형의 하한값(이상)
    • minLength : 최소 문자수 또는 최소 목록수
    • pattern : 허용되는 문자열의 순서
    • totalDigits : 허용되는 숫자 자릿수 (0 이상)
    • whiteSpace : white space(LF, tab, space, CR)를 어떻게 취급할 지 지정

XSD Complex 요소

  • Complex 요소란 다른 요소나 속성을 포함하는 요소로 4가지 종류가 있다.
    • <product pid="12354" />                                  : empty 요소
    • <employee><fn>A</fn><ln>B</ln></employee>  : 다른 요소만 포함하는 요소
    • <food type="desert">Ice cream</food>               : 텍스트만 포함하는 요소
    • <desc>It happened on <date lang="NR">03.03.99</date></desc>
                                          : 다른 요소와 텍스트를 포함하는 요소
    • 단!!!! 각각의 요소는 속성을 가질 수 있다.

Complex 요소를 정의하는 방법의 예

<employee>
    <firstname>Jorhn</firstname>
    <lastname>Smith</lastname>
</employee>

====

<xs:element name="employee">
    <xs:complexType>
        <xs:sequence>                    sequence를 사용하면 순서대로 나타나야 함.
            <xs:element name="firstname" type="xs:string" />
            <xs:element name="lastname" type="xs:string" />
        </xs:sequence>
    </xs:complexType>
</xs:element>

  • 유형을 따로 정하면 여러번 반복하여 사용할 수 있다.

<xs:element name="employee" type="personType" />
<xs:element name="student" type="personType" />

<xs:complexType name="personType">
    <xs:sequence>
        <xs:element name="firstname" type="xs:string" />
        
<xs:element name="lastname" type="xs:string" />
    </xs:sequence>
<xs:complexType>

  • xs:complexContent와 xs:extension을 사용하면 기본 complex 요소를 확장시킬 수 있다.

<xs:element name="employee" type="fullPersonInfo" />

<xs:complexType name="personinfo">
    <xs:sequence>
        <xs:element name="firstname" type="xs:string" />
        
<xs:element name="lastname" type="xs:string" />
    </xs:sequence>
<xs:complexType>

<xs:complexType name="fullPersonInfo">
    <xs:complexContent>
        <xs:extension base="personinfo">
            <xs:sequence>
                <xs:element name="address" type="xs:string">
                
<xs:element name="city" type="xs:string">
                <xs:element name="country" type="xs:string">
            </xs:sequence>
        </xs:extension>
    </xs:complexContent>
</xs:complexType>

XSD Empty 요소

  • <product prodid="1234" /> 와 같이 내용이 없는 요소를 정의하려면 아래의 방법이 가장 간단.

<xs:element name="product" type="prodType" />

<xs:complexType name="prodtype">
    <xs:attribute name="prodid" type="xs:positiveInteger" />
</xs:complexType>

XSD 요소들만 들어가는 Complex 유형

<person>
    <firstname>A</firstname>
    <lastname>B</lastname>
</person>

====

<xs:element name="person" type="personType" />

<xs:complexType name="personType">
    <xs:sequence>
        <xs:element name="firstname" type="xs:string" />
        <xs:element name="lastname" type="xs:string" />
    </xs:sequence>
</xs:complexType>

Text만 들어가는 Complex 유형

  • simple 유형은 <xs:element name="xxx" type="yyy"/> 와 같이, 제한도, 속성도 못넣음
  • <shoesize country="france">35</shoesize> 를 정의하는 방법
    • complexType으로 정의하고, 내부에 simpleContent를 넣고 그 안에 extension 또는 restriction을 사용함.

<xs:element name="shoesize" type="shoeType" />

<xs:complexType name="shoeType"
    <xs:simpleContent>
        <xs:extension base="xs:integer">
            <xs:attribute name="country" type="xs:string" />
        </xs:extension>
    </xs:simpleContent>
</xs:complexContent

XSD 문자와 요소가 혼합된 Comlex 유형

  • 아래와 같이 문자와 요소가 섞여도 무방한 Complex 유형을 만들려면 mixed="true"를 추가하면 된다.

<letter>
    Dear Mr.<name>John Smith</name>.
    Your order <orderid>2043</orderid>
    will be shipped on <shipdate>2001-07-13</shipdate>.
</letter>

<xs:element name="letter" type="letterType" />

<xs:complexType name="letterType" mixed="true">
    <xs:sequence>                                        ----> 순서대로 나타나야 함
        <xs:element name="name" type="xs:string">
        <xs:element name="order" type="xs:positiveInteger">
        <xs:element name="shipdate" type="xs:date">
    </xs:sequence>
</xs:complexType>

XSD 지시자(Indicator)

  • 순서 지시자(Order Indicator)
    • sequence - 모두 한번씩. 정해진 순서대로
    • all - 모두 단 한번씩 등장해야 함. 순서는 없음
    • choice - 둘중의 하나만 등장
  • 횟수 지시자(Occurence Indicator)
    • minOccurs/maxOccurs
  • 그룹 지시자(Group Indicator)
    • <xs:group name="xxx">   
    • 그룹을 지정하면 다른 정의에서도 사용할 수 있음
  • 속성 그룹(attribute Group)
    • <xs:attributeGroup name="xxx">
    • 그룹을 지정하면 다른 정의에서도 사용할 수 있음
  • 예제

<?xml version="1.0" encoding="UTF-8" ?>
<persons xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="family.xsd">

<person>
    <fullname>Min Heo</fullname>
    <childname>Minho</childname>
</person>

<person>
    <fullname>Tove Refsnes</fullname>
    <childname>Hege</childname>
    <childname>Stale</childname>
    <childname>Jim</childname>
</person>

<person>
    <fullname>Stale Refsnes</fullname>
</person>

</persons>

  • family.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
      elementFormDefault="qualified">

<xs:element name="persons">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="person" maxOccurs="unbounded">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="fullname" type="xs:string"/>
            <xs:element name="childname" type="xs:string"
                  minOccurs="0" maxOccurs="5"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    </xs:sequence>
  </xs:complexType>
</xs:element>

</xs:schema>

XSD <any> 요소, <anyAttribute> 요소

  • <any> 요소를 사용하면 스키마에서 지정하지 않은 요소를 사용할 수 있도록 확장시킬 수 있다.
  • 아래는 family.xsd 파일의 일부

<xs:element name="person">
    <xs:complexType>
        <xs:sequence>
            <xs:element name="firstname" type="xs:string" />
            <xs:element name="lastname" type="xs:string" />
            <xs:any minOccurs="0" />
 --- </xs:element>

  • 사용법은....

XSD Substitution Group

  • 예를 들어, 영국고객과 노르웨이고객이 있어서, 영국식/노르웨이 언어로 정의하도록
  • head 요소를 정의한 후, 이 head 요소를 대체할 수 있다고 명시한 또 다른 요소를 정의한다. 
  • 아래에서 head 요소는 "name", "navn"요소는 "name" 요소를 대체할 수 있음.

<xs:element name="name" type="xs:string" />
<xs:element name="navn" substitutionGroup="name" />

  • XML Schema

<xs:element name="name" type="xs:string" />
<xs:element name="navn" substitutionGroup="name" />

<xs:complexType name="customerType">
    <xs:sequence>
        <xs:element ref="name" />
    <xs:sequence>
</xs:complexType>

<xs:element name="customer" type="customerType" />
<xs:element name="kunde" substitutionGroup="customer" />

  • 이런 식으로 정의하였을 때 XML 파일에는 아래와 같이 두가지가 모두 들어갈 수 있다.

<customer>
    <name>Min Heo</name>
</customer>
<kunde>
    <navn>John Smith</navn>
</kunde>

  • 대체를 금지시키고 싶으면 block을 사용하면 된다.

<xs:element name="name" type="xs:string" block= "substitution" />

  • SubstitutionGroup 사용방법
    • 대체가능 요소(substitutable element)는 head요소와 동일한 type 또는 head 요소 유형에서 유도된 유형이어야 한다.
    • 동일한 유형일 경우엔 substitution 하면서 type은 정의할 필요없지만, 유도할 경우 새로 정의
    • substitutionGroup의 모든 요소(head 요소 및 substitutable 요소)는 반드시 Global 요소로 선언

XSD 예제

<?xml version="1.0" encoding="UTF-8" ?>
<shiporder orderid="8893"
    xmlns:xsi="http://www.w3c.org/2001/XMLSchema-Instance"
    xsi:noNamespaceSchemaLocaiton="shiporder.xsd">

    <orderperson>John Smith</orderperson>
    <shipto>
        <name>Ola Nordmann</name>
<address>Langgt 2</address>
<city>400 Stavanger</city>
<country>Norway</country>
    </shipto>

    <item>
        <title>Empire Burlesque</title>
<note>Special Edition</note>
<quantity>1</quantity>
<price>10.90</price>
    </item>

    <item>
        <title>Hide your Heart</title>
<quantity>1</quantity>
<price>9.90</price>
    </item>
</shiporder>

  • root 요소 : shiporder (orderid라는 속성이 있음)
    shiporder는 3개의 child 요소(orderperson, shipto, item)
  • xmlns:xsi="http://www.w3c.org/2001/XMLSchema-instance"- 반드시 schema에 비교해야 함을 의미
  • xsi:noNamespaceSchemaLocation="shiporder.xsd" - 스키마의 위치 (여기에선 동일한 폴더)

<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

<xs:element name="shiporder">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="orderperson" type="xs:string"/>
      <xs:element name="shipto">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="name" type="xs:string"/>
            <xs:element name="address" type="xs:string"/>
            <xs:element name="city" type="xs:string"/>
            <xs:element name="country" type="xs:string"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>

      <xs:element name="item" maxOccurs="unbounded">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="title" type="xs:string"/>
            <xs:element name="note" type="xs:string" minOccurs="0"/>
            <xs:element name="quantity" type="xs:positiveInteger"/>
            <xs:element name="price" type="xs:decimal"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>

    </xs:sequence>
    <xs:attribute name="orderid" type="xs:string" use="required"/>
  </xs:complexType>
</xs:element>

</xs:schema>

XSD 분할

  • 문서가 복잡해지면 읽기 힘들다.
  • 모든 요소와 속성을 미리 다 정의한 후, 이들을 ref 속성을 사용하여 참조한다. 

Named 유형을 사용하기

  • 클래스/유형을 먼저 정의하고, 요소 정의를 재활용. 


===

원문 : https://www.w3schools.com/xml/schema_intro.asp 에서...

Posted by 푸른하늘이

댓글을 달아 주세요

공간정보/표준2017. 12. 24. 12:06

이 글은 W3C 의 XML 투토리얼에 있는 내용을 간략히 정리한 것입니다. 

저는 현재 공간정보 표준들을 정리하는 중입니다. 지형지물목록이나 메타데이터 등의 많은 표준들이 XML 을 표준으로 사용하고 있기 때문에 어쩔 수 없이 이 글을 찾아보게 된겁니다. 

그런데... XML이 정보를 담기위한 목적이라는 것은 어렴풋이 알고 있었지만, 이렇게 광범위하게 사용될 수 있을지는 몰랐네요. 아주 간략하게 어떤 기능이 있는지 어떻게 활용할 수 있는지에 대해서만 수박 겉핥기 식으로 훝어봤습니다만, 많이 도움이 될 것 같습니다. 이 글을 방문하신 분들도 저처럼 도움이 되시길 바랍니다.

XML 이란

  • eXtensible Markup Language
  • HTML과 비슷한 마크업 언어
    • HTML은 표현. XML은 데이터 그 자체
    • XML에서는 tag가 미리 정의되어 있지 않음
  • 데이터를 저장하거나 전송하는 목적
    • 표현과는 관련이 없다.
  • self-descriptive (하나의 문서만으로 모든 것을 설명할 수 있게) 설계됨
  • W3C에서 추천함
    • 데이터 공유가 쉽다. 
    • 전송이 쉽다
    • 플랫폼에 독립적이다.
    • 데이터 사용을 쉽게 한다.

XML은 어떻게 사용하는가

  • 데이터와 표현을 분리한다. (XML에는 표현하기 위한 어떤 정보도 없다)
  • HTML에 보조하여 사용하기도 한다.
  • 별도의 XML 파일로 저장하고, JavaScript로 HTML에 읽어들일 수 있다.
  • 산업분야별로 정해진 XML 포맷이 있다. 이것을 사용하여 데이터를 전송한다.
    • 예를 들어 XML News 는 뉴스를 교환하기 위한 사양이다.
    • NOAA의 날씨 서비스는 XML Weather Service를 이용한다.

XML의 트리구조

  • root 엘리먼트 밑에 child 엘리먼트가 있다. 
  • parent - child - sibling
  • 모든 엘리먼트는 내용(text content)와 속성(attribute 예: category="cooking") 을 가질 수 있다.

XML의 구조 규칙 ("Well Formed")

  • 반드시 Root 엘리먼트(모든 엘리먼트의 parent)가 있어야 한다. 
  • prolog는 첫줄에 있어야 한다. (선택)
    • <?xml version="1.0" encoding="UTF-8"?>
    • UTF-8이 기존 문자인코딩이다. (HTML5, CSS, JavaScript, PHP, SQL 등에서도 UTF-8이 기본)
  • 모든 XML 엘리먼트는 끝 태그(closing tag)가 있어야 한다.
    • prolog의 경우엔 xml 문서요소가 아니므로 끝 태그가 없다.
  • XML 태그는 대소문자를 구분한다. 시작태그와 끝태그는 동일해야 한다.
  • 중첩순서가 맞아야 한다. - First in Last out
  • XML 속성값은 반드시 "따옴표" 로 묶어야 함.
    • <note date="12/11/2007">
  • 특수문자는... 
    • &lt;    &gt;    &amp;   &apos;   &quot;
  • 코멘트는 
    • <!-- 이렇게 하면 코멘트 -->
  • XML에서는 blank를 여러개 사용해도 무방하다.

XML 엘리먼트

  • 시작태그와 끝태그 사이에 있는 모든 것. (시작태그와 끝태그도 포함
  • 엘리먼트는 다음과 같은 것들을 가질 수 있다.
    • text
    • attribute
    • 다른 element
  • Empty Element도 존재할 수 있고, 속성을 가질 수 있다. 아래 두가지 형태 모두 허용
    • <element></element>
    • <element />
  • XML 명명 규칙
    • 대소문자 구분. 시작은 문자또는 underscore
    • xml,XML,Xml 등으로 시작할 수 없음
    • 문자, 숫자, 하이픈, underscore, 마침표(. period)를 포함해도 된다.
    • 공백은 포함할 수 없다.
  • 이름 지을때 주의할 점
    • 마이너스, 마침표, 콜론 등은 사용하지 않는 게 좋고, plain 알파벳을 사용하는 것이 좋다.
  • 명명 스타일은 정해진 게 없다
    • 전체소문자, 전체대문자,_로 연결, Pascal case, Camel case 모두 허용
    • 무엇을 사용하던 일관성있게 사용하라.
  • Element는 확장 가능하다.
    • 확장하여 추가하더라도, 어플쪽엔 아무런 문제도 없다.

XML 속성

  • 반드시 따옴표 사용. 홑따옴표, 곁따옴표 모두 OK
    • <person gender="female">
    • <person gender='female'>
  • 따옴표 내에 따옴표 있을 경우, 다른 것을 사용하던지 &quot;를 사용
  • 무엇을 속성으로 할지, 엘리먼트로 할지는 정해진 것이 없음. 편한대로. 정보도 동일함
  • 되도록이면 ATTRIBUTE 보다는 Element를 사용
    • 엘리먼트는 값을 여러개 가질 수도 있고, 트리구조를 가질 수 있고, 쉽게 확장할 수 있음.

XML 네임스페이스

  • 다른 응용에 속한 XML 문서를 찹치려고 하면 충돌이 발생할 수 있음
  • 이름접두어(name prefix)를 사용하면 해결가능 <h:table> <h:tr> ... </h:tr> </h:table>
  • 접두어를 사용하려면 네임스페이스를 반드시 정의해야 함.
    • <h:table xmlns="namespaceURI"> <h:tr> ... </h:tr> </h:table> 등으로 사용.
    • xmlns 는 속성. 이 속성이 이하에 있는 h: 접두어에 대해 적법한 네임스페이스를 지정함
    • 네임스페이스를 어떤 엘리먼트에 정의하면, 그 prefix를 사용하는 모든 자식 엘리먼트는 해당 네임스페이스에 속하게 됨.
  • 네임스페이스를 root 엘리먼트에 한꺼번에 정의할 수도 있음
    • 단, 여기에 있는 URI는 parser가 사용하지 않음. 고유한 이름을 지정하는 목적일 뿐.
    • 하지만, 네임스페이스 정보가 담긴 웹페이지를 가르키는 포인터로서 네임스페이스를 사용하는 경우가 많음.

<root xmlns:h="http://www.w3.org/TR/html4/"
xmlns:f="https://www.w3schools.com/furniture"
>

<h:table>
  <h:tr>
    <h:td>Apples</h:td>
    <h:td>Bananas</h:td>
  </h:tr>
</h:table>
<f:table>
  <f:name>African Coffee Table</f:name>
  <f:width>80</f:width>
  <f:length>120</f:length>
</f:table>
</root>

  • default 네임스페이스를 사용하면 각 엘리먼트마다 접두사를 붙일 필요없음
    • <table xmlns="namespaceURI"> <tr> ... </tr> </table>

XML 디스플레이

  • xml 파일을 그냥 브라우저에서 보면, 브라우저 별로 다르게 보인다. 
  • 소스보기를 하면 원래 파일의 내용을 볼 수 있다.
  • xml 파일에 오류가 있으면 오류를 표시하기도 하고, 아무것도 안보이기도 한다.
  • 이렇게 제각각으로 보이는 것은 XML에 표시에 관한 아무런 정보도 없기 때문이다.
  • CSS 를 이용해서 보이는 방법도 있지만, 추천되는 방법은 아니다.

XML HttpRequest

  • 대부분의 최신 브라우저는 서버로부터 데이터를 요청하는 XMLHttpRequest 오브젝트가 있다. 이를 사용하면 다음과 같은 장점이 있다.
    • 페이지를 새로 부르지 않고 페이지를 갱신할 수 있음
    • 페이지가 전송된 후 데이터를 전송하고 수신할 수 있다.
    • 백그라운드로 서버에 데이터를 송신할 수 있다.
  • 자세한 내용은 이 블로그의 글을 참조

XML 해석기

  • 대부분의 브라우저는 XML 해석기(parser)가 내장되어 있음. 아래와 같이 사용가능

<script>
var text, parser, xmlDoc;

text = "<bookstore><book>" +
"<title>Everyday Italian</title>" +
"<author>Giada De Laurentiis</author>" +
"<year>2005</year>" +
"</book></bookstore>";

parser = new DOMParser(); 
xmlDoc = parser.parseFromString(text,"text/xml");

document.getElementById("demo").innerHTML =
xmlDoc.getElementsByTagName("title")[0].childNodes[0].nodeValue;
</script>

  • XMLHttpRequest 객체는 XML 해석기가 내장되어 있음
    • responseText 프로퍼티는 string 형식의 응답이 들어있음
    • responseXML 프로퍼티에는 XML 형식의 응답이 들어 있음

XML DOM

  • DOM(Document Object Model)은 플랫폼/언어 중립적 인터페이스로서, 이를 통해 프로그램이나 스크립트에서 문서의 내용과 구조, 스타일을 동적으로 접근/갱신할 수 있다.
  • HTML이나 XML을 트리구조로 표현
    • getElementById() 등의 함수를 이용해 접근가능

XML 과 XPath

  • XPath는 XSLT 표준의 중요 요소이다.
  • XPath는 XML 문서에서 엘리먼트와 속성을 방문하는데 사용된다.


    • XPath는 XML 문서의 부분을 정의하는 문법이다.
    • XPath는 XML 문서를 방문하기 위한 경로표현식(path expression)을 사용한다.
    • XPath는 표준 함수의 라이브러리를 포함한다.
    • XPath는 W3C에서 추천한다.
 
  • XPath는 경로 표현식(Path Expression)을 사용하여 XML 문서의 노드를 선택한다. 이 경로표현식은 컴퓨터 파일시스템의 경로와 비슷한 형태이다.
  • XPath는 JavaScript, Java, XML Schema, PHP, Python, C, C++ 등 많은 언어에서 사용된다.
  • XSLT에서도 사용된다. XPath를 알면 XSL을 잘 활용할 수 있다.
  • 예제
    • /bookstore/book[1]    -> bookstore 엘리먼트의 자손들중 첫번째 book 엘리먼트 선택
    • /bookstore/book[last()-1)     -> ... 끝에서 두번째 엘리먼트 선택
    • /bookstore/book[postion()<3]     -> ... 처음 두개의 엘리먼트 선택
    • //title[@lang='en']            -> "lang" 속성이 "en"인 모든 title 엘리먼트 선택
    • //bookstore/book[price>35.00]/title          -> price 엘리먼트의 값이 35.00보다큰 모든 book 엘리먼트의 title 엘리먼트를 선택하라.
  • XPath 투토리얼

XML 과 XSLT

  • XSLT는 XML 문서를 HTML로 변환하는데 사용한다.
  • XSLT(eXtensible Stylesheet Language Transformations)는 XML을 위한 추천 스타일시트 언어
  • CSS 보다 훨씬 복잡함. XSLT를 사용하면 출력 파일로부터 엘리먼트나 속성을 추가/제거할 수 있음 재배열, 정렬도 가능하고, 테스트도 가능, 어떤 요소를 숨길지 표시할지 결정할 수 있음
  • XSLT는 XPath를 사용하여 XML 문서에서 정보를 찾아냄
  • XSLT 투토리얼

XML과 XQuery

  • XQuery는 SQL로 데이터베이스를 검색하는 것과 같은 역할을 한다.
  • XQuery는 XML데이터를 query할 수 있도록 설계되었다.
  • 예제 : SQL과 비슷하다.

for $x in doc("books.xml")/bookstore/book
where $x/price>30
order by $x/title
return $x/title

  • XQuery란
    • XML 데이터를 qurey 하기 위한 언어
    • SQL : 데이터베이스 = XQuery : XML
    • XQuery는 XPath 표현식을 기반으로 한다.
    • XQuery는 중요한 Database에서 지원한다.
    • XQuery는 W3C에서 추천한다. 
  • XQuery로 할 수 있는 일
    • Web서비스에서 정보추출에 사용
    • 요약 보고서 생성
    • XML 데이터를 XHTML로 변환
    • 웹 문서에서 관련 정보를 검색
  • W3C의 추천
    • XML, 네임스페이스, XSLT, XPath, XML Schema 등과 같은 W3C 표준과 호환된다.
    • XQuery 1.0은 2007년에 W3C의 추천으로 등록됨
  • XQuery Tutorial

XML 과 XLink. 그리고 XPointer

  • XLink는 XML 문서에서 하이퍼링크를 생성하는데 사용한다.
  • XML 문서중 모든 요소를 링크처럼 만들 수 있다.
  • XLink를 사용하면 링크가 문서 바깥에 존재한다.
  • WLink는 W3C에서 추천
  • XML 문서에 대한 XLink를 지원하는 브라우저는 없다.
    • 하지만, 중요 브라우저는 모두 SVG에서 XLink를 지원한다.
  • XLink 문법
    • HTML에서는 <a> 태그로 하이퍼링크를 만들지만, XML에서는 어떤 엘리먼트는 사용할 수 있으므로, 어떤 요소이름이 하이퍼링크가 될지 알 수 없다. 
    • 아래와 같은 방식으로 XLink를 만든다.
      • XLink기능을 사용하려면 XLink 네임스페이스를 선언해야 한다. 
        • xmlns:xlink="http://www.w3.org/1999/xlink"
        • xlink:type , xlink:href 속성은 XLink 네임스페이스에서 온 것이다.
        • xlink:type="symple" 을 사용하면 HTML 형식의 링크를 만들 수 있다.

<?xml version="1.0" encoding="UTF-8"?>
<homepages xmlns:xlink="http://www.w3.org/1999/xlink">
  <homepage xlink:type="simple" xlink:href="https://www.w3schools.com">Visit W3Schools</homepage>
  <homepage xlink:type="simple" xlink:href="http://www.w3.org">Visit W3C</homepage>
</homepages>

  • XPointer

    • XPointer를 사용하면 XML 문서 특정부분에 링크를 생성할 수 있다.
    • XPointer는 XPath 표현식을 사용하여 XML 문서를 방문한다.
    • XPointer는 W3C 추천.
  • XPointer의 브라우저 지원
    • XPointer를 지원하는 브라우저는 없다. 하지만, 다른 XML 언어에서는 사용된다.

XML Validator

  •  XML 문법 체크
    • root 요소가 반드시 존재해야 한다.
    • 모든 요소는 끝태그가 있어야 한다.
    • 모든 태그는 대소문자 구분
    • XML 요소들이 올바르게 중첩되어야 한다.
    • 속성 값은 반드시 "따옴표"로 묶어야 한다.
  • XML 의 경우 절대 오류가 있어서는 안된다!!!

XML DTD

  • 문법에 맞는 XML 문서는 "Well Formed"라고 함
  • DTD에 대해 검증받은 XML 문서는 "Well Formed" 하며 "Valid" 함 
    • 아래에서 !DOCTYPE 선언이 외부파일 Note.dtd를 참조하고 있음

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE note SYSTEM "Note.dtd">
<note>
    <to>Tove</to>
    <from>Jani</from>
    <body>Don't forget this weekend!</body>
</note>

<!DOCTYPE note                        ->root 엘리먼트
[
<!ELEMENT note (to, from, body)> -> note 요소는 반드시 to, from, body 요소를 포함해야 함
<!ELEMENT to (#PCDATA)>          ->to 요소는 "#PCDATA" 유형이어야 함. 
<!ELEMENT from (#PCDATA)>      -> #PCDATA란 parse-able text data (파싱 가능한 텍스트)
<!ELEMENT body (#PCDATA)>
]>

  • DOCTYPE은 특수문자를 정의하는데 사용할 수도 있음
    • <!ENTITY writer "Writer: Donald Duck."> 이렇게 정의한 뒤
    • <body> &writer;</body> 라고 사용하면 이 부분이 위 정의로 대체된다.
  • DTD/schema를 사용하면
    • 여러 그룹들이 표준 DTD를 사용하여 자료교환 가능
    • 외부에서 받은 데이터가 유효한지 확인할 수 있음
    • DTD로 자신의 데이터도 확인할 수 있음
  • 다만, 아직 추천사항도 아니고, XML의 요구조건도 아니므로, 구지 사용할 필요 없음.
  • DTD Tutorial 참고

XML Schema

  • XML Schema는 XML 문서의 구조를 설명함
  • XML Schema는 XML 기반으로 DTD 대체.

<xs:element name="note">                    -> note라는 요소를 정의함
<xs:complexType>                                -> note는 complex 유형임
    <xs:sequence>                                 -> 이 complex 유형은 요소들이 나열된 형태임
        <xs:element name="to" type="xs:string">         ->"to" 요소는 string 유형임
        <xs:element name="from" type="xs:string">
        <xs:element name="body" type="xs:string">
    </xs:sequence>
</xs:complexType>
</xs:element>

  • XML Schema는 DTD보다 훨씬 강력하다.
    • XML Schema 자체가 XML로 작성됨
    • 쉽게 추가할 수 있음
    • datatype을 지원함
    • 네임스페이스를 지원함
  • XML Schema를 사용해야 하는 이유
    • 해당 XML 파일에 대한 설명을 제공
    • 여러 그룹에서 표준으로 자료교환 가능
    • 데이터 검증이 가능
  • XML이 데이터유형을 지원한다는 것은??
    • 문서 내용을 쉽게 설명할 수 있다.
    • 데이터의 정확성을 쉽게 검증할 수 있다.
    • 데이터 제한사항을 쉽게 정의할 수 있다.
    • 다른 유형으로 쉽게 변환할 수 있다.
  • XML Schema는 XML 문법을 사용한다. 따라서
    • 새로운 언어를 배울 필요 없고
    • XML 에디터로 스키마 파일을 편집할 수 있고
    • XML parser로 스키마 파일을 해석할 수 있고
    • XML DOM으로 처리할 수 있으며
    • XSLT로 자료를 변환할 수 있다. 아주 좋은 점이 많다는 말씀. DTD를 쓰는 건 말이 안됨.
  • XML Schema Tutorial 을 참고할 것

XML Server

  • XML 파일은 단순한 텍스트 파일. 웹서버로 저장/생성하기 쉽다.
  • PHP로 생성하는 것도 어렵지 않고. (다만 header("Content-type: text/xml")로... 지정해야 한다.
  • asp로 생성하는 것도 물론 가능하고
  • Database로부터 생성할 수도 있다.

XML 예제 파일들


Posted by 푸른하늘이

댓글을 달아 주세요

기타/WWW2016. 5. 5. 00:30

현재... GPX 파일(XML 파일의 일종입니다.)을 해석해서 mySQL DB에 넣기 위해 고민 중에 있었습니다. 


제가 예전에 만들어 둔 프로그램에서는 그냥 javascript - ajax로 읽어 들인 후 사용했었습니다. 원래는 이 부분을 사용하려고 했습니다. 그런데, 이 기능을 이용할 경우, 한 개의 waypoint를 추출해서 배열을 만들고, ajax를 통해 PHP로 넘겨주면, PHP속에서 mySQL에 INSERT 시키는 방법을 사용해야 합니다. 그러면 당연히 터무니 없이 속도가 떨어질 것으로 예상됩니다.


그러던 중, W3C PHP 투토리얼 사이트에서 XML Parser에 관한 내용을 보게 되었습니다. 이걸 이용하면 그냥 PHP에서 XML(GPX파일)을 Parsing 한 후, 바로 MySQL로 넣어줄 수 있으니, 훨씬 작업이 간편할 것이라 생각했습니다.


PHP XML Parser는 두 가지 종류가 있습니다. 하나는 SimpleXML Parser이고, 다른 하나는 XML expat 입니다. SimpleXML은 말 그대로 아주 간단합니다. 그냥 파일이나 string을 지정하면, 전체를 구조체로 읽어 들이는 방식입니다. 그 다음엔 $xml->book[0]->title 과 같이 간단한 참조 방식으로 사용하면 됩니다. 


이에 비해 expat는 상당히 복잡합니다. expat는 이벤트 방식의 Parser라고 하고요, 예를 들어 아래와 같은 문장이 있다면...

<from>Jani</from>

이것을 다음과 같은 3개의 이벤트(사실은 4개의 이벤트)로 보내줍니다. 이런 방식으로 파일 전체가 이벤트로 처리되는 겁니다.

    • Start element: from
    • Start CDATA section, value: Jani
    • Close element: from

언뜻 보기에는 많이 복잡해 보였습니다. 그래서 포기할까 생각했습니다. 그런데, 파일의 크기가 클 수록 이 방식이 빠르고 편하다는 설명을 보고 시도해 보기로 했습니다. (simpleXML Parser의 경우 한꺼번에 메모리로 읽어 들이는 방식이라서 시스템에 따라서 문제가 발생할 수도 있답니다.)


expat Parser는 4개의 함수만 사용하면 거의 80%의 문제는 해결할 수 있다고 합니다. 제가 설명할 것도 바로 이 4가지 함수입니다. (일단 예제는 W3C의 예제를 이용하겠습니다.)


    • $parser=xml_parser_create(); // parser를 생성합니다.
    • xml_set_element_handler($parser,"start","stop"); // 생성한 Parser에 Start event handler 와 Stop event handler를 등록. 당연히 "start"/"stop" 은 함수명입니다.
    • xml_set_character_data_handler($parser,"char"); // Parser에 Data event handler를 등록합니다. "char"가 그 함수고요, 물론 이름은 다른 이름을 사용해도 됩니다.
    • xml_parse($parser,$data,feof($fp)); // parser를 실행합니다.

아래는 W3C 사이트에 있는 예제입니다. 빨간 표시를 한게 위에서 설명한 4개의 함수입니다.

xml_parser_create() 아래로 있는 start(), stop(), char()가 바로 event 핸들러입니다. 이 함수들 3개를 적당히 이용해서 데이터를 처리해주면 됩니다.


<?php
// Initialize the XML parser
$parser=xml_parser_create();

// Function to use at the start of an element
function start($parser,$element_name,$element_attrs) {
  switch($element_name) {
    case "NOTE":
    echo "-- Note --<br>";
    break;
    case "TO":
    echo "To: ";
    break;
    case "FROM":
    echo "From: ";
    break;
    case "HEADING":
    echo "Heading: ";
    break;
    case "BODY":
    echo "Message: ";
  }
}

// Function to use at the end of an element
function stop($parser,$element_name) {
  echo "<br>";
}

// Function to use when finding character data
function char($parser,$data) {
  echo $data;
}

// Specify element handler
xml_set_element_handler($parser,"start","stop");

// Specify data handler
xml_set_character_data_handler($parser,"char");

// Open XML file
$fp=fopen("note.xml","r");

// Read data
while ($data=fread($fp,4096)) {
  xml_parse($parser,$data,feof($fp)) or 
  die (sprintf("XML Error: %s at line %d", 
  xml_error_string(xml_get_error_code($parser)),
  xml_get_current_line_number($parser)));
}

// Free the XML parser
xml_parser_free($parser);
?>


이 파일을 사용해서 note.xml을 parsing하는 순서를 보여드리면...


<?xml version="1.0" encoding="UTF-8"?>

<note>

<to>Tove</to>

<from>Jani</from>

<heading>Reminder</heading>

<body>Don't forget me this weekend!</body>

</note>


먼저 첫줄 <?xml... 은 그냥 무시됩니다. 

두번째 줄 <note>가 들어오면, start event handler로 등록된 start() 함수가 호출되는데, 이때 $element_name에는 "NOTE"가 지정됩니다. 따라서 case 문 등을 사용해 이를 처리해 줍니다.


function start($parser,$element_name,$element_attrs) {

  switch($element_name) {

    case "NOTE":

    echo "-- Note --<br>";

    break;

    case "TO":

    ....


그 다음엔 data event handler가 호출됩니다. (<NOTE>의 경우에는 data에 공백 "  " 만 전달됩니다.)


function char($parser,$data) {

  echo $data;

}


그 다음엔 <to>Tove</to>가 처리될 차례죠. 이것도 비슷한 방식으로 아래와 같은 순서로 처리됩니다.


TO ->start event

Tove -> data event

TO ->end event

" " -> data event


이런 식으로 계속 이벤트를 처리하는 방식으로 처리하면 됩니다. 하나의 노드가 여러개의 이벤트로 나눠오기 때문에 데이터를 처리하는 게 복잡합니다만, 그래도 가능합니다.


====

아래는 제가 테스트해본 프로그램입니다. W3C의 books 예제파일 을 읽어들여서 이를 mySQL 에 삽입하는 예제입니다. 


여기에서 약간 중요한 점이 두 가지 있습니다. 위의 예제와는 달리, xml에 attribute가 있어서 이를 처리하는 부분이 추가되었는데요, 여기에서 each() 함수를 사용했습니다. 또 다른 하나는, mySQL에 입력할 때, prepared statement를 사용했습니다. $stmt=$conn->prepare()를 사용하여 미리 구문만 mySQL로 보내어 미리 최적화를 시킨 후, $stmt->execute();로 실행시켰습니다. 이렇게 해야 실행속도가 빨라진 답니다.



나머지는 아래의 코멘트를 참고하세요.


민, 푸른하늘


<?php


// mySQL DB 연결

require_once 'mySQL_login.php'; //이 파일은 각자의 환경에 맞게 준비해야 함

$conn = new mysqli($db_hostname,$db_username,$db_password, $db_database);

if($conn->connect_errno) {

    die("Connection failed: " . $connection->connect_error);

}


// Table이 미리 있다면 삭제함


$sql = "DROP TABLE IF EXISTS books";

if (!$conn->query($sql)) {

die("Error droping table: " . $conn->error);

}


// Table 생성

$sql = "CREATE TABLE `books` (

  `title` varchar(50) NOT NULL,

  `category` varchar(30) NOT NULL,

  `author` varchar(30) NOT NULL,

  `lang` varchar(10) NOT NULL,

  `year` smallint(6) NOT NULL,

  `price` float NOT NULL

) ENGINE=MyISAM";


if (!$conn->query($sql)) {

die("Error creating table: " . $conn->error);

}


// bind_para 에 사용되는 변수 초기화

$b_title = $b_author = $b_category = $b_lang = "";

$b_year = $b_price = 0;


// prepared statement 준비

$stmt = $conn->prepare("INSERT INTO books (title, author, category, lang, year, price) VALUES (?, ?, ?, ?, ?, ?)");

$stmt->bind_param("ssssid", $b_title, $b_author, $b_category, $b_lang, $b_year, $b_price);


// XML parser 생성

$parser=xml_parser_create();


// XML을 parsing 한 후 저장할 array 초기화

$num_books = 0;

$book = array("TITLE"=>"", "AUTHOR"=>"", "CATEGORY" => "" , "LANG" => "", "YEAR" => 0, "PRICE" => 0);

$index = "";


// Element Start event handler. 여기에서는 $index만 저장함.

function start($parser,$element_name,$element_attrs) {


    global $index,$book;

    

    switch($element_name) {

      case "BOOK":

          break;

      case "TITLE":

          $index = "TITLE";

          break;

      case "AUTHOR":

          $index = "AUTHOR";

          break;

      case "YEAR":

          $index = "YEAR";

          break;

      case "PRICE":

          $index = "PRICE";

          break;

    }


    // attribute의 경우엔 each로 처리함. 

    if(!empty($element_attrs)){

        $temp = each($element_attrs);

        $book[$temp[0]] = $temp[1];

    }

}


// Element Stop event handler. BOOK이 끝나는 시점에서 $stmt를 실행하여 $book array에 들어 있는 내용을 mySQL로 저장. 

function stop($parser,$element_name) {

    

    global $num_books, $book, $index, $stmt;

    global $b_title, $b_author, $b_category,$b_lang, $b_year, $b_price;

    $b_title = $book['TITLE'];

    $b_author = $book['AUTHOR'];

    $b_category = $book['CATEGORY'];

    $b_lang=$book['LANG'];

    $b_year = $book['YEAR'];

    $b_price = $book['PRICE'];

    

    if($element_name == "BOOK") {

          $num_books++;

          $stmt->execute();

          print_r($book);

          echo "<br>";

    }

}


// Element Data event handler. 실제의 값을 $book 배열에 저장.

function char($parser,$data) {

  global $book, $index;

  

  if($index != "") {

    $book[$index] = $data;

    $index = "";

  }

}


// Specify element handler

xml_set_element_handler($parser,"start","stop");


// Specify data handler

xml_set_character_data_handler($parser,"char");


// Open XML file

$fp=fopen("books.xml","r");


// Read data. feof()을 만날 때까지 계속 파일을 읽어들이고 parsing 함.

while ($data=fread($fp,4096)) {

  xml_parse($parser,$data,feof($fp)) or 

    die (sprintf("XML Error: %s at line %d", 

  xml_error_string(xml_get_error_code($parser)), xml_get_current_line_number($parser)));

}


// Free the XML parser

xml_parser_free($parser);

?>




Posted by 푸른하늘이

댓글을 달아 주세요

기타/WWW2014. 6. 26. 11:45

다섯번째는 XML. 


XML Expat Parser


  • XML Parser는 두가지 종류가 있음
    • Tree 기반 parser : XML 문서를 트리구조로 변환, 문서 전체를 분석하고, 트리의 각 요소에 접근. DOM(Document Object Model)
    • Event 기반 parser : XML 문서를 이벤트의 연속으로 봄. 특정 이벤트가 발생하면 그와 연결된 함수를 호출하는 방식. 문서의 구조보다 내용에 집중. 더 빠르다. XML 구조에 문제가 있어도 문제없음. 
  • Expat Parser는 Event 기반 parser임. PHP 웹 어플에 최적
  • Expat Parser는 PHP 에 내장되어 있음


XML DOM


<!--?xml version="1.0" encoding="UTF-8"?-->

<from>Jani</from>

  • 레벨 1 : XML document
  • 레벨 2 : Root element : <from>
  • 레벨 3 : text element : "Jani"


SimpleXML


  • PHP5에서 새롭게 등장
  • XML 요소의 이름과 text를 간단하게 추출
  • 코드를 간단하게 짤 수 있음
  • XML 문서를 객체로 변환함
    • 요소는 SimpleXMLElement 객체의 속성(attribute)로 변환됨. 어느 레벨에 여러개의 요소가 있을 경우 배열에 들어가게 됨
    • 속성은 associative 배열로 접근가능 (index가 attribute의 name)
    • 요소의 text는 문자열로 변환됨. 여러개의 text 노드가 있을 경우, 순서대로 배열됨
  • SimpleXML은 XML파일로부터 데이터를 읽거나 추출하거나, 텍스트 노드/속성을 편집할 때 빠르고 간단하게 수행가능
  • 복잡한 XML의 경우, Expat이나 DOM을 사용하는 것이 나음


















Posted by 푸른하늘이

댓글을 달아 주세요