Jmenné prostory v XML (namespaces)

Jmenné prostory řeší problém, který nastane, jakmile se v jednom dokumentu potkají značky ze dvou různých slovníků. Kapitola vysvětluje xmlns, prefixy, výchozí jmenný prostor a chyby, na které narazí skoro každý.

Autor: Aktualizováno

Problém: stejné jméno, jiný význam

XML si nechává názvy značek na autorovi, takže se snadno stane, že dva slovníky použijí stejné jméno pro něco úplně jiného. Nábytkářský katalog má <table> pro stůl, HTML pro tabulku:

<!-- nabídka nábytku -->
<table>
  <name>Jídelní stůl</name>
  <width>160</width>
</table>

<!-- HTML tabulka -->
<table>
  <tr><td>Jídelní stůl</td></tr>
</table>

Dokud má každý slovník svůj soubor, nic se neděje. Jakmile je ale potřeba vložit HTML popis do katalogu, program už nepozná, který <table> je který.

Řešení: jmenný prostor a prefix

Jmenný prostor (namespace) je identifikátor slovníku ve tvaru URI. Atributem xmlns:prefix="URI" se URI přiřadí krátký prefix, kterým se pak označí jména elementů:

<n:nabidka xmlns:n="https://example.cz/nabytek"
           xmlns:h="http://www.w3.org/1999/xhtml">
  <n:table>
    <n:name>Jídelní stůl</n:name>
  </n:table>
  <h:table>
    <h:tr><h:td>Jídelní stůl</h:td></h:tr>
  </h:table>
</n:nabidka>

Teď je jednoznačné, že n:table patří do nábytkového slovníku a h:table do XHTML. Parser každý element chápe jako dvojici {URI} + lokální jméno, tedy {https://example.cz/nabytek}table a {http://www.w3.org/1999/xhtml}table.

URI se nikam nenačítá. Je to jen jedinečný řetězec; na adrese nemusí nic být. Používají se URL, protože doménu vlastní konkrétní autor, a kolize je tak nepravděpodobná. Porovnává se znak po znaku — http:// a https:// nebo lomítko navíc na konci jsou různé jmenné prostory.

Výchozí jmenný prostor

Psát prefix ke každé značce je zdlouhavé, proto existuje výchozí jmenný prostor deklarovaný atributem xmlns="URI" bez prefixu. Platí pro element, na kterém je deklarovaný, i pro všechny jeho potomky bez prefixu. Tak je napsaná třeba každá mapa webu:

sitemap.xml
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>https://www.example.cz/</loc>
  </url>
</urlset>

Všechny tři elementy — urlset, url i loc — jsou v jmenném prostoru sitemap, přestože nemají prefix. Na tom, jaký prefix (nebo žádný) autor zvolí, nezáleží; dva dokumenty s různými prefixy a stejným URI jsou z pohledu jmenných prostorů totožné.

Platnost deklarace

Deklarace platí od elementu, na kterém je zapsaná, pro celý jeho podstrom. Uvnitř ji lze přepsat jinou deklarací a výchozí jmenný prostor lze zrušit prázdným xmlns="":

<katalog xmlns="https://example.cz/katalog">
  <produkt kod="A1">
    <nazev>Hrnek</nazev>
    <popis xmlns="http://www.w3.org/1999/xhtml">
      <p>Keramický hrnek <b>0,3 l</b></p>
    </popis>
  </produkt>
  <poznamka xmlns="">bez jmenného prostoru</poznamka>
</katalog>
  • katalog, produkt a nazev jsou v prostoru katalogu,
  • popis, p a b jsou v prostoru XHTML,
  • poznamka není v žádném jmenném prostoru.

Atributy a jmenné prostory

Tady chybuje skoro každý: výchozí jmenný prostor se na atributy nevztahuje. Atribut bez prefixu nepatří do žádného jmenného prostoru; chápe se jako vlastnost svého elementu. Do jmenného prostoru se atribut dostane jen s prefixem:

<k:produkt xmlns:k="https://example.cz/katalog"
           xmlns:x="https://example.cz/export"
           kod="A1" x:priorita="vysoka"/>

Atribut kod je bez jmenného prostoru, x:priorita patří do prostoru exportu. Typické atributy s prefixem jsou xml:lang, xml:space nebo xsi:schemaLocation.

Prefixy xml a xmlns jsou vyhrazené. Prefix xml je vždy svázaný s http://www.w3.org/XML/1998/namespace a nemusí se deklarovat.

Jmenné prostory v XPath a v kódu

Nejčastější dotaz v diskusích zní: „proč mi XPath /urlset/url/loc nic nenajde?“ V XPath 1.0 jméno bez prefixu vždy znamená element bez jmenného prostoru. Elementy sitemapy ale v prostoru jsou (výchozím), takže se výrazu neshodují. Diagnostiku a kód pro jednotlivé jazyky shrnuje stránka XPath nic nevrací.

Řešením je v programu zaregistrovat prefix (třeba s pro URI sitemap) a psát /s:urlset/s:url/s:loc, nebo se jmenným prostorům vyhnout funkcí /*[local-name()='urlset']. XPath 2.0 a novější umožňují nastavit výchozí jmenný prostor pro dotazy. Podrobnosti v kapitole XPath.

Jmenné prostory běžných formátů

URI se musí opsat přesně, včetně protokolu a lomítek:

FormátURI jmenného prostoru
XHTMLhttp://www.w3.org/1999/xhtml
SVGhttp://www.w3.org/2000/svg
XSLThttp://www.w3.org/1999/XSL/Transform
XML Schemahttp://www.w3.org/2001/XMLSchema
XML Schema instance (xsi)http://www.w3.org/2001/XMLSchema-instance
Atomhttp://www.w3.org/2005/Atom
Sitemaphttp://www.sitemaps.org/schemas/sitemap/0.9
SOAP 1.1 obálkahttp://schemas.xmlsoap.org/soap/envelope/

QName, NCName a rezervované prefixy

NCName je XML název bez dvojtečky. QName je buď NCName, nebo dvojice prefix:lokální-název. Rozšířený název elementu tvoří URI prostoru a lokální část; prefix je jen zkratka platná v kontextu.

a:polozka a b:polozka se stejným URI označují stejný rozšířený název. Stejný prefix s jiným URI naopak stejný význam nezaručuje. URI se porovnává jako řetězec, ne po stažení nebo normalizaci adresy.

Prefix xml je rezervovaný pro http://www.w3.org/XML/1998/namespace, xmlns pro deklarace prostorů. Atributy xml:* nevyžadují ruční deklaraci prefixu xml. Výchozí prostor se nevztahuje na neprefixované atributy.

Dva různé atributy id
<r xmlns="urn:r" id="1" xmlns:a="urn:a" a:id="2"/>

Atribut id nemá prostor, a:id má prostor urn:a. Oba jsou povolené. Dva atributy se stejným URI a lokálním názvem by byly chyba, i kdyby používaly různé prefixy.