Umělá složitost souborů OOXML (příklad XLSX)

27.9.2025 Italo Vignoli (překlad Žofie Miller)
Originál článku: https://blog.documentfoundation.org/blog/2025/09/27/the-artificial-complexity-of-ooxml-files-the-xlsx-case/

Příspěvek publikovaný 18. července 2025 vysvětloval, proč je XML schéma, které používají soubory Microsoft 365 (dříve Microsoft Office) uměle složité. Jde o nástroj pro udržení uživatelů, protože je neviditelné a bez hlubší analýzy prakticky neodhalitelné. Pravděpodobně proto ho převzala různá IT média, jelikož srozumitelně vysvětloval problém, kterému čelí každý, aniž by měl nástroje ho řešit.


Některé z těchto článků vyvolaly debatu mezi těmi, kteří mou tezi podporovali, a těmi, kteří hájili Microsoft, skutečné šampiony uzamčených uživatelů, kteří tvrdili, že komplexita XML schématu není umělá, ale odráží složitost samotných dokumentů.


Tato složitost souvisí s různými faktory, jako je velikost (počet stran), struktura (text, tabulky, grafy a obrázky), správa obsahu (zadávání dat více lidmi a systémy) a přizpůsobení pomocí metadat. Tyto faktory ovlivňují správu, klasifikaci i ukládání dokumentu.



Rozdílné přístupy ke správě komplexity v ODF a OOXML


Formáty ODF a OOXML však tuto komplexitu řeší zcela odlišně. V prvním případě se XML schéma snaží zjednodušit práci vývojářům i uživatelům tak, aby byly splněny požadavky obou stran. Vývojáři mají k dispozici všechny nástroje pro popis složitosti dokumentu a uživatelé mohou rozlišit mezi popisnými prvky a obsahem, protože jsou téměř vždy oddělené. Obsah má navíc konzistentní syntaxi v rámci celého dokumentu.


V druhém případě XML schéma nijak neusnadňuje práci vývojářům a zároveň komplikuje práci uživatelům tím, že všechny prvky – popis i obsah – míchá dohromady bez zjevné logiky. Tím se stává jejich rozlišení obtížné až nemožné.


Komplexita formátu OOXML souvisí s jeho návrhem a byla záměrně vytvořena tak, aby bylo pro vývojáře mimo ekosystém Microsoftu obtížné tento formát implementovat. Problémy s kompatibilitou způsobuje doslova „labyrint“ tagů používaných i pro nejjednodušší obsah, což váže uživatele na ekosystém Microsoftu, toto je první příklad uzamčení uživatelů založeného na standardu.


K tomu se přidává široké používání komplikovaných popisů, například ty u datumů, které souvisejí s chybou jež vznikla již ve Visicalcu a je dodnes přítomna v Excelu, 67 let po jejím objevení. Dále pak svévolné rozdělování obsahu, kdy jsou věty nebo dokonce slova rozděleny mezi více prvků. Formát odráží interní datové struktury a historické vlastnosti Microsoft Office. Používá nestandardní kódování, jednotky měření i nekonzistentní pojmenovávání a pravidla mezi jednotlivými moduly. Používá také obtížně srozumitelné značky.



Příklad XLSX


Abych ilustroval rozdíl v komplexitě mezi XML schématy ODF a OOXML, vytvořil jsem jednoduchou tabulku obsahující data z mého života, ať už významná nebo ironická. Patří sem například datum, kdy jsem si zlomil nos, kdy mi ho opravili, nebo kdy jsem se znovu oženil v Las Vegas při příležitosti 30. výročí svatby (neformální obřad typu drive-through v limuzíně).



Pro analýzu jsem soubor zkopíroval, přejmenoval příponu na „ZIP“ a rozbalil ho, čímž vznikly dvě složky obsahující všechny soubory daných XML schémat.


Složka LibreOffice obsahuje tři podsložky a šest souborů, z nichž jeden se jmenuje content.xml a ihned zaujme svým popisným názvem. Po jejím otevření vidíme veškerý obsah, zatímco ostatní soubory obsahují instrukce pro správné zobrazení tabulky.


