Пространства имен и атрибуты XML
Я пытаюсь понять, как пространства имен работают в XML. Когда у меня есть такой элемент, как foo: bar, у атрибутов часто не будет пространств имен. Но иногда они будут. Находятся ли атрибуты в пространстве имен элемента, даже если было объявлено пространство имен по умолчанию? Просматривая xsd для xhtml, кажется, что атрибуты являются частью схемы и должны находиться в пространстве имен для xhtml, но они никогда не представляются таким образом...
4 ответа
В большинстве случаев атрибуты не будут находиться ни в одном пространстве имен. Спецификация пространства имен говорит (выделено мое):
Объявление пространства имен по умолчанию применяется ко всем нефиксированным именам элементов в пределах его области. Объявления пространства имен по умолчанию не применяются непосредственно к именам атрибутов; Интерпретация нефиксированных атрибутов определяется элементом, на котором они появляются.
Есть причина, по которой большинство словарей XML используют атрибуты без пространств имен:
Если у ваших элементов есть пространство имен, а эти элементы имеют атрибуты, тогда не должно быть путаницы: атрибуты принадлежат вашему элементу, который принадлежит вашему пространству имен. Добавление префикса пространства имен к атрибутам сделает все более многословным.
Так почему же существуют атрибуты пространства имен?
Потому что некоторые словари выполняют полезную работу, в основном, с атрибутами, и могут делать это, когда смешиваются с другими словарями. Самый известный пример - XLink.
Наконец, W3C XML Schema имеет слишком простой способ (<schema attributeFormDefault="qualified">
) объявления ваших атрибутов как находящихся в пространстве имен, вынуждая вас префиксировать их в ваших документах, даже если вы используете пространство имен по умолчанию.
Примеры для иллюстрации с использованием нотации Clark, где префикс пространства имен заменяется URL-адресом пространства имен в фигурных скобках:
<bar xmlns:foo="http://www.foo.com/"
foo:baz="baz"
qux="qux"/>
<bar xmlns="http://www.foo.com/" xmlns:foo="http://www.foo.com/"
foo:baz="baz"
qux="qux"/>
<foo:bar xmlns="http://www.foo.com/" xmlns:foo="http://www.foo.com/"
foo:baz="baz"
qux="qux"/>
является
<{}bar
{http://www.foo.com/}baz="baz"
{}qux="qux"/>
<{http://www.foo.com/}bar
{http://www.foo.com/}baz="baz"
{}qux="qux"/>
<{http://www.foo.com/}bar
{http://www.foo.com/}baz="baz"
{}qux="qux"/>
Есть кое-что, связанное с этим атрибутом / предметным пространством имен, которое мне понадобилось некоторое время, чтобы понять сегодня, когда я работал над XSD. Я поделюсь с вами этим опытом на случай, если у кого-нибудь возникнут те же проблемы.
В Документе Схемы, над которым я работал, было несколько глобальных атрибутов, на которые ссылались некоторые элементы. Для упрощения здесь давайте предположим, что этот XSD, о котором я говорю, был о клиенте.
Давайте назовем один из этих глобальных атрибутов Id. И корневой элемент с его помощью клиента
Моя XSD-декларация выглядела так:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns="http://schemas.mycompany.com/Customer/V1"
targetNamespace="http://schemas.mycompany.com/Customer/V1"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
Моя декларация атрибута Id выглядела так:
<xs:attribute name="Id" type="xs:positiveInteger"/>
И мой элемент Customer использовал атрибут следующим образом:
<xs:element name="Customer">
<xs:complexType>
<xs:attribute ref="Id" use="required"/>
<!-- some elements here -->
</xs:complexType>
</xs:element>
Теперь, допустим, я хотел объявить XML-документ Customer следующим образом:
<?xml version="1.0" encoding="utf-8"?>
<Customer Id="1" xmlns="http://schemas.mycompany.com/Customer/V1">
<!-- ... other elements here -->
</Customer>
Я обнаружил, что не могу: когда атрибут объявлен глобально, он не находится в том же пространстве имен, что и элемент, который на него ссылается.
Я выяснил, что единственное решение с таким определенным XSD - это объявление пространства имен дважды: один раз без префикса, чтобы сделать его пространством имен по умолчанию для элементов, и один раз с префиксом, чтобы использовать его с атрибутами. Вот как это выглядело бы:
<?xml version="1.0" encoding="utf-8"?>
<Customer cus:Id="1" xmlns="http://schemas.mycompany.com/Customer/V1"
xmlns:cus="http://schemas.mycompany.com/Customer/V1">
<!-- ... other elements here -->
</Customer>
Это настолько непрактично, что я просто решил избавиться от всех глобальных атрибутов и объявить их локально. Что в случае с примером, который я привел здесь, выглядело бы так:
<xs:element name="Customer">
<xs:complexType>
<xs:attribute name="Id" type="xs:positiveInteger" use="required"/>
<!-- some elements here -->
</xs:complexType>
</xs:element>
Мне было трудно найти ссылки на то, о чем я говорю, здесь, в сети. В конце концов я нашел этот пост на форуме Stylus XSD, где парень по имени Стин Леманн предложил либо объявить атрибут локально, либо объявить его в группе атрибутов.
"так что само объявление атрибута больше не является глобальным"
Это последнее решение имеет "хакерский" вкус, поэтому я просто решил придерживаться первого решения и объявить все свои атрибуты локально.
Читайте в разделе 6.1. Определение пространства имен и 6.2 По умолчанию в пространстве имен на w3c.
В принципе:
Область объявления пространства имен, объявляющего префикс, простирается от начала начального тега, в котором он появляется, до конца соответствующего конечного тега
Тем не менее, текст здесь, кажется, не объясняет, означает ли a a foo: a или пространство имен по умолчанию в контексте. Я бы предположил, что это не относится к foo: a, а скорее к пространству имен документов по умолчанию a. Учитывая эту цитату как минимум:
Такое объявление пространства имен применяется ко всем именам элементов и атрибутов в пределах его области действия, префикс которых совпадает с указанным в объявлении.
То есть. пространство имен "foo:" применяется только к элементам с префиксом foo: