Obsah
1. Tvorba sešitů pro tabulkové procesory v programovacím jazyku Go – formát xlsx
2. Způsob uložení jednoduchého sešitu s jediným prázdným listem
3. Interní struktura sešitu se třemi prázdnými listy
4. Uložení celočíselných hodnot v buňce sešitu
5. Uložení pravdivostních hodnot a hodnot s plovoucí řádovou čárkou
6. Nepřímé uložení řetězců (referencí)
8. List s horizontálně spojenými buňkami
11. Specifikace formátu zobrazení hodnot v buňkách
12. Popis stylů zobrazení obsahu buněk
13. Formátování časových údajů a dat
14. Pomocné funkce pro konverzi časových údajů
15. Explicitně nastavené styly zobrazení
17. Repositář s demonstračními příklady
1. Tvorba sešitů pro tabulkové procesory v programovacím jazyku Go – formát xlsx
V předchozím článku jsme si ukázali, jakým způsobem je možné v aplikacích vyvinutých v programovacím jazyku Go vytvářet takzvané sešity (workbook), které je následně možné otevřít a dále zpracovat v tabulkových procesorech (spreadsheet), například v „kancelářských“ aplikacích Gnumeric, Microsoft Excel, LibreOffice Calc či v některých tabulkových procesorech naprogramovaných a dostupných ve formě webových aplikací (Google Doc, Ethercalc). Nejprve jsme se zaměřili na alespoň stručný popis standardní knihovny encoding/csv, která zajišťuje čtení i zápis tabulek (tedy vlastně jediného listu) uložených ve formátu CSV, přesněji řečeno v podmnožině tohoto variabilního formátu odpovídající RFC 4180. Tato de facto norma však zdaleka nepopisuje všechny varianty CSV, s nimiž se můžeme v praxi setkat. Navíc – což je v praxi ještě problémovější záležitost – se nepopisuje sémantika zápisu informací o datu a/nebo času.
Ve druhé polovině předchozího článku jsme se pak zmínili o knihovně nazvané tealeg/xlsx, která realizuje programové rozhraní k formátu Office Open XML Workbook neboli (podle používané koncovky) xlsx. Tento formát je součástí skupiny formátů známých též pod zkratkou OOXML a – jak uvidíme v dalších kapitolách – vnitřní struktura tohoto formátu je tvořena sadou zazipovaných souborů (většinou používajících jazyk XML). Dnes se seznámíme s některými dalšími vlastnostmi tohoto formátu, protože bez alespoň základní znalosti toho, jaké má xlsx vlastnosti, není možné úspěšně vytvářet složitěji strukturované sešity s množstvím stylů i dalších objektů (grafů atd.).
2. Způsob uložení jednoduchého sešitu s jediným prázdným listem
Nejprve se podíváme na interní strukturu souboru obsahujícího jednoduchý sešit s jediným prázdným listem. Jedná se tedy o nejjednodušší možný sešit vůbec, protože již minule jsme se dozvěděli, že každý sešit musí obsahovat alespoň jeden list (což je dosti podobná vlastnost, jakou mají textové procesory, u nichž nejjednodušší dokument taktéž obsahuje minimálně jednu prázdnou stranu). Sešit s jediným prázdným listem je pochopitelně možné vytvořit v prakticky jakémkoli moderním tabulkovém procesoru, ovšem my si ukážeme programové vytvoření (to má velkou přednost v tom, že výsledný xlsx bude „čistý“: nebude obsahovat mnoho nadbytečných informací). V případě programové tvorby sešitu se nejedná o žádné nové operace, protože jsme se s nimi seznámili již v předchozím článku. Zdrojový kód programu, který takový sešit vytvoří, může vypadat následovně:
package main import ( "fmt" "github.com/tealeg/xlsx/v3" ) // jméno generovaného souboru const spreadsheetName = "test02.xlsx" func main() { // konstrukce struktury typu File worksheet := xlsx.NewFile() fmt.Println(worksheet) // přidání listu do sešitu sheet, err := worksheet.AddSheet("Tabulka1") if err != nil { panic(err) } fmt.Println(sheet) // pokus o uložení sešitu err = worksheet.Save(spreadsheetName) if err != nil { panic(err) } }
Po překladu a spuštění této aplikace by měl vzniknout soubor nazvaný test02.xlsx o velikosti 5651 bajtů. To lze snadno ověřit:
$ ls -l test02.xlsx -rw-rw-r--. 1 ptisnovs ptisnovs 5651 Aug 25 19:21 test02.xlsx
Mohlo by se zdát, že prakticky prázdný sešit by mohl mít i menší velikost (v případě CSV by se jednalo o soubor o velikosti přesně nula bajtů), ovšem ve skutečnosti roste velikost souboru se zvětšujícími se tabulkami poměrně rozumným způsobem. I v souboru s prázdným sešitem je totiž nutné mít uloženy metainformace, styly atd. Jak jsme si již naznačili v úvodní kapitole, jsou soubory s koncovkou .xlsx de facto zazipované adresářové struktury s množstvím dalších souborů (jejich počet se mění se složitostí sešitu). Můžeme si to ostatně ověřit, protože obsah zazipovaného archivu snadno získáme nástrojem unzip:
$ unzip -l test02.xlsx Archive: test02.xlsx Length Date Time Name --------- ---------- ----- ---- 798 00-00-1980 00:00 xl/worksheets/sheet1.xml 743 00-00-1980 00:00 xl/workbook.xml 580 00-00-1980 00:00 _rels/.rels 308 00-00-1980 00:00 docProps/app.xml 364 00-00-1980 00:00 docProps/core.xml 10940 00-00-1980 00:00 xl/theme/theme1.xml 142 00-00-1980 00:00 xl/sharedStrings.xml 736 00-00-1980 00:00 xl/_rels/workbook.xml.rels 1485 00-00-1980 00:00 [Content_Types].xml 1062 00-00-1980 00:00 xl/styles.xml --------- ------- 17158 10 files
Z výše uvedených deseti souborů nás bude zajímat jen mnohem menší podmnožina. Zejména se jedná o soubor nazvaný workbook.xml, který obsahuje popis struktury celého sešitu. Již podle koncovky je patrné, že se jedná o soubor s daty reprezentovanými v jazyku XML, ovšem soubor je minifikován a není tak příliš čitelný. Z tohoto důvodu provedeme jeho naformátování, a to například nástrojem xmllint:
$ xmllint --format workbook.xml
Výsledek by měl vypadat následovně:
<?xml version="1.0" encoding="UTF-8"?> <workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"> <fileVersion appName="Go XLSX"/> <workbookPr showObjects="all" date1904="false"/> <workbookProtection/> <bookViews> <workbookView showHorizontalScroll="true" showVerticalScroll="true" showSheetTabs="true" tabRatio="204" windowHeight="8192" windowWidth="16384" xWindow="0" yWindow="0"/> </bookViews> <sheets> <sheet name="Tabulka1" sheetId="1" r:id="rId1" state="visible"/> </sheets> <definedNames/> <calcPr iterateCount="100" refMode="A1" iterateDelta="0.001"/> </workbook>
Povšimněte si, že kromě informací o způsobu zobrazení sešitu je v tomto souboru uvedena jediná další důležitá informace – název jediného listu „Tabulka1“ a identifikátor tohoto listu „1“.
Druhým důležitým souborem je soubor nazvaný sheet1.xml. Ten obsahuje popis listu s ID=1, takže se opět podívejme, jaké informace lze z tohoto souboru získat:
$ xmllint --format sheet1.xml
Výsledek by měl po naformátování vypadat následovně:
<?xml version="1.0" encoding="UTF-8"?> <worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"> <sheetPr filterMode="false"> <pageSetUpPr fitToPage="false"/> </sheetPr> <dimension ref="A1"/> <sheetViews> <sheetView windowProtection="false" showFormulas="false" showGridLines="true" showRowColHeaders="true" showZeros="true" rightToLeft="false" tabSelected="true" showOutlineSymbols="true" defaultGridColor="true" view="normal" topLeftCell="A1" colorId="64" zoomScale="100" zoomScaleNormal="100" zoomScalePageLayoutView="100" workbookViewId="0"> <selection pane="topLeft" activeCell="A1" activeCellId="0" sqref="A1"/> </sheetView> </sheetViews> <sheetFormatPr defaultRowHeight="12.85"/> <sheetData/> </worksheet>
Vzhledem k tomu, že je sešit prázdný, obsahuje soubor sheet1.xml pouze informace o způsobu jeho zobrazení (sheetViews), zatímco uzel s daty je prázdný (sheetData).
3. Interní struktura sešitu se třemi prázdnými listy
Dále prozkoumáme interní strukturu sešitu, který obsahuje trojici prázdných listů, přičemž jednotlivé listy jsou nazvány „Tabulka1“, „Tabulka2“ a „Tabulka3“. Takový sešit lze vytvořit například následujícím programem, který již byl (podobně jako program z předchozí kapitoly) prezentován minule:
package main import ( "fmt" "github.com/tealeg/xlsx/v3" ) // jméno generovaného souboru const spreadsheetName = "test03.xlsx" func main() { // konstrukce struktury typu File worksheet := xlsx.NewFile() fmt.Println(worksheet) // přidání tří listů do sešitu names := []string{"Tabulka1", "Tabulka2", "Tabulka3"} for _, name := range names { // pokus o přidání nového listu sheet, err := worksheet.AddSheet(name) if err != nil { panic(err) } fmt.Println(sheet) } // pokus o uložení sešitu err := worksheet.Save(spreadsheetName) if err != nil { panic(err) } }
Podle předpokladů bude nyní soubor s koncovkou .xlsx obsahovat nikoli pouze deset souborů, ale souborů dvanáct, protože každý list je v archivu reprezentován samostatným souborem (což je poměrně dobré uspořádání):
$ unzip -l test03.xlsx Archive: test03.xlsx Length Date Time Name --------- ---------- ----- ---- 798 00-00-1980 00:00 xl/worksheets/sheet1.xml 799 00-00-1980 00:00 xl/worksheets/sheet2.xml 799 00-00-1980 00:00 xl/worksheets/sheet3.xml 885 00-00-1980 00:00 xl/workbook.xml 580 00-00-1980 00:00 _rels/.rels 308 00-00-1980 00:00 docProps/app.xml 364 00-00-1980 00:00 docProps/core.xml 10940 00-00-1980 00:00 xl/theme/theme1.xml 142 00-00-1980 00:00 xl/sharedStrings.xml 1046 00-00-1980 00:00 xl/_rels/workbook.xml.rels 1777 00-00-1980 00:00 [Content_Types].xml 1062 00-00-1980 00:00 xl/styles.xml --------- ------- 19500 12 files
Soubor obsahující popis sešitu nyní obsahuje informaci o třech listech, přičemž každému listu je přiřazen jednoznačný identifikátor, který se objevuje i ve jménu souboru s obsahem listu. Viz též zvýrazněné atributy; první s názvem listu a druhý s jeho identifikátorem (to však neznamená, že názvy listů mohou být totožné!):
$ xmllint --format workbook.xml <?xml version="1.0" encoding="UTF-8"?> <workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"> <fileVersion appName="Go XLSX"/> <workbookPr showObjects="all" date1904="false"/> <workbookProtection/> <bookViews> <workbookView showHorizontalScroll="true" showVerticalScroll="true" showSheetTabs="true" tabRatio="204" windowHeight="8192" windowWidth="16384" xWindow="0" yWindow="0"/> </bookViews> <sheets> <sheet name="Tabulka1" sheetId="1" r:id="rId1" state="visible"/> <sheet name="Tabulka2" sheetId="2" r:id="rId2" state="visible"/> <sheet name="Tabulka3" sheetId="3" r:id="rId3" state="visible"/> </sheets> <definedNames/> <calcPr iterateCount="100" refMode="A1" iterateDelta="0.001"/> </workbook>
4. Uložení celočíselných hodnot v buňce sešitu
V dalším demonstračním příkladu si ukážeme, jakým způsobem jsou uloženy celočíselné hodnoty v buňce sešitu. Nejprve si ukažme zdrojový kód příkladu, po jehož spuštění se vytvoří soubor se sešitem obsahujícím jediný list, který obsahuje jedinou buňku naplněnou celočíselnou hodnotou 42 (nikoli tedy řetězcem „42“):
package main import ( "fmt" "github.com/tealeg/xlsx/v3" ) // jméno generovaného souboru const spreadsheetName = "test13.xlsx" func main() { // konstrukce struktury typu File worksheet := xlsx.NewFile() fmt.Println(worksheet) // přidání listu do sešitu sheet, err := worksheet.AddSheet("Tabulka1") if err != nil { panic(err) } defer sheet.Close() fmt.Println(sheet) // přidání řádku do tabulky row := sheet.AddRow() // přidání buňky na řádek cell := row.AddCell() // naplnění buňky hodnotou cell.SetInt(42) // pokus o uložení sešitu err = worksheet.Save(spreadsheetName) if err != nil { panic(err) } }
Zajímat nás bude pouze obsah souboru sheet1.xml s obsahem listu, takže si ho zobrazíme ve formátované podobě:
$ xmllint --format sheet1.xml
Vypsat by se měl následující naformátovaný obsah:
<?xml version="1.0" encoding="UTF-8"?> <worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"> <sheetPr filterMode="false"> <pageSetUpPr fitToPage="false"/> </sheetPr> <dimension ref="A1"/> <sheetViews> <sheetView windowProtection="false" showFormulas="false" showGridLines="true" showRowColHeaders="true" showZeros="true" rightToLeft="false" tabSelected="true" showOutlineSymbols="true" defaultGridColor="true" view="normal" topLeftCell="A1" colorId="64" zoomScale="100" zoomScaleNormal="100" zoomScalePageLayoutView="100" workbookViewId="0"> <selection pane="topLeft" activeCell="A1" activeCellId="0" sqref="A1"/> </sheetView> </sheetViews> <sheetFormatPr defaultRowHeight="12.85"/> <sheetData> <row r="1"> <c r="A1"> <v>42</v> </c> </row> </sheetData> </worksheet>
Důležité informace jsou zvýrazněny tučným písmem, takže jen ve stručnosti:
- Hodnoty, které jsou na list vloženy, jsou umístěny do uzlu nazvanéhosheetData.
- Neukládají se přímo jednotlivé buňky, ale řádky tabulky, přičemž každý řádek je umístěn v samostatném uzlu nazvaném row s identifikátorem (což je celé číslo vetší nebo rovno jedné – pouze některé starší tabulkové procesory číslují řádky od nuly).
- Samotná buňka je představována uzlem nazvaným c, který opět obsahuje svoji adresu; v našem případě A1.
- Hodnota umístěná do buňky je uložena v uzlu nazvanémv. V případě celočíselné hodnoty je v uzlu přímo tato hodnota. Zajímavé je, že u celočíselných hodnot se neuvádí typ, pouze je v uzlu v umístěna hodnota 42 bez dalších doplňujících metainformací.
5. Uložení pravdivostních hodnot a hodnot s plovoucí řádovou čárkou
Víme již, jak jsou uloženy buňky obsahující celá čísla, takže logicky zbývá odpovědět na otázku uložení pravdivostních hodnot, popř. numerických hodnot s řádovou čárkou (nutně se nemusí jednat o plovoucí čárku!). Sešit s listem obsahujícím pravdivostní hodnotu a číslo 1/3 vytvoříme spuštěním následujícího demonstračního příkladu:
package main import ( "fmt" "github.com/tealeg/xlsx/v3" ) // jméno generovaného souboru const spreadsheetName = "test14.xlsx" func main() { // konstrukce struktury typu File worksheet := xlsx.NewFile() fmt.Println(worksheet) // přidání listu do sešitu sheet, err := worksheet.AddSheet("Tabulka1") if err != nil { panic(err) } defer sheet.Close() fmt.Println(sheet) // přidání řádku do tabulky row := sheet.AddRow() // přidání buňky na řádek cell := row.AddCell() // naplnění buňky hodnotou cell.SetFloat(1 / 3.) // přidání buňky na řádek cell = row.AddCell() // naplnění buňky hodnotou cell.SetBool(false) // přidání buňky na řádek cell = row.AddCell() // naplnění buňky hodnotou cell.SetBool(true) // pokus o uložení sešitu err = worksheet.Save(spreadsheetName) if err != nil { panic(err) } }
Opět nás bude zajímat pouze obsah souboru sheet1.xml s informacemi o jediném listu, který se v sešitu nachází:
$ xmllint --format sheet1.xml
Výsledky jsou nyní zajímavější, protože ukazují, že:
- Hodnota s řádovou čárkou je uložena v největší podporované přesnosti, a to opět bez uvedení datového typu (rozlišení mezi celými čísly a čísly s řádovou čárkou je tedy implicitní).
- Pravdivostní hodnota je převedena na celé číslo, a to true → 1 a false → 0 (tedy pro nás programátory typickým způsobem).
- U pravdivostních hodnot je uveden typ t=„b“, takže tabulkové procesory budou umět hodnoty 0 a 1 správně interpretovat.
Ověřme si, že jsou tato tvrzení skutečně správná, a to pohledem do souboru sheet1.xml:
<?xml version="1.0" encoding="UTF-8"?> <worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"> <sheetPr filterMode="false"> <pageSetUpPr fitToPage="false"/> </sheetPr> <dimension ref="A1:B1"/> <sheetViews> <sheetView windowProtection="false" showFormulas="false" showGridLines="true" showRowColHeaders="true" showZeros="true" rightToLeft="false" tabSelected="true" showOutlineSymbols="true" defaultGridColor="true" view="normal" topLeftCell="A1" colorId="64" zoomScale="100" zoomScaleNormal="100" zoomScalePageLayoutView="100" workbookViewId="0"> <selection pane="topLeft" activeCell="A1" activeCellId="0" sqref="A1"/> </sheetView> </sheetViews> <sheetFormatPr defaultRowHeight="12.85"/> <sheetData> <row r="1"> <c r="A1"> <v>0.3333333333333333</v> </c> <c r="B1" t="b"> <v>0</v> </c> <c r="C1" t="b"> <v>1</v> </c> </row> </sheetData> </worksheet>
6. Nepřímé uložení řetězců (referencí)
Nyní zdrojový kód demonstračního příkladu, který vytváří sešit, nepatrně upravíme, a to konkrétně takovým způsobem, aby se v listu sešitu nacházela buňka s řetězcem (použijeme tedy metodu SetString). Jak totiž uvidíme dále, jsou řetězce ukládány způsobem zcela odlišným od „primitivních“ hodnot, což může být zpočátku překvapující:
package main import ( "fmt" "github.com/tealeg/xlsx/v3" ) // jméno generovaného souboru const spreadsheetName = "test04.xlsx" func main() { // konstrukce struktury typu File worksheet := xlsx.NewFile() fmt.Println(worksheet) // přidání listu do sešitu sheet, err := worksheet.AddSheet("Tabulka1") if err != nil { panic(err) } defer sheet.Close() fmt.Println(sheet) // přidání řádku do tabulky row := sheet.AddRow() // přidání buňky na řádek cell := row.AddCell() // naplnění buňky hodnotou cell.SetString("Hello") // pokus o uložení sešitu err = worksheet.Save(spreadsheetName) if err != nil { panic(err) } }
Pohled na interní strukturu sešitu nám odhalí, jak jsou řetězce ukládány:
$ xmllint --format sheet1.xml
Z výpisu je patrné, že list obsahuje jedinou buňku (konkrétně buňku A1), která je typu „s“ a obsahuje hodnotu 0. To je zajisté zvláštní, protože jsme přece do listu uložili řetězec „Hello“ a nikoli nulovou hodnotu:
<?xml version="1.0" encoding="UTF-8"?> <worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"> <sheetPr filterMode="false"> <pageSetUpPr fitToPage="false"/> </sheetPr> <dimension ref="A1"/> <sheetViews> <sheetView windowProtection="false" showFormulas="false" showGridLines="true" showRowColHeaders="true" showZeros="true" rightToLeft="false" tabSelected="true" showOutlineSymbols="true" defaultGridColor="true" view="normal" topLeftCell="A1" colorId="64" zoomScale="100" zoomScaleNormal="100" zoomScalePageLayoutView="100" workbookViewId="0"> <selection pane="topLeft" activeCell="A1" activeCellId="0" sqref="A1"/> </sheetView> </sheetViews> <sheetFormatPr defaultRowHeight="12.85"/> <sheetData> <row r="1"> <c r="A1" t="s"> <v>0</v> </c> </row> </sheetData> </worksheet>
Ve skutečnosti jsou řetězce ukládány do jiného souboru nazvaného sharedStrings.xml ve formě jednoduché tabulky:
$ xmllint --format sharedStrings.xml <?xml version="1.0" encoding="UTF-8"?> <sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="1" uniqueCount="1"> <si> <t>Hello</t> </si> </sst>
Tabulkový procesor z této tabulky přečte řetězec s indexem 0 a zobrazí ho v buňce A1.
7. Spojení buněk v tabulce
Tabulky používané v tabulkových procesorech nejsou čistými maticemi buněk o stejné velikosti. Buňky, přesněji řečeno sousední buňky tvořící obdélníkové oblasti, je totiž možné spojovat. V knihovně tealeg/xlsx k tomuto účelu slouží metoda nazvaná Merge aplikovaná na buňku – to nám napovídá, že spojení je vlastností buňky a nikoli sešitu:
$ go doc tealeg/xlsx.Merge package xlsx // import "github.com/tealeg/xlsx" func (c *Cell) Merge(hcells, vcells int) Merge with other cells, horizontally and/or vertically.
Z popisu je patrné, že se této funkci předává dvojice celých čísel. Tyto hodnoty udávají s kolika buňkami horizontálně, popř. vertikálně se má buňka spojit. To znamená, že číslo 1 znamená spojení se sousední buňkou, zatímco číslo 0 znamená, že v daném směru ke spojení nedochází (to je velký rozdíl například oproti atributům rowspan a colspan v HTML). A dalším rozdílem je, že spojované buňky by měly v listu existovat, jinak může při importu sešitu dojít k chybě (to si ostatně ukážeme v dalších kapitolách).
8. List s horizontálně spojenými buňkami
V následujícím demonstračním příkladu je vytvořen sešit s jedním listem a tento list obsahuje trojici buněk (všechny na jednom řádku). Ovšem druhá buňka je spojena s buňkou třetí, takže ve skutečnosti hodnotu třetí buňky v tabulkovém procesoru neuvidíme, což je ostatně patrné i na screenshotu:
package main import ( "fmt" "github.com/tealeg/xlsx/v3" ) // jméno generovaného souboru const spreadsheetName = "test15.xlsx" func main() { // konstrukce struktury typu File worksheet := xlsx.NewFile() fmt.Println(worksheet) // přidání listu do sešitu sheet, err := worksheet.AddSheet("Tabulka1") if err != nil { panic(err) } defer sheet.Close() fmt.Println(sheet) // přidání řádku do tabulky row := sheet.AddRow() // přidání první buňky na řádek cell := row.AddCell() // naplnění buňky hodnotou cell.SetString("1x1") // přidání druhé buňky na řádek cell = row.AddCell() // naplnění buňky hodnotou cell.SetString("2x1") // a spojení s další buňkou cell.Merge(1, 0) // přidání třetí buňky na řádek cell = row.AddCell() // naplnění buňky hodnotou cell.SetString("1x1") // pokus o uložení sešitu err = worksheet.Save(spreadsheetName) if err != nil { panic(err) } }
Zajímavé bude zjistit, jak se vlastně informace o spojení buněk uloží do souboru sheet1.xml s popisem obsahu listu:
$ xmllint --format sheet1.xml <?xml version="1.0" encoding="UTF-8"?> <worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"> <sheetPr filterMode="false"> <pageSetUpPr fitToPage="false"/> </sheetPr> <dimension ref="A1:C1"/> <sheetViews> <sheetView windowProtection="false" showFormulas="false" showGridLines="true" showRowColHeaders="true" showZeros="true" rightToLeft="false" tabSelected="true" showOutlineSymbols="true" defaultGridColor="true" view="normal" topLeftCell="A1" colorId="64" zoomScale="100" zoomScaleNormal="100" zoomScalePageLayoutView="100" workbookViewId="0"> <selection pane="topLeft" activeCell="A1" activeCellId="0" sqref="A1"/> </sheetView> </sheetViews> <sheetFormatPr defaultRowHeight="12.85"/> <sheetData> <row r="1"> <c r="A1" t="s"> <v>0</v> </c> <c r="B1" t="s"> <v>1</v> </c> <c r="C1" t="s"> <v>0</v> </c> </row> </sheetData> <mergeCells count="1"> <mergeCell ref="B1:C1"/> </mergeCells> </worksheet>
Můžeme vidět, že informace o spojených buňkách není součástí atributu buňky (jak by nás k tomu mohla vést metoda Merge), ale „globální informací“ vztaženou k celému listu.
$ xmllint --format sharedStrings.xml <?xml version="1.0" encoding="UTF-8"?> <sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="2" uniqueCount="2"> <si> <t>1x1</t> </si> <si> <t>2x1</t> </si> </sst>
9. Spojení neexistující buňky
V předchozí kapitole jsme si řekli, že pokud dochází ke spojení buněk, musí i další spojované buňky existovat, i když se jejich hodnota ani styl nikde nezobrazí. Pokud tomu tak není, mohou tabulkové procesory nahlásit chybu při pokusu o import takto upraveného sešitu:
Sešit se špatným obsahem byl vytvořen tímto demonstračním příkladem (který ovšem po svém spuštění žádnou chybu nenahlásí):
package main import ( "fmt" "github.com/tealeg/xlsx/v3" ) // jméno generovaného souboru const spreadsheetName = "test16.xlsx" func main() { // konstrukce struktury typu File worksheet := xlsx.NewFile() fmt.Println(worksheet) // přidání listu do sešitu sheet, err := worksheet.AddSheet("Tabulka1") if err != nil { panic(err) } defer sheet.Close() fmt.Println(sheet) // přidání řádku do tabulky row := sheet.AddRow() // přidání první buňky na řádek cell := row.AddCell() // naplnění buňky hodnotou cell.SetString("1x1") // přidání druhé buňky na řádek cell = row.AddCell() // naplnění buňky hodnotou cell.SetString("2x1") // a spojení s další buňkou cell.Merge(1, 0) // pokus o uložení sešitu err = worksheet.Save(spreadsheetName) if err != nil { panic(err) } }
10. Vertikální spojení buněk
V případě, že se buňky spojují vertikálně (tedy mezi několika řádky), musí být všechny spojované řádky explicitně vytvořeny, což si na nejjednodušším příkladu (spojení dvou buněk pod sebou) ukážeme v následujícím zdrojovém kódu. Povšimněte si (zvýrazněný řádek), jak je možné jediným příkazem zajistit vytvoření nového řádku, přidání buňky na tento řádek a současně i nastavení hodnoty buňky:
package main import ( "fmt" "github.com/tealeg/xlsx/v3" ) // jméno generovaného souboru const spreadsheetName = "test17.xlsx" func main() { // konstrukce struktury typu File worksheet := xlsx.NewFile() fmt.Println(worksheet) // přidání listu do sešitu sheet, err := worksheet.AddSheet("Tabulka1") if err != nil { panic(err) } defer sheet.Close() fmt.Println(sheet) // přidání řádku do tabulky row := sheet.AddRow() // přidání první buňky na řádek cell := row.AddCell() // naplnění buňky hodnotou cell.SetString("1x2") // naplnění buňky hodnotou cell.SetString("1x2") // a spojení s buňkou na následujícím řádku cell.Merge(0, 1) // přidání druhé buňky na řádek cell = row.AddCell() // naplnění buňky hodnotou cell.SetString("1x1") // další řádek tabulky sheet.AddRow().AddCell().SetString("foobar") // pokus o uložení sešitu err = worksheet.Save(spreadsheetName) if err != nil { panic(err) } }
Výsledek by mohl po otevření v tabulkovém procesoru vypadat následovně:
Nyní v souboru sheet1.xml nalezneme mj. i následující informaci o spojení buněk:
<mergeCells count="1"> <mergeCell ref="A1:A2"/> </mergeCells>
11. Specifikace formátu zobrazení hodnot v buňkách
Tabulkové procesory rozlišují mezi hodnotou buňky (což může být i vzorec) a zobrazenou hodnotou. Po textově-grafické stránce se tyto dva údaje mohou odlišovat a mnohdy se i odlišují, protože v mnoha případech například požadujeme zobrazení pouze určitého počtu desetinných míst, určitý konkrétní způsob zobrazení časových údajů atd. Následující demonstrační příklad již známe, protože jsme se s ním seznámili minule. Ukazuje, jakým způsobem se nastavuje formát zobrazení numerických hodnot s řádovou čárkou (hodnota je ve všech buňkách stejná, ovšem zobrazí se různým způsobem):
package main import ( "fmt" "github.com/tealeg/xlsx/v3" ) // jméno generovaného souboru const spreadsheetName = "test07.xlsx" func main() { // konstrukce struktury typu File worksheet := xlsx.NewFile() fmt.Println(worksheet) // přidání listu do sešitu sheet, err := worksheet.AddSheet("Tabulka1") if err != nil { panic(err) } defer sheet.Close() fmt.Println(sheet) // přidání řádku do tabulky row := sheet.AddRow() // přidání buňky na řádek a naplnění hodnotou row.AddCell().SetFloatWithFormat(1/3.0, "#0") row.AddCell().SetFloatWithFormat(1/3.0, "#0.0") row.AddCell().SetFloatWithFormat(1/3.0, "#0.00") row.AddCell().SetFloatWithFormat(1/3.0, "#0.000") row.AddCell().SetFloatWithFormat(1/3.0, "#0.0000") row.AddCell().SetFloatWithFormat(1/3.0, "#0.00000") row.AddCell().SetFloatWithFormat(1/3.0, "#0.000000") // pokus o uložení sešitu err = worksheet.Save(spreadsheetName) if err != nil { panic(err) } }
V samotném sešitu je hodnota uložena v plné (dostupné) přesnosti, což je ostatně patrné i z pohledu na zdrojový kód sešitu. Ovšem u buněk je navíc ještě specifikován index stylu (zvýrazněný atribut):
$ xmllint --format sheet1.xml <?xml version="1.0" encoding="UTF-8"?> <worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"> <sheetPr filterMode="false"> <pageSetUpPr fitToPage="false"/> </sheetPr> <dimension ref="A1:G1"/> <sheetViews> <sheetView windowProtection="false" showFormulas="false" showGridLines="true" showRowColHeaders="true" showZeros="true" rightToLeft="false" tabSelected="true" showOutlineSymbols="true" defaultGridColor="true" view="normal" topLeftCell="A1" colorId="64" zoomScale="100" zoomScaleNormal="100" zoomScalePageLayoutView="100" workbookViewId="0"> <selection pane="topLeft" activeCell="A1" activeCellId="0" sqref="A1"/> </sheetView> </sheetViews> <sheetFormatPr defaultRowHeight="12.85"/> <sheetData> <row r="1"> <c r="A1" s="1"> <v>0.3333333333333333</v> </c> <c r="B1" s="2"> <v>0.3333333333333333</v> </c> <c r="C1" s="3"> <v>0.3333333333333333</v> </c> <c r="D1" s="4"> <v>0.3333333333333333</v> </c> <c r="E1" s="5"> <v>0.3333333333333333</v> </c> <c r="F1" s="6"> <v>0.3333333333333333</v> </c> <c r="G1" s="7"> <v>0.3333333333333333</v> </c> </row> </sheetData> </worksheet>
12. Popis stylů zobrazení obsahu buněk
Styly zobrazení jsou uloženy v samostatném souboru nazvaném styles.xml, jehož struktura je poměrně komplikovaná. Ovšem můžeme zde vidět především sedm specifikací zobrazení numerických hodnot:
<numFmts count="7"> <numFmt numFmtId="164" formatCode="#0"/> <numFmt numFmtId="165" formatCode="#0.0"/> <numFmt numFmtId="166" formatCode="#0.00"/> <numFmt numFmtId="167" formatCode="#0.000"/> <numFmt numFmtId="168" formatCode="#0.0000"/> <numFmt numFmtId="169" formatCode="#0.00000"/> <numFmt numFmtId="170" formatCode="#0.000000"/> </numFmts>
Ty jsou referencovány ve specifikaci stylů buněk. Příkladem může být druhý styl, který používá zobrazení numerických hodnot popsané formátovacím řetězcem „#0“:
<cellXfs count="8"> ... ... ... <xf applyAlignment="0" applyBorder="0" applyFont="0" applyFill="0" applyNumberFormat="1" applyProtection="0" borderId="0" fillId="0" fontId="0" numFmtId="164"> <alignment horizontal="general" indent="0" shrinkToFit="0" textRotation="0" vertical="bottom" wrapText="0"/> </xf> ... ... ... </cellXfs>
Pro úplnost si ukažme úplný obsah souboru s popisem stylů:
<?xml version="1.0" encoding="UTF-8"?> <styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"> <numFmts count="7"> <numFmt numFmtId="164" formatCode="#0"/> <numFmt numFmtId="165" formatCode="#0.0"/> <numFmt numFmtId="166" formatCode="#0.00"/> <numFmt numFmtId="167" formatCode="#0.000"/> <numFmt numFmtId="168" formatCode="#0.0000"/> <numFmt numFmtId="169" formatCode="#0.00000"/> <numFmt numFmtId="170" formatCode="#0.000000"/> </numFmts> <fonts count="1"> <font> <sz val="11"/> <name val="Arial"/> <family val="2"/> <color theme="1"/> <scheme val="minor"/> </font> </fonts> <fills count="2"> <fill> <patternFill patternType="none"/> </fill> <fill> <patternFill patternType="gray125"/> </fill> </fills> <borders count="1"> <border> <left/> <right/> <top/> <bottom/> </border> </borders> <cellStyleXfs count="1"> <xf applyAlignment="0" applyBorder="0" applyFont="0" applyFill="0" applyNumberFormat="0" applyProtection="0" borderId="0" fillId="0" fontId="0" numFmtId="0"> <alignment horizontal="general" indent="0" shrinkToFit="0" textRotation="0" vertical="bottom" wrapText="0"/> </xf> </cellStyleXfs> <cellXfs count="8"> <xf applyAlignment="0" applyBorder="0" applyFont="0" applyFill="0" applyNumberFormat="0" applyProtection="0" borderId="0" fillId="0" fontId="0" numFmtId="0"> <alignment horizontal="general" indent="0" shrinkToFit="0" textRotation="0" vertical="bottom" wrapText="0"/> </xf> <xf applyAlignment="0" applyBorder="0" applyFont="0" applyFill="0" applyNumberFormat="1" applyProtection="0" borderId="0" fillId="0" fontId="0" numFmtId="164"> <alignment horizontal="general" indent="0" shrinkToFit="0" textRotation="0" vertical="bottom" wrapText="0"/> </xf> <xf applyAlignment="0" applyBorder="0" applyFont="0" applyFill="0" applyNumberFormat="1" applyProtection="0" borderId="0" fillId="0" fontId="0" numFmtId="165"> <alignment horizontal="general" indent="0" shrinkToFit="0" textRotation="0" vertical="bottom" wrapText="0"/> </xf> <xf applyAlignment="0" applyBorder="0" applyFont="0" applyFill="0" applyNumberFormat="1" applyProtection="0" borderId="0" fillId="0" fontId="0" numFmtId="166"> <alignment horizontal="general" indent="0" shrinkToFit="0" textRotation="0" vertical="bottom" wrapText="0"/> </xf> <xf applyAlignment="0" applyBorder="0" applyFont="0" applyFill="0" applyNumberFormat="1" applyProtection="0" borderId="0" fillId="0" fontId="0" numFmtId="167"> <alignment horizontal="general" indent="0" shrinkToFit="0" textRotation="0" vertical="bottom" wrapText="0"/> </xf> <xf applyAlignment="0" applyBorder="0" applyFont="0" applyFill="0" applyNumberFormat="1" applyProtection="0" borderId="0" fillId="0" fontId="0" numFmtId="168"> <alignment horizontal="general" indent="0" shrinkToFit="0" textRotation="0" vertical="bottom" wrapText="0"/> </xf> <xf applyAlignment="0" applyBorder="0" applyFont="0" applyFill="0" applyNumberFormat="1" applyProtection="0" borderId="0" fillId="0" fontId="0" numFmtId="169"> <alignment horizontal="general" indent="0" shrinkToFit="0" textRotation="0" vertical="bottom" wrapText="0"/> </xf> <xf applyAlignment="0" applyBorder="0" applyFont="0" applyFill="0" applyNumberFormat="1" applyProtection="0" borderId="0" fillId="0" fontId="0" numFmtId="170"> <alignment horizontal="general" indent="0" shrinkToFit="0" textRotation="0" vertical="bottom" wrapText="0"/> </xf> </cellXfs> </styleSheet>
13. Formátování časových údajů a dat
V běžných tabulkách se velmi často pracuje s časovými údaji a pravděpodobně ještě častěji s daty (resp. s kombinací datum+čas). Tyto údaje, které jsou interně reprezentovány číslem s řádovou čárkou, je možné zobrazit mnoha různými způsoby, které jsou specifikovány formátovacím řetězcem. Ukažme si použití následujících formátů, kde „y“ představuje rok, „m“ měsíc, „d“ den atd.:
"yyyy-mm-dd" "m/d" "m/d/yyyy" "dd/mm/yyyy" "dd/mm/yy" "yyyy-mm-dd hh:mm:ss" "hh:mm" "hh:mm:ss" "h:mm:ss" "[h]:mm:ss" "[mm]:ss"
V následujícím demonstračním příkladu je ukázáno, jak lze nastavit styl zobrazení buněk s časovými údaji (což vlastně znamená přiřazení formátovacího řetězce buňce):
package main import ( "fmt" "time" "github.com/tealeg/xlsx/v3" ) // jméno generovaného souboru const spreadsheetName = "test12.xlsx" func main() { // konstrukce struktury typu File worksheet := xlsx.NewFile() fmt.Println(worksheet) // přidání listu do sešitu sheet, err := worksheet.AddSheet("Tabulka1") if err != nil { panic(err) } defer sheet.Close() fmt.Println(sheet) // formáty časového razítka, které si odzkoušíme formats := []string{ "yyyy-mm-dd", "m/d", "m/d/yyyy", "dd/mm/yyyy", "dd/mm/yy", "yyyy-mm-dd hh:mm:ss", "hh:mm", "hh:mm:ss", "h:mm:ss", "[h]:mm:ss", "[mm]:ss", } // aktuální datum a čas timestamp := time.Now() // zobrazit tabulku s daty/časy naformátovanými zvoleným formátem for _, format := range formats { // přidání nového řádku do tabulky row := sheet.AddRow() // popis formátu row.AddCell().SetString(format) // naformátované časové razítko cell := row.AddCell() cell.SetDateTime(timestamp) cell.SetFormat(format) } // pokus o uložení sešitu err = worksheet.Save(spreadsheetName) if err != nil { panic(err) } }
Z obsahu souboru sheet1.xml je patrné, že hodnoty ve druhém sloupci jsou skutečně shodné, ovšem odkaz na styl je pokaždé odlišný:
<?xml version="1.0" encoding="UTF-8"?> <worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"> <sheetPr filterMode="false"> <pageSetUpPr fitToPage="false"/> </sheetPr> <dimension ref="A1:B11"/> <sheetViews> <sheetView windowProtection="false" showFormulas="false" showGridLines="true" showRowColHeaders="true" showZeros="true" rightToLeft="false" tabSelected="true" showOutlineSymbols="true" defaultGridColor="true" view="normal" topLeftCell="A1" colorId="64" zoomScale="100" zoomScaleNormal="100" zoomScalePageLayoutView="100" workbookViewId="0"> <selection pane="topLeft" activeCell="A1" activeCellId="0" sqref="A1"/> </sheetView> </sheetViews> <sheetFormatPr defaultRowHeight="12.85"/> <sheetData> <row r="1"> <c r="A1" t="s"> <v>0</v> </c> <c r="B1" s="1"> <v>44069.7353125</v> </c> </row> <row r="2"> <c r="A2" t="s"> <v>1</v> </c> <c r="B2" s="2"> <v>44069.7353125</v> </c> </row> <row r="3"> <c r="A3" t="s"> <v>2</v> </c> <c r="B3" s="3"> <v>44069.7353125</v> </c> </row> <row r="4"> <c r="A4" t="s"> <v>3</v> </c> <c r="B4" s="4"> <v>44069.7353125</v> </c> </row> <row r="5"> <c r="A5" t="s"> <v>4</v> </c> <c r="B5" s="5"> <v>44069.7353125</v> </c> </row> <row r="6"> <c r="A6" t="s"> <v>5</v> </c> <c r="B6" s="6"> <v>44069.7353125</v> </c> </row> <row r="7"> <c r="A7" t="s"> <v>6</v> </c> <c r="B7" s="7"> <v>44069.7353125</v> </c> </row> <row r="8"> <c r="A8" t="s"> <v>7</v> </c> <c r="B8" s="8"> <v>44069.7353125</v> </c> </row> <row r="9"> <c r="A9" t="s"> <v>8</v> </c> <c r="B9" s="9"> <v>44069.7353125</v> </c> </row> <row r="10"> <c r="A10" t="s"> <v>9</v> </c> <c r="B10" s="10"> <v>44069.7353125</v> </c> </row> <row r="11"> <c r="A11" t="s"> <v>10</v> </c> <c r="B11" s="11"> <v>44069.7353125</v> </c> </row> </sheetData> </worksheet>
Začátek obsahu souboru styles.xml se specifikací formátovacích řetězců:
$ xmllint --format styles.xml <?xml version="1.0" encoding="UTF-8"?> <styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"> <numFmts count="9"> <numFmt numFmtId="164" formatCode="yyyy-mm-dd"/> <numFmt numFmtId="165" formatCode="m/d"/> <numFmt numFmtId="166" formatCode="m/d/yyyy"/> <numFmt numFmtId="167" formatCode="dd/mm/yyyy"/> <numFmt numFmtId="168" formatCode="dd/mm/yy"/> <numFmt numFmtId="169" formatCode="yyyy-mm-dd hh:mm:ss"/> <numFmt numFmtId="170" formatCode="hh:mm"/> <numFmt numFmtId="171" formatCode="hh:mm:ss"/> <numFmt numFmtId="172" formatCode="[mm]:ss"/> </numFmts> ... ... ...
14. Pomocné funkce pro konverzi časových údajů
Pro snadnější práci s časovými údaji je dostupných několik funkcí provádějících konverzi mezi několika formáty času (a data):
# | Funkce | Stručný popis |
---|---|---|
1 | TimeFromExcelTime | konverze času z Excelovského formátu (číslo s plovoucí čárkou) na hodnotu typu time.Time |
2 | TimeToExcelTime | provádí opačnou konverzi než první funkce |
3 | TimeToUTCTime | konverze ze standardní reprezentace času do UTC |
15. Explicitně nastavené styly zobrazení
Na závěr si ukažme, jak se do sešitu uloží explicitně nastavené styly zobrazení. I následující příklad jsme již mohli vidět v předchozí části tohoto seriálu – nastavujeme v něm styl jediné buňky na listu:
package main import ( "fmt" "github.com/tealeg/xlsx/v3" ) // jméno generovaného souboru const spreadsheetName = "test10.xlsx" func main() { // konstrukce struktury typu File worksheet := xlsx.NewFile() fmt.Println(worksheet) // přidání listu do sešitu sheet, err := worksheet.AddSheet("Tabulka1") if err != nil { panic(err) } defer sheet.Close() fmt.Println(sheet) // přidání řádku do tabulky row := sheet.AddRow() style := xlsx.NewStyle() style.Alignment.Horizontal = "right" style.Fill.FgColor = "FFa0FFa0" style.Fill.PatternType = "solid" style.Font.Bold = true style.ApplyAlignment = true style.ApplyFill = true style.ApplyFont = true // přidání buňky na řádek a naplnění hodnotou cell := row.AddCell() cell.SetString("Test") // nastavení stylu buňky cell.SetStyle(style) // pokus o uložení sešitu err = worksheet.Save(spreadsheetName) if err != nil { panic(err) } }
Obsah souboru se sešitem neobsahuje žádné doplňkové informace, kromě odkazu na styl s ID=1 (zvýrazněný atribut):
<?xml version="1.0" encoding="UTF-8"?> <worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"> <sheetPr filterMode="false"> <pageSetUpPr fitToPage="false"/> </sheetPr> <dimension ref="A1"/> <sheetViews> <sheetView windowProtection="false" showFormulas="false" showGridLines="true" showRowColHeaders="true" showZeros="true" rightToLeft="false" tabSelected="true" showOutlineSymbols="true" defaultGridColor="true" view="normal" topLeftCell="A1" colorId="64" zoomScale="100" zoomScaleNormal="100" zoomScalePageLayoutView="100" workbookViewId="0"> <selection pane="topLeft" activeCell="A1" activeCellId="0" sqref="A1"/> </sheetView> </sheetViews> <sheetFormatPr defaultRowHeight="12.85"/> <sheetData> <row r="1"> <c r="A1" s="1" t="s"> <v>0</v> </c> </row> </sheetData> </worksheet>
Samotný styl je umístěn samostatně:
<?xml version="1.0" encoding="UTF-8"?> <styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"> <fonts count="2"> <font> <sz val="11"/> <name val="Arial"/> <family val="2"/> <color theme="1"/> <scheme val="minor"/> </font> <font> <sz val="12"/> <name val="Verdana"/> <family val="0"/> <charset val="0"/> <b/> </font> </fonts> <fills count="4"> <fill> <patternFill patternType="none"/> </fill> <fill> <patternFill patternType="gray125"/> </fill> <fill> <patternFill patternType="solid"> <fgColor rgb="FFa0FFa0"/> </patternFill> </fill> <fill> <patternFill patternType="lightGray"/> </fill> </fills> <borders count="2"> <border> <left/> <right/> <top/> <bottom/> </border> <border> <left style="none"/> <right style="none"/> <top style="none"/> <bottom style="none"/> </border> </borders> <cellStyleXfs count="1"> <xf applyAlignment="0" applyBorder="0" applyFont="0" applyFill="0" applyNumberFormat="0" applyProtection="0" borderId="0" fillId="0" fontId="0" numFmtId="0"> <alignment horizontal="general" indent="0" shrinkToFit="0" textRotation="0" vertical="bottom" wrapText="0"/> </xf> </cellStyleXfs> <cellXfs count="2"> <xf applyAlignment="0" applyBorder="0" applyFont="0" applyFill="0" applyNumberFormat="0" applyProtection="0" borderId="0" fillId="0" fontId="0" numFmtId="0"> <alignment horizontal="general" indent="0" shrinkToFit="0" textRotation="0" vertical="bottom" wrapText="0"/> </xf> <xf applyAlignment="1" applyBorder="0" applyFont="1" applyFill="1" applyNumberFormat="0" applyProtection="0" borderId="1" fillId="2" fontId="1" numFmtId="0"> <alignment horizontal="right" indent="0" shrinkToFit="0" textRotation="0" vertical="bottom" wrapText="0"/> </xf> </cellXfs> </styleSheet>
Příkladem nepřímého použití stylů je specifikace barvy výplně buňky:
<fill> <patternFill patternType="solid"> <fgColor rgb="FFa0FFa0"/> </patternFill> </fill>
Tento styl výplně je referencován zde (zvýrazněný atribut):
<xf applyAlignment="1" applyBorder="0" applyFont="1" applyFill="1" applyNumberFormat="0" applyProtection="0" borderId="1" fillId="2" fontId="1" numFmtId="0"> <alignment horizontal="right" indent="0" shrinkToFit="0" textRotation="0" vertical="bottom" wrapText="0"/> </xf>
16. Závěrem
Při pohledu na zdrojové kódy demonstračních příkladů a současně i na interní strukturu souborů .xlsx je patrné, že samotná tvorba sešitů vlastně není příliš komplikovaná (na rozdíl od již zmíněného původního formátu .xls). Ovšem tvorba nových sešitů je pouze polovina práce (a to ta snadnější) – většinou totiž potřebujeme sešity i načítat, provádět v nich změny a ty ukládat bez toho, aby se poškodil zbylý obsah sešitu. A právě touto problematikou se budeme věnovat v navazujícím článku.
17. Repositář s demonstračními příklady
Zdrojové kódy všech dnes použitých demonstračních příkladů byly uloženy do nového Git repositáře, který je dostupný na adrese https://github.com/tisnik/go-root (stále na GitHubu :-). V případě, že nebudete chtít klonovat celý repositář (ten je ovšem – alespoň prozatím – velmi malý, dnes má přibližně stovku kilobajtů), můžete namísto toho použít odkazy na jednotlivé demonstrační příklady, které naleznete v následující tabulce:
18. Odkazy na Internetu
- Spreadsheet
https://en.wikipedia.org/wiki/Spreadsheet - List of spreadsheet software
https://en.wikipedia.org/wiki/List_of_spreadsheet_software - Processing spreadsheet data in Go
https://appliedgo.net/spreadsheet/ - Package encoding/csv
https://golang.org/pkg/encoding/csv/#example_Writer - Package sheets
https://godoc.org/google.golang.org/api/sheets/v4 - Package xlsx
https://github.com/tealeg/xlsx - Comma-separated values
https://en.wikipedia.org/wiki/Comma-separated_values - Common Format and MIME Type for Comma-Separated Values (CSV) Files
https://tools.ietf.org/html/rfc4180 - Tab-separated values
https://en.wikipedia.org/wiki/Tab-separated_values - Office Open XML (Wikipedia)
https://en.wikipedia.org/wiki/Office_Open_XML - Standard ECMA-376: Office Open XML File Formats
https://www.ecma-international.org/publications/standards/Ecma-376.htm - Adventure for the Atari 2600 Video Game Console by Warren Robinett
http://www.warrenrobinett.com/adventure/index.html - Mapa hry Adventure
http://www.warrenrobinett.com/adventure/adv-map1.gif - Integration Basics
https://gafferongames.com/post/integration_basics/ - Fix Your Timestep!
https://gafferongames.com/post/fix_your_timestep/ - Handling variable frame rate in SDL2
https://gamedev.stackexchange.com/questions/151877/handling-variable-frame-rate-in-sdl2 - Too Fast! (SDL fórum)
https://discourse.libsdl.org/t/too-fast/11128 - Performance tricks (SDL fórum)
https://discourse.libsdl.org/t/performance-tricks/6685 - Achieving a constant frame rate in SDL
https://stackoverflow.com/questions/2548541/achieving-a-constant-frame-rate-in-sdl - Object’s speed control against different framerates
https://discourse.libsdl.org/t/objects-speed-control-against-different-framerates/14497/1 - Stránky projektu SDL
http://www.libsdl.org/ - Simple DirectMedia Layer (Wikipedia)
https://en.wikipedia.org/wiki/Simple_DirectMedia_Layer - SDL Language Bindings
http://www.libsdl.org/languages.php - SDL version 1.2.15
http://www.libsdl.org/download-1.2.php - SDL version 2.0.1
http://www.libsdl.org/download-2.0.php - Rozhraní go-sdl2
https://github.com/veandco/go-sdl2 - Dokumentace k rozhraní go-sdl2
https://godoc.org/github.com/veandco/go-sdl2 - Dokumentace k balíčku sdl
https://godoc.org/github.com/veandco/go-sdl2/sdl - Dokumentace k balíčku gfx
https://godoc.org/github.com/veandco/go-sdl2/gfx - Cross-platform games development (part 1)
http://renatoc.wait4.org/2010/02/04/cross-platform-games-development-part-1/ - Cross-platform games development (part 2)
http://renatoc.wait4.org/tag/sdljava/ - Go Data Structures: Binary Search Tree
https://flaviocopes.com/golang-data-structure-binary-search-tree/ - Gobs of data
https://blog.golang.org/gobs-of-data - Formát BSON
http://bsonspec.org/ - Golang Guide: A List of Top Golang Frameworks, IDEs & Tools
https://blog.intelligentbee.com/2017/08/14/golang-guide-list-top-golang-frameworks-ides-tools/ - Tvorba univerzálních projevů
http://www.kyblsoft.cz/projevy - Repositář projektu Gift
https://github.com/disintegration/gift - Dokumentace k projektu Gift
https://godoc.org/github.com/disintegration/gift - Online x86 / x64 Assembler and Disassembler
https://defuse.ca/online-x86-assembler.htm#disassembly2 - The Design of the Go Assembler
https://talks.golang.org/2016/asm.slide#1 - A Quick Guide to Go's Assembler
https://golang.org/doc/asm - AssemblyPolicy
https://github.com/golang/go/wiki/AssemblyPolicy - Geohash in Golang Assembly
https://mmcloughlin.com/posts/geohash-assembly - Command objdump
https://golang.org/cmd/objdump/ - Assembly
https://goroutines.com/asm - Go & Assembly
http://www.doxsey.net/blog/go-and-assembly - A Foray Into Go Assembly Programming
https://blog.sgmansfield.com/2017/04/a-foray-into-go-assembly-programming/ - Golang Capturing log.Println And fmt.Println Output
https://medium.com/@hau12a1/golang-capturing-log-println-and-fmt-println-output-770209c791b4 - Stránka projektu plotly
https://plot.ly/ - Plotly JavaScript Open Source Graphing Library
https://plot.ly/javascript/ - Domain coloring
https://en.wikipedia.org/wiki/Domain_coloring - Michael Fogleman's projects
https://www.michaelfogleman.com/projects/tagged/graphics/ - Color Graphs of Complex Functions
https://web.archive.org/web/20120511021419/http://w.american.edu/cas/mathstat/lcrone/ComplexPlot.html - A Gallery of Complex Functions
http://wismuth.com/complex/gallery.html - package glot
https://godoc.org/github.com/Arafatk/glot - Gnuplotting: Output terminals
http://www.gnuplotting.org/output-terminals/ - Introducing Glot the plotting library for Golang
https://medium.com/@Arafat./introducing-glot-the-plotting-library-for-golang-3133399948a1 - Introducing Glot the plotting library for Golang
https://blog.gopheracademy.com/advent-2018/introducing-glot/ - Glot is a plotting library for Golang built on top of gnuplot
https://github.com/Arafatk/glot - Example plots (gonum/plot)
https://github.com/gonum/plot/wiki/Example-plots - A repository for plotting and visualizing data (gonum/plot)
https://github.com/gonum/plot - golang library to make https://chartjs.org/ plots
https://github.com/brentp/go-chartjs - Gorilla REPL: interaktivní prostředí pro programovací jazyk Clojure
https://www.root.cz/clanky/gorilla-repl-interaktivni-prostredi-pro-programovaci-jazyk-clojure/ - The Gonum Numerical Computing Package
https://www.gonum.org/post/introtogonum/ - Gomacro na GitHubu
https://github.com/cosmos72/gomacro - gophernotes – Use Go in Jupyter notebooks and nteract
https://github.com/gopherdata/gophernotes - gonum
https://github.com/gonum - go-gota/gota – DataFrames and data wrangling in Go (Golang)
https://porter.io/github.com/go-gota/gota - A repository for plotting and visualizing data
https://github.com/gonum/plot - Gonum Numerical Packages
https://www.gonum.org/ - Stránky projektu MinIO
https://min.io/ - MinIO Quickstart Guide
https://docs.min.io/docs/minio-quickstart-guide.html - MinIO Go Client API Reference
https://docs.min.io/docs/golang-client-api-reference - MinIO Python Client API Reference
https://docs.min.io/docs/python-client-api-reference.html - Performance at Scale: MinIO Pushes Past 1.4 terabits per second with 256 NVMe Drives
https://blog.min.io/performance-at-scale-minio-pushes-past-1–3-terabits-per-second-with-256-nvme-drives/ - Benchmarking MinIO vs. AWS S3 for Apache Spark
https://blog.min.io/benchmarking-apache-spark-vs-aws-s3/ - MinIO Client Quickstart Guide
https://docs.min.io/docs/minio-client-quickstart-guide.html - Analýza kvality zdrojových kódů Minia
https://goreportcard.com/report/github.com/minio/minio - This is MinIO
https://www.youtube.com/watch?v=vF0lQh0XOCs - Running MinIO Standalone
https://www.youtube.com/watch?v=dIQsPCHvHoM - „Amazon S3 Compatible Storage in Kubernetes“ – Rob Girard, Principal Tech Marketing Engineer, Minio
https://www.youtube.com/watch?v=wlpn8K0jJ4U - Ginkgo
http://onsi.github.io/ginkgo/ - Gomega
https://onsi.github.io/gomega/ - Ginkgo's Preferred Matcher Library na GitHubu
https://github.com/onsi/gomega/ - Provided Matchers
http://onsi.github.io/gomega/#provided-matchers - Dokumentace k balíčku goexpect
https://godoc.org/github.com/google/goexpect - Balíček goexpect
https://github.com/google/goexpect - Balíček go-expect
https://github.com/Netflix/go-expect - Balíček gexpect
https://github.com/ThomasRooney/gexpect - Expect (originál naprogramovaný v TCL)
https://core.tcl-lang.org/expect/index - Expect (Wikipedia)
https://en.wikipedia.org/wiki/Expect - Pexpect
https://pexpect.readthedocs.io/en/stable/ - Golang SSH Client: Multiple Commands, Crypto & Goexpect Examples
http://networkbit.ch/golang-ssh-client/ - goblin na GitHubu
https://github.com/franela/goblin - Mocha framework
https://mochajs.org/ - frisby na GitHubu
https://github.com/verdverm/frisby - package frisby
https://godoc.org/github.com/verdverm/frisby - Frisby alternatives and similar packages (generováno)
https://go.libhunt.com/frisby-alternatives - Cucumber for golang
https://github.com/DATA-DOG/godog - How to Use Godog for Behavior-driven Development in Go
https://semaphoreci.com/community/tutorials/how-to-use-godog-for-behavior-driven-development-in-go - Comparative Analysis Of GoLang Testing Frameworks
https://www.slideshare.net/DushyantBhalgami/comparative-analysis-of-golang-testing-frameworks - A Quick Guide to Testing in Golang
https://caitiem.com/2016/08/18/a-quick-guide-to-testing-in-golang/ - Tom's Obvious, Minimal Language.
https://github.com/toml-lang/toml - xml.org
http://www.xml.org/ - Soubory .properties
https://en.wikipedia.org/wiki/.properties - Soubory INI
https://en.wikipedia.org/wiki/INI_file - JSON to YAML
https://www.json2yaml.com/ - Data Format Converter
https://toolkit.site/format.html - Viper na GitHubu
https://github.com/spf13/viper - GoDotEnv na GitHubu
https://github.com/joho/godotenv - The fantastic ORM library for Golang
http://gorm.io/ - Dokumentace k balíčku gorilla/mux
https://godoc.org/github.com/gorilla/mux - Gorilla web toolkitk
http://www.gorillatoolkit.org/ - Metric types
https://prometheus.io/docs/concepts/metric_types/ - Histograms with Prometheus: A Tale of Woe
http://linuxczar.net/blog/2017/06/15/prometheus-histogram-2/ - Why are Prometheus histograms cumulative?
https://www.robustperception.io/why-are-prometheus-histograms-cumulative - Histograms and summaries
https://prometheus.io/docs/practices/histograms/ - Instrumenting Golang server in 5 min
https://medium.com/@gsisimogang/instrumenting-golang-server-in-5-min-c1c32489add3 - Semantic Import Versioning in Go
https://www.aaronzhuo.com/semantic-import-versioning-in-go/ - Sémantické verzování
https://semver.org/ - Getting started with Go modules
https://medium.com/@fonseka.live/getting-started-with-go-modules-b3dac652066d - Create projects independent of $GOPATH using Go Modules
https://medium.com/mindorks/create-projects-independent-of-gopath-using-go-modules-802260cdfb51o - Anatomy of Modules in Go
https://medium.com/rungo/anatomy-of-modules-in-go-c8274d215c16 - Modules
https://github.com/golang/go/wiki/Modules - Go Modules Tutorial
https://tutorialedge.net/golang/go-modules-tutorial/ - Module support
https://golang.org/cmd/go/#hdr-Module_support - Go Lang: Memory Management and Garbage Collection
https://vikash1976.wordpress.com/2017/03/26/go-lang-memory-management-and-garbage-collection/ - Golang Internals, Part 4: Object Files and Function Metadata
https://blog.altoros.com/golang-part-4-object-files-and-function-metadata.html - What is REPL?
https://pythonprogramminglanguage.com/repl/ - What is a REPL?
https://codewith.mu/en/tutorials/1.0/repl - Programming at the REPL: Introduction
https://clojure.org/guides/repl/introduction - What is REPL? (Quora)
https://www.quora.com/What-is-REPL - Gorilla REPL: interaktivní prostředí pro programovací jazyk Clojure
https://www.root.cz/clanky/gorilla-repl-interaktivni-prostredi-pro-programovaci-jazyk-clojure/ - Read-eval-print loop (Wikipedia)
https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop - Vim as a Go (Golang) IDE using LSP and vim-go
https://octetz.com/posts/vim-as-go-ide - gopls
https://github.com/golang/go/wiki/gopls - IDE Integration Guide
https://github.com/stamblerre/gocode/blob/master/docs/IDE_integration.md - How to instrument Go code with custom expvar metrics
https://sysdig.com/blog/golang-expvar-custom-metrics/ - Golang expvar metricset (Metricbeat Reference)
https://www.elastic.co/guide/en/beats/metricbeat/7.x/metricbeat-metricset-golang-expvar.html - Package expvar
https://golang.org/pkg/expvar/#NewInt - Java Platform Debugger Architecture: Overview
https://docs.oracle.com/en/java/javase/11/docs/specs/jpda/jpda.html - The JVM Tool Interface (JVM TI): How VM Agents Work
https://www.oracle.com/technetwork/articles/javase/index-140680.html - JVM Tool Interface Version 11.0
https://docs.oracle.com/en/java/javase/11/docs/specs/jvmti.html - Creating a Debugging and Profiling Agent with JVMTI
http://www.oracle.com/technetwork/articles/javase/jvmti-136367.html - JVM TI (Wikipedia)
http://en.wikipedia.org/wiki/JVM_TI - IBM JVMTI extensions
http://publib.boulder.ibm.com/infocenter/realtime/v2r0/index.jsp?topic=%2Fcom.ibm.softrt.doc%2Fdiag%2Ftools%2Fjvmti_extensions.html - Go & cgo: integrating existing C code with Go
http://akrennmair.github.io/golang-cgo-slides/#1 - Using cgo to call C code from within Go code
https://wenzr.wordpress.com/2018/06/07/using-cgo-to-call-c-code-from-within-go-code/ - Package trace
https://golang.org/pkg/runtime/trace/ - Introducing HTTP Tracing
https://blog.golang.org/http-tracing - Command trace
https://golang.org/cmd/trace/ - A StreamLike, Immutable, Lazy Loading and smart Golang Library to deal with slices
https://github.com/wesovilabs/koazee - Funkce vyššího řádu v knihovně Underscore
https://www.root.cz/clanky/funkce-vyssiho-radu-v-knihovne-underscore/ - Delve: a debugger for the Go programming language.
https://github.com/go-delve/delve - Příkazy debuggeru Delve
https://github.com/go-delve/delve/tree/master/Documentation/cli - Debuggery a jejich nadstavby v Linuxu
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu/ - Debuggery a jejich nadstavby v Linuxu (2. část)
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-2-cast/ - Debuggery a jejich nadstavby v Linuxu (3): Nemiver
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-3-nemiver/ - Debuggery a jejich nadstavby v Linuxu (4): KDbg
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-4-kdbg/ - Debuggery a jejich nadstavby v Linuxu (5): ladění aplikací v editorech Emacs a Vim
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-5-ladeni-aplikaci-v-editorech-emacs-a-vim/ - Debugging Go Code with GDB
https://golang.org/doc/gdb - Debugging Go (golang) programs with gdb
https://thornydev.blogspot.com/2014/01/debugging-go-golang-programs-with-gdb.html - GDB – Dokumentace
http://sourceware.org/gdb/current/onlinedocs/gdb/ - GDB – Supported Languages
http://sourceware.org/gdb/current/onlinedocs/gdb/Supported-Languages.html#Supported-Languages - GNU Debugger (Wikipedia)
https://en.wikipedia.org/wiki/GNU_Debugger - The LLDB Debugger
http://lldb.llvm.org/ - Debugger (Wikipedia)
https://en.wikipedia.org/wiki/Debugger - 13 Linux Debuggers for C++ Reviewed
http://www.drdobbs.com/testing/13-linux-debuggers-for-c-reviewed/240156817 - Go is on a Trajectory to Become the Next Enterprise Programming Language
https://hackernoon.com/go-is-on-a-trajectory-to-become-the-next-enterprise-programming-language-3b75d70544e - Go Proverbs: Simple, Poetic, Pithy
https://go-proverbs.github.io/ - Handling Sparse Files on Linux
https://www.systutorials.com/136652/handling-sparse-files-on-linux/ - Gzip (Wikipedia)
https://en.wikipedia.org/wiki/Gzip - Deflate
https://en.wikipedia.org/wiki/DEFLATE - 10 tools written in Go that every developer needs to know
https://gustavohenrique.net/en/2019/01/10-tools-written-in-go-that-every-dev-needs-to-know/ - Hexadecimální prohlížeče a editory s textovým uživatelským rozhraním
https://www.root.cz/clanky/hexadecimalni-prohlizece-a-editory-s-textovym-uzivatelskym-rozhranim/ - Hex dump
https://en.wikipedia.org/wiki/Hex_dump - Rozhraní io.ByteReader
https://golang.org/pkg/io/#ByteReader - Rozhraní io.RuneReader
https://golang.org/pkg/io/#RuneReader - Rozhraní io.ByteScanner
https://golang.org/pkg/io/#ByteScanner - Rozhraní io.RuneScanner
https://golang.org/pkg/io/#RuneScanner - Rozhraní io.Closer
https://golang.org/pkg/io/#Closer - Rozhraní io.Reader
https://golang.org/pkg/io/#Reader - Rozhraní io.Writer
https://golang.org/pkg/io/#Writer - Typ Strings.Reader
https://golang.org/pkg/strings/#Reader - VACUUM (SQL)
https://www.sqlite.org/lang_vacuum.html - VACUUM (Postgres)
https://www.postgresql.org/docs/8.4/sql-vacuum.html - go-cron
https://github.com/rk/go-cron - gocron
https://github.com/jasonlvhit/gocron - clockwork
https://github.com/whiteShtef/clockwork - clockwerk
https://github.com/onatm/clockwerk - JobRunner
https://github.com/bamzi/jobrunner - Rethinking Cron
https://adam.herokuapp.com/past/2010/4/13/rethinking_cron/ - In the Beginning was the Command Line
https://web.archive.org/web/20180218045352/http://www.cryptonomicon.com/beginning.html - repl.it (REPL pro různé jazyky)
https://repl.it/languages - GOCUI – Go Console User Interface (celé uživatelské prostředí, nejenom input box)
https://github.com/jroimartin/gocui - Read–eval–print loop
https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop - go-prompt
https://github.com/c-bata/go-prompt - readline
https://github.com/chzyer/readline - A pure golang implementation for GNU-Readline kind library
https://golangexample.com/a-pure-golang-implementation-for-gnu-readline-kind-library/ - go-readline
https://github.com/fiorix/go-readline - 4 Python libraries for building great command-line user interfaces
https://opensource.com/article/17/5/4-practical-python-libraries - prompt_toolkit 2.0.3 na PyPi
https://pypi.org/project/prompt_toolkit/ - python-prompt-toolkit na GitHubu
https://github.com/jonathanslenders/python-prompt-toolkit - The GNU Readline Library
https://tiswww.case.edu/php/chet/readline/rltop.html - GNU Readline (Wikipedia)
https://en.wikipedia.org/wiki/GNU_Readline - readline — GNU readline interface (Python 3.x)
https://docs.python.org/3/library/readline.html - readline — GNU readline interface (Python 2.x)
https://docs.python.org/2/library/readline.html - GNU Readline Library – command line editing
https://tiswww.cwru.edu/php/chet/readline/readline.html - gnureadline 6.3.8 na PyPi
https://pypi.org/project/gnureadline/ - Editline Library (libedit)
http://thrysoee.dk/editline/ - Comparing Python Command-Line Parsing Libraries – Argparse, Docopt, and Click
https://realpython.com/comparing-python-command-line-parsing-libraries-argparse-docopt-click/ - libedit or editline
http://www.cs.utah.edu/~bigler/code/libedit.html - WinEditLine
http://mingweditline.sourceforge.net/ - rlcompleter — Completion function for GNU readline
https://docs.python.org/3/library/rlcompleter.html - rlwrap na GitHubu
https://github.com/hanslub42/rlwrap - rlwrap(1) – Linux man page
https://linux.die.net/man/1/rlwrap - readline(3) – Linux man page
https://linux.die.net/man/3/readline - history(3) – Linux man page
https://linux.die.net/man/3/history - Dokumentace k balíčku oglematchers
https://godoc.org/github.com/jacobsa/oglematchers - Balíček oglematchers
https://github.com/jacobsa/oglematchers - Dokumentace k balíčku ogletest
https://godoc.org/github.com/jacobsa/ogletest - Balíček ogletest
https://github.com/jacobsa/ogletest - Dokumentace k balíčku assert
https://godoc.org/github.com/stretchr/testify/assert - Testify – Thou Shalt Write Tests
https://github.com/stretchr/testify/ - package testing
https://golang.org/pkg/testing/ - Golang basics – writing unit tests
https://blog.alexellis.io/golang-writing-unit-tests/ - An Introduction to Programming in Go / Testing
https://www.golang-book.com/books/intro/12 - An Introduction to Testing in Go
https://tutorialedge.net/golang/intro-testing-in-go/ - Advanced Go Testing Tutorial
https://tutorialedge.net/golang/advanced-go-testing-tutorial/ - GoConvey
http://goconvey.co/ - Testing Techniques
https://talks.golang.org/2014/testing.slide - 5 simple tips and tricks for writing unit tests in #golang
https://medium.com/@matryer/5-simple-tips-and-tricks-for-writing-unit-tests-in-golang-619653f90742 - Afinní transformace
https://cs.wikibooks.org/wiki/Geometrie/Afinn%C3%AD_transformace_sou%C5%99adnic - package gg
https://godoc.org/github.com/fogleman/gg - Generate an animated GIF with Golang
http://tech.nitoyon.com/en/blog/2016/01/07/go-animated-gif-gen/ - Generate an image programmatically with Golang
http://tech.nitoyon.com/en/blog/2015/12/31/go-image-gen/ - The Go image package
https://blog.golang.org/go-image-package - Balíček draw2D: 2D rendering for different output (raster, pdf, svg)
https://github.com/llgcode/draw2d - Draw a rectangle in Golang?
https://stackoverflow.com/questions/28992396/draw-a-rectangle-in-golang - YAML
https://yaml.org/ - edn
https://github.com/edn-format/edn - Smile
https://github.com/FasterXML/smile-format-specification - Protocol-Buffers
https://developers.google.com/protocol-buffers/ - Marshalling (computer science)
https://en.wikipedia.org/wiki/Marshalling_(computer_science) - Unmarshalling
https://en.wikipedia.org/wiki/Unmarshalling - Introducing JSON
http://json.org/ - Package json
https://golang.org/pkg/encoding/json/ - The Go Blog: JSON and Go
https://blog.golang.org/json-and-go - Go by Example: JSON
https://gobyexample.com/json - Writing Web Applications
https://golang.org/doc/articles/wiki/ - Golang Web Apps
https://www.reinbach.com/blog/golang-webapps-1/ - Build web application with Golang
https://legacy.gitbook.com/book/astaxie/build-web-application-with-golang/details - Golang Templates – Golang Web Pages
https://www.youtube.com/watch?v=TkNIETmF-RU - Simple Golang HTTPS/TLS Examples
https://github.com/denji/golang-tls - Playing with images in HTTP response in golang
https://www.sanarias.com/blog/1214PlayingwithimagesinHTTPresponseingolang - MIME Types List
https://www.freeformatter.com/mime-types-list.html - Go Mutex Tutorial
https://tutorialedge.net/golang/go-mutex-tutorial/ - Creating A Simple Web Server With Golang
https://tutorialedge.net/golang/creating-simple-web-server-with-golang/ - Building a Web Server in Go
https://thenewstack.io/building-a-web-server-in-go/ - How big is the pipe buffer?
https://unix.stackexchange.com/questions/11946/how-big-is-the-pipe-buffer - How to turn off buffering of stdout in C
https://stackoverflow.com/questions/7876660/how-to-turn-off-buffering-of-stdout-in-c - setbuf(3) – Linux man page
https://linux.die.net/man/3/setbuf - setvbuf(3) – Linux man page (stejný obsah jako předchozí stránka)
https://linux.die.net/man/3/setvbuf - Select waits on a group of channels
https://yourbasic.org/golang/select-explained/ - Rob Pike: Simplicity is Complicated (video)
http://www.golang.to/posts/dotgo-2015-rob-pike-simplicity-is-complicated-youtube-16893 - Algorithms to Go
https://yourbasic.org/ - Využití knihovny Pygments (nejenom) pro obarvení zdrojových kódů
https://www.root.cz/clanky/vyuziti-knihovny-pygments-nejenom-pro-obarveni-zdrojovych-kodu/ - Využití knihovny Pygments (nejenom) pro obarvení zdrojových kódů: vlastní filtry a lexery
https://www.root.cz/clanky/vyuziti-knihovny-pygments-nejenom-pro-obarveni-zdrojovych-kodu-vlastni-filtry-a-lexery/ - Go Defer Simplified with Practical Visuals
https://blog.learngoprogramming.com/golang-defer-simplified-77d3b2b817ff - 5 More Gotchas of Defer in Go — Part II
https://blog.learngoprogramming.com/5-gotchas-of-defer-in-go-golang-part-ii-cc550f6ad9aa - The Go Blog: Defer, Panic, and Recover
https://blog.golang.org/defer-panic-and-recover - The defer keyword in Swift 2: try/finally done right
https://www.hackingwithswift.com/new-syntax-swift-2-defer - Swift Defer Statement
https://andybargh.com/swift-defer-statement/ - Modulo operation (Wikipedia)
https://en.wikipedia.org/wiki/Modulo_operation - Node.js vs Golang: Battle of the Next-Gen Languages
https://www.hostingadvice.com/blog/nodejs-vs-golang/ - The Go Programming Language (home page)
https://golang.org/ - GoDoc
https://godoc.org/ - Go (programming language), Wikipedia
https://en.wikipedia.org/wiki/Go_(programming_language) - Go Books (kniha o jazyku Go)
https://github.com/dariubs/GoBooks - The Go Programming Language Specification
https://golang.org/ref/spec - Go: the Good, the Bad and the Ugly
https://bluxte.net/musings/2018/04/10/go-good-bad-ugly/ - Package builtin
https://golang.org/pkg/builtin/ - Package fmt
https://golang.org/pkg/fmt/ - The Little Go Book (další kniha)
https://github.com/dariubs/GoBooks - The Go Programming Language by Brian W. Kernighan, Alan A. A. Donovan
https://www.safaribooksonline.com/library/view/the-go-programming/9780134190570/ebook_split010.html - Learning Go
https://www.miek.nl/go/ - Go Bootcamp
http://www.golangbootcamp.com/ - Programming in Go: Creating Applications for the 21st Century (další kniha o jazyku Go)
http://www.informit.com/store/programming-in-go-creating-applications-for-the-21st-9780321774637 - Introducing Go (Build Reliable, Scalable Programs)
http://shop.oreilly.com/product/0636920046516.do - Learning Go Programming
https://www.packtpub.com/application-development/learning-go-programming - The Go Blog
https://blog.golang.org/ - Getting to Go: The Journey of Go's Garbage Collector
https://blog.golang.org/ismmkeynote - Go (programovací jazyk, Wikipedia)
https://cs.wikipedia.org/wiki/Go_(programovac%C3%AD_jazyk) - Rychle, rychleji až úplně nejrychleji s jazykem Go
https://www.root.cz/clanky/rychle-rychleji-az-uplne-nejrychleji-s-jazykem-go/ - Installing Go on the Raspberry Pi
https://dave.cheney.net/2012/09/25/installing-go-on-the-raspberry-pi - How the Go runtime implements maps efficiently (without generics)
https://dave.cheney.net/2018/05/29/how-the-go-runtime-implements-maps-efficiently-without-generics - Niečo málo o Go – Golang (slovensky)
http://golangsk.logdown.com/ - How Many Go Developers Are There?
https://research.swtch.com/gophercount - Most Popular Technologies (Stack Overflow Survery 2018)
https://insights.stackoverflow.com/survey/2018/#most-popular-technologies - Most Popular Technologies (Stack Overflow Survery 2017)
https://insights.stackoverflow.com/survey/2017#technology - JavaScript vs. Golang for IoT: Is Gopher Winning?
https://www.iotforall.com/javascript-vs-golang-iot/ - The Go Programming Language: Release History
https://golang.org/doc/devel/release.html - Go 1.11 Release Notes
https://golang.org/doc/go1.11 - Go 1.10 Release Notes
https://golang.org/doc/go1.10 - Go 1.9 Release Notes (tato verze je stále používána)
https://golang.org/doc/go1.9 - Go 1.8 Release Notes (i tato verze je stále používána)
https://golang.org/doc/go1.8 - Go on Fedora
https://developer.fedoraproject.org/tech/languages/go/go-installation.html - Writing Go programs
https://developer.fedoraproject.org/tech/languages/go/go-programs.html - The GOPATH environment variable
https://tip.golang.org/doc/code.html#GOPATH - Command gofmt
https://tip.golang.org/cmd/gofmt/ - The Go Blog: go fmt your code
https://blog.golang.org/go-fmt-your-code - C? Go? Cgo!
https://blog.golang.org/c-go-cgo - Spaces vs. Tabs: A 20-Year Debate Reignited by Google’s Golang
https://thenewstack.io/spaces-vs-tabs-a-20-year-debate-and-now-this-what-the-hell-is-wrong-with-go/ - 400,000 GitHub repositories, 1 billion files, 14 terabytes of code: Spaces or Tabs?
https://medium.com/@hoffa/400–000-github-repositories-1-billion-files-14-terabytes-of-code-spaces-or-tabs-7cfe0b5dd7fd - Gofmt No Longer Allows Spaces. Tabs Only
https://news.ycombinator.com/item?id=7914523 - Why does Go „go fmt“ uses tabs instead of whitespaces?
https://www.quora.com/Why-does-Go-go-fmt-uses-tabs-instead-of-whitespaces - Interactive: The Top Programming Languages 2018
https://spectrum.ieee.org/static/interactive-the-top-programming-languages-2018 - Go vs. Python
https://www.peterbe.com/plog/govspy - PackageManagementTools
https://github.com/golang/go/wiki/PackageManagementTools - A Tour of Go: Type inference
https://tour.golang.org/basics/14 - Go Slices: usage and internals
https://blog.golang.org/go-slices-usage-and-internals - Go by Example: Slices
https://gobyexample.com/slices - What is the point of slice type in Go?
https://stackoverflow.com/questions/2098874/what-is-the-point-of-slice-type-in-go - The curious case of Golang array and slices
https://medium.com/@hackintoshrao/the-curious-case-of-golang-array-and-slices-2565491d4335 - Introduction to Slices in Golang
https://www.callicoder.com/golang-slices/ - Golang: Understanding ‚null‘ and nil
https://newfivefour.com/golang-null-nil.html - What does nil mean in golang?
https://stackoverflow.com/questions/35983118/what-does-nil-mean-in-golang - nils In Go
https://go101.org/article/nil.html - Go slices are not dynamic arrays
https://appliedgo.net/slices/ - Go-is-no-good (nelze brát doslova)
https://github.com/ksimka/go-is-not-good - Rust vs. Go
https://news.ycombinator.com/item?id=13430108 - Seriál Programovací jazyk Rust
https://www.root.cz/serialy/programovaci-jazyk-rust/ - Modern garbage collection: A look at the Go GC strategy
https://blog.plan99.net/modern-garbage-collection-911ef4f8bd8e - Go GC: Prioritizing low latency and simplicity
https://blog.golang.org/go15gc - Is Golang a good language for embedded systems?
https://www.quora.com/Is-Golang-a-good-language-for-embedded-systems - Running GoLang on an STM32 MCU. A quick tutorial.
https://www.mickmake.com/post/running-golang-on-an-mcu-a-quick-tutorial - Go, Robot, Go! Golang Powered Robotics
https://gobot.io/ - Emgo: Bare metal Go (language for programming embedded systems)
https://github.com/ziutek/emgo - UTF-8 history
https://www.cl.cam.ac.uk/~mgk25/ucs/utf-8-history.txt - Less is exponentially more
https://commandcenter.blogspot.com/2012/06/less-is-exponentially-more.html - Should I Rust, or Should I Go
https://codeburst.io/should-i-rust-or-should-i-go-59a298e00ea9 - Setting up and using gccgo
https://golang.org/doc/install/gccgo - Elastic Tabstops
http://nickgravgaard.com/elastic-tabstops/ - Strings, bytes, runes and characters in Go
https://blog.golang.org/strings - Datový typ
https://cs.wikipedia.org/wiki/Datov%C3%BD_typ - Seriál o programovacím jazyku Rust: Základní (primitivní) datové typy
https://www.root.cz/clanky/programovaci-jazyk-rust-nahrada-c-nebo-slepa-cesta/#k09 - Seriál o programovacím jazyku Rust: Vytvoření „řezu“ z pole
https://www.root.cz/clanky/prace-s-poli-v-programovacim-jazyku-rust/#k06 - Seriál o programovacím jazyku Rust: Řezy (slice) vektoru
https://www.root.cz/clanky/prace-s-vektory-v-programovacim-jazyku-rust/#k05 - Printf Format Strings
https://www.cprogramming.com/tutorial/printf-format-strings.html - Java: String.format
https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#format-java.lang.String-java.lang.Object…- - Java: format string syntax
https://docs.oracle.com/javase/8/docs/api/java/util/Formatter.html#syntax - Selectors
https://golang.org/ref/spec#Selectors - Calling Go code from Python code
http://savorywatt.com/2015/09/18/calling-go-code-from-python-code/ - Go Data Structures: Interfaces
https://research.swtch.com/interfaces - How to use interfaces in Go
http://jordanorelli.com/post/32665860244/how-to-use-interfaces-in-go - Interfaces in Go (part I)
https://medium.com/golangspec/interfaces-in-go-part-i-4ae53a97479c - Part 21: Goroutines
https://golangbot.com/goroutines/ - Part 22: Channels
https://golangbot.com/channels/ - [Go] Lightweight eventbus with async compatibility for Go
https://github.com/asaskevich/EventBus - What about Trait support in Golang?
https://www.reddit.com/r/golang/comments/8mfykl/what_about_trait_support_in_golang/ - Don't Get Bitten by Pointer vs Non-Pointer Method Receivers in Golang
https://nathanleclaire.com/blog/2014/08/09/dont-get-bitten-by-pointer-vs-non-pointer-method-receivers-in-golang/ - Control Flow
https://en.wikipedia.org/wiki/Control_flow - Structured programming
https://en.wikipedia.org/wiki/Structured_programming - Control Structures
https://www.golang-book.com/books/intro/5 - Control structures – Go if else statement
http://golangtutorials.blogspot.com/2011/06/control-structures-if-else-statement.html - Control structures – Go switch case statement
http://golangtutorials.blogspot.com/2011/06/control-structures-go-switch-case.html - Control structures – Go for loop, break, continue, range
http://golangtutorials.blogspot.com/2011/06/control-structures-go-for-loop-break.html - Goroutine IDs
https://blog.sgmansfield.com/2015/12/goroutine-ids/ - Different ways to pass channels as arguments in function in go (golang)
https://stackoverflow.com/questions/24868859/different-ways-to-pass-channels-as-arguments-in-function-in-go-golang - justforfunc #22: using the Go execution tracer
https://www.youtube.com/watch?v=ySy3sR1LFCQ - Single Function Exit Point
http://wiki.c2.com/?SingleFunctionExitPoint - Entry point
https://en.wikipedia.org/wiki/Entry_point - Why does Go have a GOTO statement?!
https://www.reddit.com/r/golang/comments/kag5q/why_does_go_have_a_goto_statement/ - Effective Go
https://golang.org/doc/effective_go.html - GoClipse: an Eclipse IDE for the Go programming language
http://goclipse.github.io/ - GoClipse Installation
https://github.com/GoClipse/goclipse/blob/latest/documentation/Installation.md#installation - The zero value of a slice is not nil
https://stackoverflow.com/questions/30806931/the-zero-value-of-a-slice-is-not-nil - Go-tcha: When nil != nil
https://dev.to/pauljlucas/go-tcha-when-nil–nil-hic - Nils in Go
https://www.doxsey.net/blog/nils-in-go