<office:body>
<office:spreadsheet>
<table:calculation-settings table:case-sensitive=”false” table:automatic-find-labels=”false” table:use-regular-expressions=”false” table:use-wildcards=”true”>
<table:iteration table:maximum-difference=”0.0001″/>
</table:calculation-settings>
<table:table table:name=”Foglio1″ table:style-name=”ta1″>
<office:forms form:automatic-focus=”false” form:apply-design-mode=”false”/>
<table:table-column table:style-name=”co1″ table:default-cell-style-name=”ce2″/>
<table:table-column table:style-name=”co2″ table:default-cell-style-name=”ce4″/>
<table:table-column table:style-name=”co3″ table:number-columns-repeated=”16382″/>
<table:table-row table:style-name=”ro1″>
<table:table-cell table:style-name=”ce1″ office:value-type=”string” calcext:value-type=”string”>
<text:p>Event</text:p>
</table:table-cell>
<table:table-cell table:style-name=”ce3″ office:value-type=”string” calcext:value-type=”string”>
<text:p>Date</text:p>
</table:table-cell>
</table:table-row>
<table:table-row table:style-name=”ro1″>
<table:table-cell office:value-type=”string” calcext:value-type=”string”>
<text:p>Was Born in Umbria</text:p>
</table:table-cell>
<table:table-cell table:style-name=”ce7″ office:value-type=”date” office:date-value=”1954-08-12″ calcext:value-type=”date”>
<text:p>08/12/1954</text:p>
</table:table-cell>
</table:table-row>
<table:table-row table:style-name=”ro1″>
<table:table-cell office:value-type=”string” calcext:value-type=”string”>
<text:p>Broke Nose in Rome</text:p>
</table:table-cell>
<table:table-cell table:style-name=”ce7″ office:value-type=”date” office:date-value=”1965-01-18″ calcext:value-type=”date”>
<text:p>01/18/1965</text:p>
</table:table-cell>
</table:table-row>
<table:table-row table:style-name=”ro1″>
<table:table-cell office:value-type=”string” calcext:value-type=”string”>
<text:p>University Degree in Milan</text:p>
</table:table-cell>
<table:table-cell table:style-name=”ce7″ office:value-type=”date” office:date-value=”1978-11-19″ calcext:value-type=”date”>
<text:p>11/19/1978</text:p>
</table:table-cell>
</table:table-row>
<table:table-row table:style-name=”ro1″>
<table:table-cell office:value-type=”string” calcext:value-type=”string”>
<text:p>First Job at Italian Touring Club</text:p>
</table:table-cell>
<table:table-cell table:style-name=”ce7″ office:value-type=”date” office:date-value=”1981-01-10″ calcext:value-type=”date”>
<text:p>01/10/1981</text:p>
</table:table-cell>
</table:table-row>
<table:table-row table:style-name=”ro1″>
<table:table-cell office:value-type=”string” calcext:value-type=”string”>
<text:p>Hired by Honeywell and Got 1st PC</text:p>
</table:table-cell>
<table:table-cell table:style-name=”ce7″ office:value-type=”date” office:date-value=”1983-01-09″ calcext:value-type=”date”>
<text:p>01/09/1983</text:p>
</table:table-cell>
</table:table-row>
<table:table-row table:style-name=”ro1″>
<table:table-cell office:value-type=”string” calcext:value-type=”string”>
<text:p>1st Wedding in Assisi</text:p>
</table:table-cell>
<table:table-cell table:style-name=”ce7″ office:value-type=”date” office:date-value=”1984-08-09″ calcext:value-type=”date”>
<text:p>08/09/1984</text:p>
</table:table-cell>
</table:table-row>
<table:table-row table:style-name=”ro1″>
<table:table-cell office:value-type=”string” calcext:value-type=”string”>
<text:p>BBC Show Interview in Birmingham</text:p>
</table:table-cell>
<table:table-cell table:style-name=”ce7″ office:value-type=”date” office:date-value=”1987-02-17″ calcext:value-type=”date”>
<text:p>02/17/1987</text:p>
</table:table-cell>
</table:table-row>
<table:table-row table:style-name=”ro1″>
<table:table-cell office:value-type=”string” calcext:value-type=”string”>
<text:p>Installed OpenOffice</text:p>
</table:table-cell>
<table:table-cell table:style-name=”ce7″ office:value-type=”date” office:date-value=”2003-02-01″ calcext:value-type=”date”>
<text:p>02/01/2003</text:p>
</table:table-cell>
</table:table-row>
<table:table-row table:style-name=”ro1″>
<table:table-cell office:value-type=”string” calcext:value-type=”string”>
<text:p>Repaired Nose in Rozzano</text:p>
</table:table-cell>
<table:table-cell table:style-name=”ce7″ office:value-type=”date” office:date-value=”2008-12-04″ calcext:value-type=”date”>
<text:p>12/04/2008</text:p>
</table:table-cell>
</table:table-row>
<table:table-row table:style-name=”ro1″>
<table:table-cell office:value-type=”string” calcext:value-type=”string”>
<text:p>Launched LibreOffice</text:p>
</table:table-cell>
<table:table-cell table:style-name=”ce7″ office:value-type=”date” office:date-value=”2010-09-28″ calcext:value-type=”date”>
<text:p>09/28/2010</text:p>
</table:table-cell>
</table:table-row>
<table:table-row table:style-name=”ro1″>
<table:table-cell office:value-type=”string” calcext:value-type=”string”>
<text:p>2nd Wedding in Las Vegas</text:p>
</table:table-cell>
<table:table-cell table:style-name=”ce7″ office:value-type=”date” office:date-value=”2014-08-08″ calcext:value-type=”date”>
<text:p>08/08/2014</text:p>
</table:table-cell>
</table:table-row>
<table:table-row table:style-name=”ro2″ table:number-rows-repeated=”1048563″>
<table:table-cell table:number-columns-repeated=”2″/>
</table:table-row>
<table:table-row table:style-name=”ro2″>
<table:table-cell table:number-columns-repeated=”2″/>
</table:table-row>
</table:table>
<table:named-expressions/>
</office:spreadsheet>
</office:body>


