공간정보/표준

XML 네임스페이스의 이해

하늘이푸른오늘 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