Коротко о пространствах имен (XML Namespaces)

Введение

При создании XML-документа мы можем столкнуться с тем, что разные по смыслу элементы будут иметь одинаковое имя. Вы можете увидеть пример в статье «10 главных ошибок RSS» в пункте 5 «Неправильное расширение RSS».

Разберём пример, явно «притянутый за уши», зато простой для понимания. Нам необходимо сделать выборку из двух таблиц базы данных, касающихся творчества некоего музыкального коллектива и сформировать каталог в виде XML-документа. В одной таблице базы данных содержится информация об аудио записях коллектива, в другой — информация о книгах посвященных его творчеству. По какой-то причине (непонятно какой, но очень важной), и описание аудио записей и описание книг должно содержаться в элементе «item». По той же причине, и названия записей и названия книг должны содержаться в элементе «title».

В результате получаем, что-то вроде этого:

<catalog>
    <item>
        <title />
    </item>
    <item>
        <title />
    </item>
</catalog>

Налицо конфликт имен, так как сложно определить, какой вид данных содержит каждый из элементов «item» и «title». Первый блок «item» относится к дискографии и элемент «title» содержит название диска. Второй блок «item» относится к библиографии и элемент «title» содержит название книги. Для предотвращения подобного конфликта нам надо разделить эти группы логически. Делается это заданием пространства имен: одни элементы относятся к имени «music», другие — к имени «book». Для объявления пространствa имeн используeтся атрибут имя которого состоит из зарезервированного слова «xmlns», после которого следует двоеточие и, собстветнно, само имя:

xmlns:music = "http://ininfo.biz/music"

Первый вопрос, который возникает, что использовать в качестве значения атрибута «xmlns»? Для того, чтобы обеспечить уникальность пространства имен надо использовать какой-либо URI (Uniform Resource Identifier, Унифицированный Идентификатор Ресурса), проще говоря — уникальную строку, которая будет однозначно идентифицировать данный элемент*. Многие используют в качестве идентификатора URL, так как имена доменов, которые используются в URL являются уникальными. Кроме того, вряд ли кто-нибудь будет использовать адрес «http://ininfo.biz/book» кроме его владельца, так что конфликт исключен.

Пространства имен для элементов

Указание на то, к какому пространству имен относится тот или иной элемент, записывается перед началом имени элемента с разделителем в виде двоеточия:

<music:title />

Исходя из вышеизложенного, в принципе, можно объявить пространство имен для каждого элемента, который используется в документе:

<catalog>
    <music:item xmlns:music = "http://ininfo.biz/music">
        <music:title xmlns:music = "http://ininfo.biz/music" />
    </music:item xmlns:music = "http://ininfo.biz/music">
    <book:item xmlns:book = "http://ininfo.biz/book">
        <book:title xmlns:book = "http://ininfo.biz/book" />
    </book:item xmlns:book = "http://ininfo.biz/book">
</catalog>

Согласитесь, это не самый лучший вариант, так как во-первых, надо набирать много текста; во-вторых, такой код сложно читать; в-третьих, легко наделать ошибок. Можно поступить другим образом используя правило:

Пространство имен объявленное для какого-либо элемента, является таковым для всех вложенных в него элементов, если для них не объявлено других пространств имен.

<music:catalog xmlns:music = "http://ininfo.biz/music">
    <music:item>
        <music:title />
    </music:item>
    <book:item xmlns:book = "http://ininfo.biz/book">
        <book:title />
    </book:item>
</music:catalog>

Можно поступить еще проще — объявить все пространства имен за один раз в корневом элементе:

<music:catalog 
    xmlns:music = "http://ininfo.biz/music"
    xmlns:book = "http://ininfo.biz/book">
    <music:item>
        <music:title />
    </music:item>
    <book:item>
        <book:title />
    </book:item>
</music:catalog>

Однако надо помнить, что идентификатором пространства имен является значение атрибута «xmlns», а не его название-префикс. В следующем примере все элементы принадлежат одному пространству(значение атрибута равно «http://ininfo.biz/group») хотя и имеют разные имена-префиксы(«music» и «book»):

<music:catalog 
    xmlns:music = "http://ininfo.biz/group"
    xmlns:book = "http://ininfo.biz/group">
    <music:item>
        <music:title />
    </music:item>
    <book:item>
        <book:title />
    </book:item>
</music:catalog>

Допускается и обратное — элементы имеют различные пространства имен, но используют одинаковые имена-префиксы:

<catalog>
    <group:item xmlns:group = "http://ininfo.biz/music">
        <group:title />
    </group:item>
    <group:item xmlns:group = "http://ininfo.biz/book">
        <group:title />
    </group:item>
</catalog>

Можно обойтись и без имен-префиксов. Для этого надо задать пространство имен по-умолчанию. В этом случае, данное пространство будет использоваться для элемента, в котором он встречается и для всех его дочерних(вложенных) элементов:

<catalog>
    <item xmlns = "http://ininfo.biz/music">
        <title />
    </item>
    <item xmlns = "http://ininfo.biz/book">
        <title />
    </item>
</catalog>

Для того, чтобы отменить пространство имен заданное по-умолчанию, необходимо присвоить атрибуту «xmlns» значение пустой строки:

<catalog 
    xmlns = "http://ininfo.biz/group">
    <item>
        <title />
    </item>
    <item xmlns = "">
        <title />
    </item>
</catalog>

Пространства имен для атрибутов элементов

Также как и элементы, к заданному пространству имен могут быть отнесены и их атрибуты:

<music:catalog 
    xmlns:music = "http://ininfo.biz/music"
    xmlns:book = "http://ininfo.biz/book">
    <music:item music:number="10">
        <music:title book:numref="20" />
    </music:item>
    <book:item book:number="20">
        <book:title music:numref="10" />
    </book:item>
</music:catalog>

Однако пространство имен по-умолчанию на атрибуты не распостраняется. Если у атрибута не указан префикс, то он не принадлежит ни к одному пространству имен:

<music:catalog 
    xmlns:music = "http://ininfo.biz/music"
    xmlns:book = "http://ininfo.biz/book">
    <music:item music:number="10">
        <music:title numref="20" />
    </music:item>
    <book:item book:number="20">
        <book:title numref="10" />
    </book:item>
</music:catalog>

Вышеизложенное верно и для случая, когда пространство имен задано для элемента, к которому принадлежит атрибут, например:

<music:item number="10" 
    xmlns:music = "http://ininfo.biz/music">

Чтобы совсем запутаться, можно отметить, что объявление пространства имен действует в рамках того элемента, в котором оно встречается:

<root xmlns:primer = "http://ininfo.biz/one"> 
    <primer:el1 xmlns:primer = "http://ininfo.biz/two"> 
        <primer:el2 /> 
        <el3 xmlns:primer = "http://ininfo.biz/three"> 
            <primer:el2 />
        </el3> 
    </primer:el1> 
    <primer:el2 /> 
</root>

Возможно, эта статья будет дополнена. Поэтому, продолжение следует и следите за обновлениями.


* У гражданина РФ уникальным идентификатором может считаться его ИНН. Не номер паспорта — паспорт трижды меняется и, в случае потери, выписывается новый.