Jde o XML soubor přiměřené složitosti. I člověk bez technických znalostí dokáže s trochou snahy identifikovat obsah obou sloupců. Formát je srozumitelný – pro data, textové řetězce i značky (řádek tabulky, buňka, text, datum).


Naopak složka Microsoft 365 obsahuje tři podsložky a soubor [Content_Types].xml. Po otevření tohoto souboru vidíme informace o dalších souborech včetně těch v podsložkách. Také ukazuje, že obsah je uložen v souboru sheet1.xml, který je skrytý ve složce worksheets, která je zase skrytá ve složce xl. Pro toto schovávání neexistuje žádný technický důvod, kromě zbytečného zkomplikování struktury souboru XLSX.

Velká část souboru  sheet1.xml vypadá takto:



<dimension ref=”A1:B12″/>
<sheetViews>
<sheetView tabSelected=”1″ workbookViewId=”0″>
<selection activeCell=”B1″ sqref=”B1:B1048576″/>
</sheetView>
</sheetViews>
<sheetFormatPr defaultRowHeight=”15″/>
<cols>
<col min=”1″ max=”1″ width=”34.140625″ style=”2″ bestFit=”1″ customWidth=”1″/>
<col min=”2″ max=”2″ width=”11.7109375″ style=”4″ bestFit=”1″ customWidth=”1″/>
</cols>
<sheetData>
<row r=”1″ spans=”1:2″>
<c r=”A1″ s=”1″ t=”s”>
<v>0</v>
</c>
<c r=”B1″ s=”3″ t=”s”>
<v>1</v>
</c>
</row>
<row r=”2″ spans=”1:2″>
<c r=”A2″ s=”2″ t=”s”>
<v>2</v>
</c>
<c r=”B2″ s=”4″>
<v>19948</v>
</c>
</row>
<row r=”3″ spans=”1:2″>
<c r=”A3″ s=”2″ t=”s”>
<v>3</v>
</c>
<c r=”B3″ s=”4″>
<v>23760</v>
</c>
</row>
<row r=”4″ spans=”1:2″>
<c r=”A4″ s=”2″ t=”s”>
<v>4</v>
</c>
<c r=”B4″ s=”4″>
<v>28813</v>
</c>
</row>
<row r=”5″ spans=”1:2″>
<c r=”A5″ s=”2″ t=”s”>
<v>5</v>
</c>
<c r=”B5″ s=”4″>
<v>29860</v>
</c>
</row>
<row r=”6″ spans=”1:2″>
<c r=”A6″ s=”2″ t=”s”>
<v>6</v>
</c>
<c r=”B6″ s=”4″>
<v>30560</v>
</c>
</row>
<row r=”7″ spans=”1:2″>
<c r=”A7″ s=”2″ t=”s”>
<v>7</v>
</c>
<c r=”B7″ s=”4″>
<v>30933</v>
</c>
</row>
<row r=”8″ spans=”1:2″>
<c r=”A8″ s=”2″ t=”s”>
<v>8</v>
</c>
<c r=”B8″ s=”4″>
<v>31825</v>
</c>
</row>
<row r=”9″ spans=”1:2″>
<c r=”A9″ s=”2″ t=”s”>
<v>9</v>
</c>
<c r=”B9″ s=”4″>
<v>37623</v>
</c>
</row>
<row r=”10″ spans=”1:2″>
<c r=”A10″ s=”2″ t=”s”>
<v>10</v>
</c>
<c r=”B10″ s=”4″>
<v>39550</v>
</c>
</row>
<row r=”11″ spans=”1:2″>
<c r=”A11″ s=”2″ t=”s”>
<v>11</v>
</c>
<c r=”B11″ s=”4″>
<v>40449</v>
</c>
</row>
<row r=”12″ spans=”1:2″>
<c r=”A12″ s=”2″ t=”s”>
<v>12</v>
</c>
<c r=”B12″ s=”4″>
<v>41859</v>
</c>
</row>
</sheetData>
<pageMargins left=”0.7″ right=”0.7″ top=”0.75″ bottom=”0.75″ header=”0.3″ footer=”0.3″/>


