Znění hlášky v jednotlivých parserech
libxml2 (PHP, xmllint, lxml) hlásí Extra content at the end of the document, Python a Firefox junk after document element, Java The markup in the document following the root element must be well-formed a .NET There are multiple root elements:
Pozice v hlášce ukazuje na začátek obsahu navíc, tedy na první znak za uzavírací značkou kořenového elementu. Chyba samotná ale vznikla tam, kde se dokument skládal dohromady.
Příčiny a opravy
Dva kořenové elementy
<?xml version="1.0" encoding="UTF-8"?>
<objednavka cislo="2026-117"/>
<objednavka cislo="2026-118"/> <?xml version="1.0" encoding="UTF-8"?>
<objednavky>
<objednavka cislo="2026-117"/>
<objednavka cislo="2026-118"/>
</objednavky> Typicky vznikne, když program zapisuje záznamy v cyklu a zapomene na obalový element. XML není formát „jeden záznam na řádek“ — seznam musí mít společného rodiče. Pokud opravdu potřebuješ záznamy za sebou bez kořene (například pro postupné připisování do logu), jde o jiný formát a každý záznam musíš parsovat zvlášť.
Text za kořenovým elementem
<?xml version="1.0" encoding="UTF-8"?>
<objednavky>
<objednavka cislo="2026-117"/>
</objednavky>
Export dokončen: 1 záznam <?xml version="1.0" encoding="UTF-8"?>
<objednavky>
<objednavka cislo="2026-117"/>
</objednavky> Za kořenem smí být jen komentáře, instrukce pro zpracování a bílé znaky. Text sem obvykle dostane skript, který po XML vypíše ještě hlášení o průběhu. Java tu hlásí jinou větu (Content is not allowed in trailing section), .NET obecné Data at the root level is invalid.
Dva soubory spojené za sebe
<?xml version="1.0" encoding="UTF-8"?>
<objednavka cislo="2026-117"/>
<?xml version="1.0" encoding="UTF-8"?>
<objednavka cislo="2026-118"/> <?xml version="1.0" encoding="UTF-8"?>
<objednavky>
<objednavka cislo="2026-117"/>
<objednavka cislo="2026-118"/>
</objednavky>
Dva celé soubory spojené za sebe (cat a.xml b.xml, export po částech). libxml2
a Java tu nezačnou kořenem, ale druhou deklarací: XML declaration allowed only at the
start of the document a The processing instruction target matching
"[xX][mM][lL]" is not allowed — stejně jako u obsahu
před prologem. Soubory je potřeba sloučit jako XML, ne jako text.
Jak chybu najít
- Otevři soubor na řádku z hlášky. Řádek nad ním obvykle končí uzavírací značkou kořene.
- Když ti připadá, že kořen končí až na konci souboru, hledej jeho uzavírací značku uprostřed dokumentu (třeba zkopírovanou s kusem jiného souboru). Ta kořen ukončí a všechno za ní je pro parser obsah navíc.
- Validátor zvýrazní řádek s chybou a formátování odsadí dokument tak, že je vidět, kde kořen končí.
Oprava v kódu
Soubory neslepuj jako text. Načti každý parserem a jejich kořenové elementy vlož pod nový společný kořen:
import xml.etree.ElementTree as ET
# Více souborů pod jeden společný kořen
merged = ET.Element("objednavky")
for path in ["a.xml", "b.xml"]:
merged.append(ET.parse(path).getroot())
ET.ElementTree(merged).write("vse.xml", encoding="UTF-8", xml_declaration=True)
# Úryvek bez deklarace (několik elementů za sebou) obal dočasným kořenem
root = ET.fromstring(f"<objednavky>{fragment}</objednavky>") $merged = new DOMDocument('1.0', 'UTF-8');
$root = $merged->appendChild($merged->createElement('objednavky'));
foreach (['a.xml', 'b.xml'] as $path) {
$part = new DOMDocument();
$part->load($path);
$root->appendChild($merged->importNode($part->documentElement, true));
}
$merged->save('vse.xml');
Dočasný kořen kolem úryvku funguje jen tehdy, když úryvek nemá vlastní deklaraci
<?xml … ?> ani DOCTYPE.
Související
- Pravidla dobře formovaného dokumentu v kapitole Jak funguje XML.
- Opening and ending tag mismatch — neuzavřené, překlepnuté a křížené značky.
- Přehled všech chybových hlášek.