Znění hlášky v jednotlivých parserech
Pro & hlásí libxml2 (PHP, xmllint) EntityRef: expecting ';' nebo
xmlParseEntityRef: no name, Java The reference to entity "…" must end with the
';' delimiter, Python not well-formed (invalid token), .NET An error occurred
while parsing EntityName:
Která hláška se objeví, záleží na tom, co za & následuje. Za
&barva= parser přečte název entity barva a chybí mu středník.
Za & s mezerou nenajde žádný název.
Příčiny a opravy
Znak & v adrese URL
<?xml version="1.0" encoding="UTF-8"?>
<produkt>
<url>https://example.cz/detail?id=42&barva=cerna</url>
</produkt> <?xml version="1.0" encoding="UTF-8"?>
<produkt>
<url>https://example.cz/detail?id=42&barva=cerna</url>
</produkt>
Nejčastější případ: adresa s parametry v produktovém feedu, sitemapě nebo RSS. V XML musí
být každý & v URL zapsaný jako &. Program, který XML
čte, dostane zpátky původní adresu s &.
Samotný znak & v textu
<?xml version="1.0" encoding="UTF-8"?>
<firma>Novák & syn s.r.o.</firma> <?xml version="1.0" encoding="UTF-8"?>
<firma>Novák & syn s.r.o.</firma>
Názvy firem, produktů a textů od uživatelů. Stejně se opraví &.
Znak < v textu
<?xml version="1.0" encoding="UTF-8"?>
<podminka>cena < 1000</podminka>
Za < parser čeká název elementu. Mezera nebo číslice název začínat nesmí,
proto libxml2 hlásí StartTag: invalid element name a Java obecné The content of
elements must consist of well-formed character data or markup. Delší text se spoustou
takových znaků (kód, HTML) se hodí zabalit do <![CDATA[ … ]]>.
HTML entita, kterou XML nezná
<?xml version="1.0" encoding="UTF-8"?>
<cena>1 290 Kč</cena>
XML zná jen pět pojmenovaných entit: &, <,
>, " a '. HTML entity jako
, © nebo – v něm
neexistují, dokud je nedeklaruje DTD. Nahraď je číselnou entitou
(  pro nezlomitelnou mezeru) nebo přímo znakem v UTF-8.
Které znaky se musí escapovat
| Znak | V textu elementu | V hodnotě atributu |
|---|---|---|
| & | & (vždy) | & (vždy) |
| < | < (vždy) | < (vždy) |
| > | smí zůstat, kromě dvojice ]]> (pak >) | smí zůstat |
| " | smí zůstat | ", když je hodnota v uvozovkách "…" |
| ' | smí zůstat | ', když je hodnota v apostrofech '…' |
Jak chybu najít
-
Hledej v souboru regulárním výrazem
&(?!(amp|lt|gt|quot|apos|#[0-9]+|#x[0-9a-fA-F]+);). Najde každý&, který nezačíná platnou entitu. - Validátor neescapovaný znak nejen najde, ale nabídne i opravu
na
&. - Opravuj zdroj, ne výsledný soubor: pokud feed vzniká ze šablony, chyba se vrátí při dalším exportu.
Oprava v kódu
Nejjistější je XML vůbec neskládat spojováním řetězců. Knihovna, která dokument sestaví ze stromu, escapuje text i atributy sama. Když řetězec skládat musíš, použij escapovací funkci pro XML, ne pro HTML ani URL:
from xml.sax.saxutils import escape
escape("cena < 1000 & více") # 'cena < 1000 & více'
# Lepší je nechat escapování na knihovně, která XML sestavuje:
import xml.etree.ElementTree as ET
url = ET.Element("url")
url.text = "https://example.cz/detail?id=42&barva=cerna"
ET.tostring(url, encoding="unicode")
# '<url>https://example.cz/detail?id=42&barva=cerna</url>' echo htmlspecialchars($text, ENT_XML1 | ENT_QUOTES, 'UTF-8');
$dom = new DOMDocument('1.0', 'UTF-8');
$url = $dom->createElement('url');
$url->appendChild($dom->createTextNode($text)); // escapuje sám
$dom->appendChild($url); Element url = doc.createElement("url");
url.setTextContent("https://example.cz/detail?id=42&barva=cerna");
// Transformer při zápisu vypíše & var url = new XElement("url", "https://example.cz/detail?id=42&barva=cerna");
// <url>https://example.cz/detail?id=42&barva=cerna</url>
SecurityElement.Escape("cena < 1000 & více"); // cena < 1000 & více const doc = document.implementation.createDocument(null, 'produkt', null);
const url = doc.createElement('url');
url.textContent = 'https://example.cz/detail?id=42&barva=cerna';
doc.documentElement.appendChild(url);
new XMLSerializer().serializeToString(doc);
Pozor na dvojí escapování: když text už obsahuje & a projde escapováním
znovu, vznikne &amp; a čtenář uvidí doslova &.
Související
- Kódování znaků a entity v kapitole Jak funguje XML.
- XML feed pro Heureku a Zboží — URL s parametry ve feedu.
- DTD — jak deklarovat vlastní entity.
- Přehled všech chybových hlášek.