Soubor je extrémně obtížně čitelný. Kromě několika značek - col, row, sheetview a sheetdata - je celé XML úplně nesrozumitelné. Kde jsou data? Kde jsou popisy událostí?


Ve skutečnosti tam jsou, ale vyzývám kohokoli, aby je našel, pokud neví, že Excel zapisuje data jako pořadová čísla počítaná od 1. ledna 1900. Pro datum 29. února 1900 přidává o jeden den navíc, přestože jde o „fiktivní“ den, který program – nekompatibilní s gregoriánským kalendářem, jenž je standardem uznávaným i Čínou a 
muslimským světem – tvrdošíjně považuje za existující, i když tzv. „chyba přestupného roku“ (the leap year bug) byla objevena Bobem Bemerem už v roce 1958. 


Takže v Excelu číslo 19948 odpovídá datu 12. srpna 1954, ale ve skutečnosti jde o 13. srpna 1954. Další hodnoty jsou tedy  zřejmě 23,760; 28,813; 29,860; 30,560; 30,933; 31,825; 37,623; 39,550; 40,449; a 41,859. To je prý intuitivní a jednoduché a údajně vyplývá ze složitosti dokumentu. Nesmysl.


Záhada popisů událostí však stále zůstává. V souboru sheet1.xml vůbec nejsou ani ve formě odkazu. Jako by tabulka obsahovala jen druhý sloupec.


Takže se vracím k dokumentu [Content_Types].xml a otevírám xml dokumenty v pořadí v němž jsou seřazeny a hledám v podsouborech.


<Types xmlns=”http://schemas.openxmlformats.org/package/2006/content-types”>
<Default Extension=”rels” ContentType=”application/vnd.openxmlformats-package.relationships+xml”/>
<Default Extension=”xml” ContentType=”application/xml”/>
<Override PartName=”/xl/workbook.xml” ContentType=”application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml”/>
<Override PartName=”/docProps/core.xml” ContentType=”application/vnd.openxmlformats-package.core-properties+xml”/>
<Override PartName=”/docProps/app.xml” ContentType=”application/vnd.openxmlformats-officedocument.extended-properties+xml”/>
<Override PartName=”/xl/worksheets/sheet1.xml” ContentType=”application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml”/>
<Override PartName=”/xl/theme/theme1.xml” ContentType=”application/vnd.openxmlformats-officedocument.theme+xml”/>
<Override PartName=”/xl/styles.xml” ContentType=”application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml”/>
<Override PartName=”/xl/sharedStrings.xml” ContentType=”application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml”/>
</Types>


