1. Načtení XML
Encoding/xml nabízí Unmarshal pro byte slice a Decoder pro io.Reader. Exportovaná pole a tagy struktury určují mapování. Následující úplný program zároveň vytvoří a serializuje XML a JSON; ulož jej jako main.go a spusť go run main.go.
package main
import (
"encoding/xml"
"encoding/json"
"fmt"
)
type Kniha struct {
XMLName xml.Name `xml:"kniha" json:"-"`
ID string `xml:"id,attr" json:"id"`
Nazev string `xml:"nazev" json:"nazev"`
}
func main() {
var k Kniha
if err := xml.Unmarshal([]byte(`<kniha id="1"><nazev>XML</nazev></kniha>`), &k); err != nil { panic(err) }
k.Nazev = "XML & JSON"
x, err := xml.Marshal(k); if err != nil { panic(err) }
fmt.Println(string(x))
j, err := json.Marshal(k); if err != nil { panic(err) }
fmt.Println(string(j))
var copy Kniha
if err := json.Unmarshal(j, ©); err != nil { panic(err) }
fmt.Println(copy.ID, copy.Nazev)
} 2. Vytvoření XML
Naplň strukturu Kniha nebo použij Encoder s tokeny. Namespace může být součástí xml tagu struktury. Mapování struktur není obecně bezeztrátová archivace libovolného smíšeného obsahu.
3. Serializace XML
Marshal a Encoder.Encode escapují text a atributy. MarshalIndent přidá odsazení. XMLName v ukázce určuje kořen a json tag jej vyřazuje z JSON reprezentace.
4. DOM
Encoding/xml je tokenový parser a mapování struktur, ne DOM API. Pokud potřebuješ libovolnou navigaci a úpravy stromu, použij vhodnou knihovnu a prověř její namespace model.
5. Streamové čtení
Decoder.Token vrací tokeny; DecodeElement načte vybraný element do struktury. Ukončení io.EOF odliš od chyby. Nezadržuj všechny dekódované záznamy ve slice, pokud chceš omezenou paměť.
6. XPath
Ve standardní knihovně XPath není. Pro známé struktury často stačí průchod tokeny. Knihovnu XPath vybírej podle verze a namespace podpory, nikoli podle názvu balíčku.
7. Validace XSD
Unmarshal neověří všechna pravidla XSD. Nepřítomná pole se mohou stát nulovými hodnotami. Použij samostatný validátor, pokud příjemce požaduje shodu s XSD.
8. Bezpečnost parseru
Decoder nevytváří síťový resolver DTD jako běžný validující XML procesor. Přesto omez vstup a hloubku. Strict nevynucuje všechna namespace pravidla; dokumentace výslovně upozorňuje na chování nedefinovaných prefixů.
9. Načtení JSON
Unmarshal do struktury je pohodlné; pro čtení z proudu použij json.Decoder. UseNumber zachová čísla v interface jako json.Number místo float64. DisallowUnknownFields zpřísní struktury, ale není kompletním JSON Schema.
10. Vytvoření JSON
Vytvoř strukturu nebo mapu se známými poli. Rozlišuj prázdné pole a nil slice podle požadované serializace. Zkontroluj omitempty, pokud je nulová hodnota významová; podrobně v sekci struct tagy a chybějící hodnoty.
11. Serializace JSON
Marshal nebo Encoder.Encode vytvoří JSON; kontroluj chybu, například pro NaN a Infinity. Encoding/json escapuje některé HTML znaky, což se může projevit v textu ukázky bez změny načtené hodnoty.
12. JSON Schema
Go standardní knihovna validátor neobsahuje. Použij knihovnu s explicitní podporou požadovaného draftu; ověř vzdálené reference i chování format. Runtime schéma doplňuje typy struktur, nenahrazuje je.
Primární dokumentace: encoding/xml a encoding/json.
Stream: výběr knih podle namespace
package main
import ("encoding/xml"; "fmt"; "io"; "os")
type Kniha struct {
XMLName xml.Name `xml:"urn:knihy kniha"`
ID string `xml:"id,attr"`
Nazev string `xml:"urn:knihy nazev"`
}
func main() {
f, err := os.Open("katalog.xml"); if err != nil { panic(err) }; defer f.Close()
info, err := f.Stat(); if err != nil { panic(err) }
if info.Size() > 10*1024*1024 { panic("Limit souboru") }
decoder := xml.NewDecoder(f)
for {
token, err := decoder.Token()
if err == io.EOF { break }; if err != nil { panic(err) }
start, ok := token.(xml.StartElement)
if !ok || start.Name.Space != "urn:knihy" || start.Name.Local != "kniha" { continue }
var k Kniha
if err := decoder.DecodeElement(&k, &start); err != nil { panic(err) }
fmt.Println(k.ID, k.Nazev)
}
} <katalog xmlns="urn:knihy"><kniha id="k1"><nazev>XML</nazev></kniha><kniha id="k2"><nazev>XPath</nazev></kniha></katalog> Výstup jsou řádky k1 XML a k2 XPath. Decoder čte postupně a každou knihu načte až při jejím startu. Kontrola namespace zabrání záměně s cizím elementem kniha. Po zpracování strukturu nezadržuj v rostoucím seznamu. Limit velikosti je zde kontrola známého lokálního souboru; pro příchozí stream musíš limitovat skutečné čtení a ošetřit truncation i hloubku.
XMLName a tagy struktur vyjadřují mapování, ne všechny podmínky XSD. Například chybějící Nazev může skončit jako prázdný string. Pro DOM a XPath lze zvolit xmlquery s vlastním stromovým modelem; pro XSD samostatný libxml2 procesor, například xmllint, nebo udržovaný binding. Ověř verzi i zabezpečení samostatné validační fáze.
JSON Schema v knihovně v6
package main
import (
"fmt"
"strings"
"github.com/santhosh-tekuri/jsonschema/v6"
)
func main() {
schema, err := jsonschema.UnmarshalJSON(strings.NewReader(`{
"$schema":"https://json-schema.org/draft/2020-12/schema",
"type":"object", "required":["id"],
"properties":{"id":{"type":"string"}}, "additionalProperties":false
}`)); if err != nil { panic(err) }
c := jsonschema.NewCompiler()
if err := c.AddResource("https://example.cz/schema/kniha", schema); err != nil { panic(err) }
compiled, err := c.Compile("https://example.cz/schema/kniha"); if err != nil { panic(err) }
for _, raw := range []string{`{"id":"001"}`, `{"id":1}`} {
data, err := jsonschema.UnmarshalJSON(strings.NewReader(raw)); if err != nil { panic(err) }
err = compiled.Validate(data)
fmt.Println(err == nil)
}
} Ve vlastní prázdné složce spusť go mod init ukazka, go get github.com/santhosh-tekuri/jsonschema/v6@v6.0.3 a go run schema.go. Výsledek je true a false. Schéma je registrováno lokálně pod URI a nevyžaduje stahovat example.cz. UnmarshalJSON je zde z knihovny validátoru, která používá vhodnou reprezentaci čísel. Tento krok je jiný než Go deserializace do struktury.
Neznámá pole u Go struktur může zpřísnit DisallowUnknownFields, ale neověří enum, pattern či logické kombinace schématu. U více JSON textů kontroluj po první hodnotě konec vstupu. API v6: oficiální dokumentace.
Struct tagy a chybějící hodnoty
Go nemá pro pole struktury stav „nenastaveno“. Když klíč ve vstupu chybí, zůstane v poli nulová hodnota typu: 0, "", false. Podle hodnoty 0 pak nepoznáš, jestli klient poslal nulu, nebo nic. Pole s ukazatelem (*int) tento rozdíl zachová: nil znamená, že hodnota nepřišla.
package main
import (
"encoding/json"
"encoding/xml"
"fmt"
"time"
)
type Produkt struct {
XMLName xml.Name `xml:"produkt" json:"-"`
Kod string `xml:"kod,attr" json:"kod"`
Nazev string `xml:"nazev" json:"nazev"`
Popis string `xml:",chardata" json:"-"`
Sleva int `xml:"sleva,omitempty" json:"sleva,omitempty"`
Sklad *int `xml:"sklad,omitempty" json:"sklad,omitempty"`
Stitky []string `xml:"stitek" json:"stitky,omitempty"`
Zmeneno time.Time `xml:"-" json:"zmeneno,omitzero"`
}
func main() {
for _, vstup := range []string{
`{"kod":"A1","nazev":"Hrnek"}`,
`{"kod":"A1","nazev":"Hrnek","sklad":0,"sleva":0}`,
`{"kod":"A1","nazev":"Hrnek","sklad":null}`,
} {
var p Produkt
if err := json.Unmarshal([]byte(vstup), &p); err != nil {
panic(err)
}
if p.Sklad == nil {
fmt.Print("sklad: chybí nebo null")
} else {
fmt.Printf("sklad: %d", *p.Sklad)
}
fmt.Printf(", sleva: %d\n", p.Sleva)
}
nula := 0
p := Produkt{Kod: "A1", Nazev: "Hrnek", Sklad: &nula}
j, _ := json.Marshal(p)
fmt.Println(string(j))
p.Zmeneno = time.Date(2026, 10, 4, 12, 0, 0, 0, time.UTC)
p.Stitky = []string{"keramika", "výprodej"}
p.Sleva = 10
j, _ = json.Marshal(p)
fmt.Println(string(j))
x, _ := xml.MarshalIndent(p, "", " ")
fmt.Println(string(x))
var z Produkt
err := xml.Unmarshal([]byte(`<produkt kod="B2"><nazev>Talíř</nazev>bílý<sklad>3</sklad></produkt>`), &z)
fmt.Println(err, z.Kod, z.Nazev, z.Popis, *z.Sklad)
} sklad: chybí nebo null, sleva: 0
sklad: 0, sleva: 0
sklad: chybí nebo null, sleva: 0
{"kod":"A1","nazev":"Hrnek","sklad":0}
{"kod":"A1","nazev":"Hrnek","sleva":10,"sklad":0,"stitky":["keramika","výprodej"],"zmeneno":"2026-10-04T12:00:00Z"}
<produkt kod="A1">
<nazev>Hrnek</nazev>
<sleva>10</sleva>
<sklad>0</sklad>
<stitek>keramika</stitek>
<stitek>výprodej</stitek>
</produkt>
<nil> B2 Talíř bílý 3 - Ukazatel.
Slevajeint, takže chybějící klíč i"sleva":0dají 0.Skladje*inta rozliší chybějící hodnotu od nuly. Klíč s hodnotounulldá stejně jako chybějící klíčnil. - omitempty vynechá při zápisu
false, 0, nil ukazatel a prázdný řetězec, řez nebo mapu. Ukazatel na nulu není prázdný, proto se"sklad":0zapíše. Na strukturyomitemptynepůsobí: prázdnýtime.Timeby se zapsal jako"0001-01-01T00:00:00Z". - omitzero (od Go 1.24) vynechá nulovou hodnotu libovolného typu. Pokud typ má metodu
IsZero(), použije ji, takže funguje i protime.Time. - Tagy xml.
,attrzapíše pole jako atribut,,chardatazachytí text elementu (zde „bílý“ mezi elementy). Řez bez obalového elementu dá opakované elementystitek. Pomlčka-pole v daném formátu vynechá. - Řez nil a prázdný řez. Bez
omitemptyse řez nil zapíše jakonull, prázdný řez jako[]. Pokud klient očekává vždy pole, inicializuj řez.
Když potřebuješ rozlišit všechny tři stavy (klíč chybí, null, hodnota), typicky u částečné aktualizace podle JSON Merge Patch, ukazatel nestačí. Pomůže vlastní typ s metodou UnmarshalJSON, kterou dekodér zavolá jen pro klíče přítomné ve vstupu:
package main
import (
"encoding/json"
"fmt"
)
// Volitelna rozlišuje chybějící klíč, null a hodnotu.
type Volitelna[T any] struct {
Zadano bool // klíč byl ve vstupu
Null bool
Hodnota T
}
func (v *Volitelna[T]) UnmarshalJSON(b []byte) error {
v.Zadano = true
if string(b) == "null" {
v.Null = true
return nil
}
return json.Unmarshal(b, &v.Hodnota)
}
type Zmena struct {
Sklad Volitelna[int] `json:"sklad"`
}
func main() {
for _, vstup := range []string{`{}`, `{"sklad":null}`, `{"sklad":0}`} {
var z Zmena
if err := json.Unmarshal([]byte(vstup), &z); err != nil { panic(err) }
fmt.Printf("%-15s zadáno=%v null=%v hodnota=%d\n", vstup, z.Sklad.Zadano, z.Sklad.Null, z.Sklad.Hodnota)
}
} {} zadáno=false null=false hodnota=0
{"sklad":null} zadáno=true null=true hodnota=0
{"sklad":0} zadáno=true null=false hodnota=0 Stejný rozdíl mezi chybějícím klíčem, JSON null a SQL NULL řeší i PostgreSQL. Zdroj: encoding/json Marshal a Go 1.24 release notes.