Když už jsem se vzdával naděje, konečně jsem našel soubor obsahující popis událostí s názvem sharedStrings.xml. Ten obsahuje následující:



<sst xmlns=”http://schemas.openxmlformats.org/spreadsheetml/2006/main” count=”13″ uniqueCount=”13″>
<si>
<t>Event</t>
</si>
<si>
<t>Date</t>
</si>
<si>
<t>Was Born in Umbria</t>
</si>
<si>
<t>Broke Nose in Rome</t>
</si>
<si>
<t>University Degree in Milan</t>
</si>
<si>
<t>First Job at Italian Touring Club</t>
</si>
<si>
<t>Hired by Honeywell and Got 1st PC</t>
</si>
<si>
<t>1st Wedding in Assisi</t>
</si>
<si>
<t>BBC Show Interview in Birmingham</t>
</si>
<si>
<t>Installed OpenOffice</t>
</si>
<si>
<t>Repaired Nose in Rozzano</t>
</si>
<si>
<t>Launched LibreOffice</t>
</si>
<si>
<t>2nd Wedding in Las Vegas</t>
</si>
</sst>



Ten je však ještě méně srozumitelný než záhadný dokument sheet1.xml. Zajímalo by mě, jak jsou popisy propojeny s daty v souboru sheet1.xml pomocí odlišných tagů <t> a <v>. Neexistují žádné zjevné vazby mezi těmito prvky a pokud ano, vyzývám kohokoli, aby mi je vysvětlil způsobem, kterému budu rozumět, a zároveň aby mi ospravedlnil záhadný formát těchto odkazů. 

Bohužel realita je taková, jak jsem se ji už snažil vysvětlit bez zabíhání do technických detailů, jak jsem to udělal v tomto článku a jak to udělám i v dalším, který bude věnován formátu DOCX. Microsoft vytvořil zbytečně složitý formát – pokud LibreOffice dokáže pracovat s těmito informacemi jednodušeji, nechápu, proč to Microsoft 365 nedokáže také – cílem je výrazně ztížit napodobení formátu OOXML bez použití zpětného inženýrství, které je v některých zemích široce využíváno.

Programy, které používají zpětné inženýrství k tomu, aby přijaly OOXML jako svůj nativní formát, navíc ve skutečnosti pouze pomáhají Microsoftu bránit jeho tržní podíl tím, že podporují proprietární formát, který jde proti zájmům uživatelů a jejich právu na vlastnictví a kontrolu nad obsahem, který vytvořili, což se obecně označuje jako digitální suverenita.

Uživatelé by se měli naučit chránit svá práva tím, že si zvolí otevřený standardní formát, jako je ODF. Ten zaručuje kontrolu nad obsahem a vším, co s tím souvisí, včetně ochrany soukromí, správného nakládání s citlivými daty a možnosti rozhodovat o tom, co sdílet a s kým.

Vývojový proces, vlastnosti i verze tohoto formátu jsou popsané a jejich popis odpovídá tomu, co se skutečně děje na počítači uživatele, díky čemuž dokáže i méně technicky zdatný uživatel pochopit, co se děje, když nastane problém, a v mnoha případech ho i vyřešit.

Stručně řečeno, jde o standardní formát dokumentů, který bychom všichni chtěli používat, ale ve skutečnosti jej využívá jen menšina, kvůli nedostatku informací o reálném obsahu formátu OOXML a kvůli téměř „mesianistické“ důvěře, kterou mnozí vkládají do Microsoftu. Ta je vede k přesvědčení, že za formátem dokumentů nemůže stát žádná obchodní strategie, která by upřednostňovala zájmy firmy na úkor uživatelů.