Exemples de Sérialisation de Données Web Go

Exemples de sérialisation de données Web Go incluant l'encodage/décodage JSON et l'analyse XML

💻 Sérialisation JSON go

🟢 simple ⭐⭐

Convertir les structures et types de données Go en chaînes JSON en utilisant le paquet encoding/json

⏱️ 25 min 🏷️ go, web, serialization, json
Prerequisites: Basic Go, encoding/json package
// Web Go JSON Serialization Examples
// Converting Go objects to JSON strings

package main

import (
	"encoding/json"
	"fmt"
	"time"
)

// 1. Basic Struct Serialization

// User represents a user object
type User struct {
	ID        int       `json:"id"`
	Username  string    `json:"username"`
	Email     string    `json:"email"`
	FullName  string    `json:"full_name,omitempty"`
	CreatedAt time.Time `json:"created_at"`
	IsActive  bool      `json:"is_active"`
}

// SerializeUser serializes user to JSON
func SerializeUser(user User) (string, error) {
	data, err := json.Marshal(user)
	if err != nil {
		return "", fmt.Errorf("error marshaling user: %v", err)
	}
	return string(data), nil
}

// SerializeUserIndented serializes user with indentation
func SerializeUserIndented(user User) (string, error) {
	data, err := json.MarshalIndent(user, "", "  ")
	if err != nil {
		return "", fmt.Errorf("error marshaling user: %v", err)
	}
	return string(data), nil
}

// 2. Map Serialization

// SerializeMap serializes map to JSON
func SerializeMap(m map[string]interface{}) (string, error) {
	data, err := json.Marshal(m)
	if err != nil {
		return "", fmt.Errorf("error marshaling map: %v", err)
	}
	return string(data), nil
}

// SerializeMapIndented serializes map with indentation
func SerializeMapIndented(m map[string]interface{}) (string, error) {
	data, err := json.MarshalIndent(m, "", "  ")
	if err != nil {
		return "", fmt.Errorf("error marshaling map: %v", err)
	}
	return string(data), nil
}

// SerializeStringMap serializes string map
func SerializeStringMap(m map[string]string) (string, error) {
	data, err := json.Marshal(m)
	if err != nil {
		return "", err
	}
	return string(data), nil
}

// 3. Slice Serialization

// SerializeSlice serializes slice to JSON
func SerializeSlice(slice []interface{}) (string, error) {
	data, err := json.Marshal(slice)
	if err != nil {
		return "", err
	}
	return string(data), nil
}

// SerializeSliceOfUsers serializes slice of users
func SerializeSliceOfUsers(users []User) (string, error) {
	data, err := json.MarshalIndent(users, "", "  ")
	if err != nil {
		return "", err
	}
	return string(data), nil
}

// SerializeIntSlice serializes int slice
func SerializeIntSlice(numbers []int) (string, error) {
	data, err := json.Marshal(numbers)
	if err != nil {
		return "", err
	}
	return string(data), nil
}

// SerializeStringSlice serializes string slice
func SerializeStringSlice(strings []string) (string, error) {
	data, err := json.Marshal(strings)
	if err != nil {
		return "", err
	}
	return string(data), nil
}

// 4. Advanced Struct Serialization

// Product represents a product with custom tags
type Product struct {
	ID          int     `json:"id"`
	Name        string  `json:"name"`
	Description string  `json:"description,omitempty"`
	Price       float64 `json:"price"`
	InStock     bool    `json:"in_stock"`
	Tags        []string `json:"tags,omitempty"`
}

// SerializeProduct serializes product
func SerializeProduct(product Product) (string, error) {
	data, err := json.Marshal(product)
	if err != nil {
		return "", err
	}
	return string(data), nil
}

// Order represents an order
type Order struct {
	OrderID   int       `json:"order_id"`
	UserID    int       `json:"user_id"`
	Items     []Item    `json:"items"`
	Total     float64   `json:"total"`
	CreatedAt time.Time `json:"created_at"`
	Status    string    `json:"status"`
}

// Item represents an order item
type Item struct {
	ProductID int     `json:"product_id"`
	Quantity  int     `json:"quantity"`
	Price     float64 `json:"price"`
}

// SerializeOrder serializes order
func SerializeOrder(order Order) (string, error) {
	data, err := json.MarshalIndent(order, "", "  ")
	if err != nil {
		return "", err
	}
	return string(data), nil
}

// 5. Custom Serialization

// MarshalJSON implements custom JSON marshaling
type Person struct {
	FirstName string `json:"first_name"`
	LastName  string `json:"last_name"`
	Age       int    `json:"age"`
}

// MarshalJSON custom JSON marshaling for Person
func (p Person) MarshalJSON() ([]byte, error) {
	type Alias Person
	return json.Marshal(&struct {
		FullName string `json:"full_name"`
		*Alias
	}{
		FullName: fmt.Sprintf("%s %s", p.FirstName, p.LastName),
		Alias:    (*Alias)(&p),
	})
}

// SerializePerson serializes person
func SerializePerson(person Person) (string, error) {
	data, err := json.Marshal(person)
	if err != nil {
		return "", err
	}
	return string(data), nil
}

// 6. Omit Empty Fields

// Config represents configuration with omitempty
type Config struct {
	Host     string `json:"host"`
	Port     int    `json:"port,omitempty"`
	Username string `json:"username,omitempty"`
	Password string `json:"-"'                    // Always omit
	Debug    bool   `json:"debug,omitempty"`
}

// SerializeConfig serializes config
func SerializeConfig(config Config) (string, error) {
	data, err := json.MarshalIndent(config, "", "  ")
	if err != nil {
		return "", err
	}
	return string(data), nil
}

// 7. Pretty Printing

// PrettyPrint prints JSON with indentation
func PrettyPrint(v interface{}) (string, error) {
	data, err := json.MarshalIndent(v, "", "  ")
	if err != nil {
		return "", err
	}
	return string(data), nil
}

// PrettyPrintWithPrefix prints with custom prefix
func PrettyPrintWithPrefix(v interface{}, prefix string) (string, error) {
	data, err := json.MarshalIndent(v, prefix, "  ")
	if err != nil {
		return "", err
	}
	return string(data), nil
}

// 8. Streaming Serialization

// NewJSONStreamEncoder creates streaming encoder
func NewJSONStreamEncoder() func(v interface{}) (string, error) {
	return func(v interface{}) (string, error) {
		data, err := json.Marshal(v)
		if err != nil {
			return "", err
		}
		return string(data), nil
	}
}

// SerializeMultiple serializes multiple objects
func SerializeMultiple(objects []interface{}) ([]string, error) {
	var results []string
	for _, obj := range objects {
		data, err := json.Marshal(obj)
		if err != nil {
			return nil, err
		}
		results = append(results, string(data))
	}
	return results, nil
}

// 9. Conditional Serialization

// SerializableProduct with conditional field
type SerializableProduct struct {
	ID          int     `json:"id"`
	Name        string  `json:"name"`
	Price       float64 `json:"price"`
	ShowPrice   bool    `json:"-"'                     // Not serialized
	EffectivePrice *float64 `json:"effective_price,omitempty"`
}

// MarshalJSON conditional marshaling
func (p SerializableProduct) MarshalJSON() ([]byte, error) {
	type Alias SerializableProduct
	aux := &struct {
		*Alias
	}{
		Alias: (*Alias)(&p),
	}

	if !p.ShowPrice {
		aux.EffectivePrice = nil
	} else {
		aux.EffectivePrice = &p.Price
	}

	return json.Marshal(aux)
}

// 10. Error Serialization

// ErrorInfo represents error information
type ErrorInfo struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
	Details string `json:"details,omitempty"`
}

// SerializeError serializes error
func SerializeError(err error, code int) (string, error) {
	errorInfo := ErrorInfo{
		Code:    code,
		Message: err.Error(),
	}
	data, err := json.Marshal(errorInfo)
	if err != nil {
		return "", err
	}
	return string(data), nil
}

// SerializeErrors serializes multiple errors
func SerializeErrors(errors []error) (string, error) {
	var errorInfos []ErrorInfo
	for _, err := range errors {
		errorInfos = append(errorInfos, ErrorInfo{
			Message: err.Error(),
		})
	}
	data, err := json.Marshal(errorInfos)
	if err != nil {
		return "", err
	}
	return string(data), nil
}

// 11. Special Characters Handling

// JSONEscape properly escapes special characters
func JSONEscape(text string) string {
	data, _ := json.Marshal(text)
	return string(data)
}

// SerializeWithSpecialChars serializes handling special chars
func SerializeWithSpecialChars(text string) (string, error) {
	data, err := json.Marshal(text)
	if err != nil {
		return "", err
	}
	return string(data), nil
}

// 12. Validation During Serialization

// ValidatedUser with validation
type ValidatedUser struct {
	Username string `json:"username"`
	Email    string `json:"email"`
}

// MarshalJSON with validation
func (u ValidatedUser) MarshalJSON() ([]byte, error) {
	if u.Username == "" {
		return nil, fmt.Errorf("username cannot be empty")
	}
	if u.Email == "" {
		return nil, fmt.Errorf("email cannot be empty")
	}
	type Alias ValidatedUser
	return json.Marshal(&struct{ *Alias }{
		Alias: (*Alias)(&u),
	})
}

// SerializeValidatedUser serializes with validation
func SerializeValidatedUser(user ValidatedUser) (string, error) {
	data, err := json.Marshal(user)
	if err != nil {
		return "", err
	}
	return string(data), nil
}

// Usage Examples
func main() {
	fmt.Println("=== Web Go JSON Serialization Examples ===
")

	// 1. Basic struct
	fmt.Println("--- 1. Basic Struct Serialization ---")
	user := User{
		ID:        1,
		Username:  "john_doe",
		Email:     "[email protected]",
		FullName:  "John Doe",
		CreatedAt: time.Now(),
		IsActive:  true,
	}
	jsonUser, _ := SerializeUser(user)
	fmt.Printf("User JSON: %s
", jsonUser)

	indentedUser, _ := SerializeUserIndented(user)
	fmt.Printf("Indented JSON:
%s
", indentedUser)

	// 2. Map
	fmt.Println("
--- 2. Map Serialization ---")
	userMap := map[string]interface{}{
		"id":       1,
		"username": "jane_doe",
		"email":    "[email protected]",
		"active":   true,
	}
	jsonMap, _ := SerializeMap(userMap)
	fmt.Printf("Map JSON: %s
", jsonMap)

	// 3. Slice
	fmt.Println("
--- 3. Slice Serialization ---")
	users := []User{
		{ID: 1, Username: "user1", Email: "[email protected]"},
		{ID: 2, Username: "user2", Email: "[email protected]"},
	}
	jsonSlice, _ := SerializeSliceOfUsers(users)
	fmt.Printf("Slice JSON:
%s
", jsonSlice)

	// 4. Nested structs
	fmt.Println("
--- 4. Nested Struct Serialization ---")
	order := Order{
		OrderID:   1001,
		UserID:    1,
		Items:     []Item{{ProductID: 10, Quantity: 2, Price: 29.99}},
		Total:     59.98,
		CreatedAt: time.Now(),
		Status:    "pending",
	}
	jsonOrder, _ := SerializeOrder(order)
	fmt.Printf("Order JSON:
%s
", jsonOrder)

	// 5. Custom serialization
	fmt.Println("
--- 5. Custom Serialization ---")
	person := Person{FirstName: "John", LastName: "Doe", Age: 30}
	jsonPerson, _ := SerializePerson(person)
	fmt.Printf("Person JSON: %s
", jsonPerson)

	// 6. Omit empty
	fmt.Println("
--- 6. Omit Empty Fields ---")
	config := Config{Host: "localhost", Port: 8080}
	jsonConfig, _ := SerializeConfig(config)
	fmt.Printf("Config JSON:
%s
", jsonConfig)

	// 7. Error serialization
	fmt.Println("
--- 7. Error Serialization ---"
	err := fmt.Errorf("something went wrong")
	jsonErr, _ := SerializeError(err, 500)
	fmt.Printf("Error JSON: %s
", jsonErr)

	// 8. Pretty print
	fmt.Println("
--- 8. Pretty Print ---")
	pretty, _ := PrettyPrint(user)
	fmt.Printf("Pretty JSON:
%s
", pretty)

	// 9. Special characters
	fmt.Println("
--- 9. Special Characters ---")
	special := `Hello "World"
New Line	Tab`
	jsonSpecial, _ := SerializeWithSpecialChars(special)
	fmt.Printf("Special chars JSON: %s
", jsonSpecial)

	fmt.Println("
=== All JSON Serialization Examples Completed ===")
}

💻 Désérialisation JSON go

🟡 intermediate ⭐⭐⭐

Analyser les chaînes JSON en structures Go, maps et types de données avec gestion des erreurs

⏱️ 30 min 🏷️ go, web, serialization, json
Prerequisites: Intermediate Go, encoding/json package
// Web Go JSON Deserialization Examples
// Converting JSON strings to Go objects

package main

import (
	"encoding/json"
	"fmt"
	"io"
	"strings"
)

// 1. Basic Struct Deserialization

// User represents a user object
type User struct {
	ID        int    `json:"id"`
	Username  string `json:"username"`
	Email     string `json:"email"`
	FullName  string `json:"full_name"`
	IsActive  bool   `json:"is_active"`
}

// DeserializeUser deserializes JSON to user
func DeserializeUser(jsonStr string) (User, error) {
	var user User
	err := json.Unmarshal([]byte(jsonStr), &user)
	if err != nil {
		return User{}, fmt.Errorf("error unmarshaling user: %v", err)
	}
	return user, nil
}

// DeserializeUserStrict deserializes with strict validation
func DeserializeUserStrict(jsonStr string) (User, error) {
	var user User
	decoder := json.NewDecoder(strings.NewReader(jsonStr))
	decoder.DisallowUnknownFields()

	err := decoder.Decode(&user)
	if err != nil {
		return User{}, fmt.Errorf("error decoding user: %v", err)
	}

	return user, nil
}

// 2. Map Deserialization

// DeserializeToMap deserializes JSON to map
func DeserializeToMap(jsonStr string) (map[string]interface{}, error) {
	var result map[string]interface{}
	err := json.Unmarshal([]byte(jsonStr), &result)
	if err != nil {
		return nil, fmt.Errorf("error unmarshaling to map: %v", err)
	}
	return result, nil
}

// DeserializeToStringMap deserializes to string map
func DeserializeToStringMap(jsonStr string) (map[string]string, error) {
	var result map[string]string
	err := json.Unmarshal([]byte(jsonStr), &result)
	if err != nil {
		return nil, err
	}
	return result, nil
}

// GetFieldFromJSON extracts specific field from JSON
func GetFieldFromJSON(jsonStr, fieldPath string) (interface{}, error) {
	var data map[string]interface{}
	err := json.Unmarshal([]byte(jsonStr), &data)
	if err != nil {
		return nil, err
	}

	// Simple field extraction (for nested paths, split and traverse)
	return data[fieldPath], nil
}

// 3. Slice Deserialization

// DeserializeSlice deserializes JSON to slice
func DeserializeSlice(jsonStr string) ([]interface{}, error) {
	var result []interface{}
	err := json.Unmarshal([]byte(jsonStr), &result)
	if err != nil {
		return nil, err
	}
	return result, nil
}

// DeserializeUserSlice deserializes JSON to slice of users
func DeserializeUserSlice(jsonStr string) ([]User, error) {
	var users []User
	err := json.Unmarshal([]byte(jsonStr), &users)
	if err != nil {
		return nil, fmt.Errorf("error unmarshaling users: %v", err)
	}
	return users, nil
}

// DeserializeIntSlice deserializes JSON to int slice
func DeserializeIntSlice(jsonStr string) ([]int, error) {
	var result []int
	err := json.Unmarshal([]byte(jsonStr), &result)
	if err != nil {
		return nil, err
	}
	return result, nil
}

// DeserializeStringSlice deserializes JSON to string slice
func DeserializeStringSlice(jsonStr string) ([]string, error) {
	var result []string
	err := json.Unmarshal([]byte(jsonStr), &result)
	if err != nil {
		return nil, err
	}
	return result, nil
}

// 4. Nested Struct Deserialization

// Product represents a product
type Product struct {
	ID          int      `json:"id"`
	Name        string   `json:"name"`
	Description string   `json:"description"`
	Price       float64  `json:"price"`
	InStock     bool     `json:"in_stock"`
	Tags        []string `json:"tags"`
}

// Order represents an order with nested items
type Order struct {
	OrderID   int       `json:"order_id"`
	UserID    int       `json:"user_id"`
	Items     []Item    `json:"items"`
	Total     float64   `json:"total"`
	Status    string    `json:"status"`
	Metadata  Metadata  `json:"metadata"`
}

// Item represents order item
type Item struct {
	ProductID int     `json:"product_id"`
	Quantity  int     `json:"quantity"`
	Price     float64 `json:"price"`
}

// Metadata represents order metadata
type Metadata struct {
	Source    string `json:"source"`
	Reference string `json:"reference"`
}

// DeserializeOrder deserializes JSON to order
func DeserializeOrder(jsonStr string) (Order, error) {
	var order Order
	err := json.Unmarshal([]byte(jsonStr), &order)
	if err != nil {
		return Order{}, fmt.Errorf("error unmarshaling order: %v", err)
	}
	return order, nil
}

// 5. Custom Deserialization

// Person with custom unmarshaling
type Person struct {
	FirstName string `json:"first_name"`
	LastName  string `json:"last_name"`
	Age       int    `json:"age"`
	FullName  string `json:"full_name"` // Will be ignored during unmarshal
}

// UnmarshalJSON custom unmarshaling for Person
func (p *Person) UnmarshalJSON(data []byte) error {
	type Alias Person
	aux := &struct {
		*Alias
	}{
		Alias: (*Alias)(p),
	}

	if err := json.Unmarshal(data, &aux); err != nil {
		return err
	}

	// Build full name from first and last name
	p.FullName = fmt.Sprintf("%s %s", p.FirstName, p.LastName)
	return nil
}

// DeserializePerson deserializes JSON to person
func DeserializePerson(jsonStr string) (Person, error) {
	var person Person
	err := json.Unmarshal([]byte(jsonStr), &person)
	if err != nil {
		return Person{}, err
	}
	return person, nil
}

// 6. Streaming Deserialization

// StreamingDecode streams JSON from reader
func StreamingDecode(reader io.Reader) ([]User, error) {
	decoder := json.NewDecoder(reader)
	var users []User

	for {
		var user User
		if err := decoder.Decode(&user); err != nil {
			if err == io.EOF {
				break
			}
			return nil, err
		}
		users = append(users, user)
	}

	return users, nil
}

// DecodeSingle decodes single JSON object from reader
func DecodeSingle(reader io.Reader, v interface{}) error {
	decoder := json.NewDecoder(reader)
	return decoder.Decode(v)
}

// 7. Error Handling

// SafeDeserialize safely deserializes with error handling
func SafeDeserialize(jsonStr string, v interface{}) error {
	err := json.Unmarshal([]byte(jsonStr), v)
	if err != nil {
		return fmt.Errorf("failed to deserialize: %w", err)
	}
	return nil
}

// DeserializeWithDefault deserializes with default value on error
func DeserializeWithDefault(jsonStr string, defaultUser User) User {
	var user User
	err := json.Unmarshal([]byte(jsonStr), &user)
	if err != nil {
		return defaultUser
	}
	return user
}

// ValidateJSON validates JSON syntax
func ValidateJSON(jsonStr string) bool {
	var js map[string]interface{}
	return json.Unmarshal([]byte(jsonStr), &js) == nil
}

// 8. Conditional Field Parsing

// OptionalConfig with optional fields
type OptionalConfig struct {
	Host     string `json:"host"`
	Port     *int   `json:"port,omitempty"`      // Pointer for optional
	Username string `json:"username,omitempty"`
	Debug    *bool  `json:"debug,omitempty"`
}

// DeserializeOptionalConfig deserializes optional config
func DeserializeOptionalConfig(jsonStr string) (OptionalConfig, error) {
	var config OptionalConfig
	err := json.Unmarshal([]byte(jsonStr), &config)
	if err != nil {
		return OptionalConfig{}, err
	}
	return config, nil
}

// 9. Raw Message Handling

// FlexibleMessage with raw JSON
type FlexibleMessage struct {
	Type    string          `json:"type"`
	Payload json.RawMessage `json:"payload"` // Raw JSON
}

// DeserializeFlexible deserializes flexible message
func DeserializeFlexible(jsonStr string) (FlexibleMessage, error) {
	var msg FlexibleMessage
	err := json.Unmarshal([]byte(jsonStr), &msg)
	if err != nil {
		return FlexibleMessage{}, err
	}
	return msg, nil
}

// ExtractPayload extracts payload to specific type
func ExtractPayload(msg FlexibleMessage, v interface{}) error {
	return json.Unmarshal(msg.Payload, v)
}

// 10. Number Handling

// NumericData with various number types
type NumericData struct {
	IntValue    int     `json:"int_value"`
	FloatValue  float64 `json:"float_value"`
	StringValue string  `json:"string_value"`
}

// DeserializeNumeric deserializes numeric data
func DeserializeNumeric(jsonStr string) (NumericData, error) {
	var data NumericData
	err := json.Unmarshal([]byte(jsonStr), &data)
	if err != nil {
		return NumericData{}, err
	}
	return data, nil
}

// UseNumber decoder for precision
func DeserializeWithNumber(jsonStr string) (map[string]interface{}, error) {
	decoder := json.NewDecoder(strings.NewReader(jsonStr))
	decoder.UseNumber()

	var result map[string]interface{}
	err := decoder.Decode(&result)
	if err != nil {
		return nil, err
	}
	return result, nil
}

// 11. Unknown Fields Handling

// StrictUser with strict mode
type StrictUser struct {
	ID       int    `json:"id"`
	Username string `json:"username"`
	Email    string `json:"email"`
}

// DeserializeStrict deserializes strictly (rejects unknown fields)
func DeserializeStrict(jsonStr string) (StrictUser, error) {
	var user StrictUser
	decoder := json.NewDecoder(strings.NewReader(jsonStr))
	decoder.DisallowUnknownFields()

	err := decoder.Decode(&user)
	if err != nil {
		return StrictUser{}, err
	}
	return user, nil
}

// 12. Null Handling

// NullableUser with nullable fields
type NullableUser struct {
	ID        int     `json:"id"`
	Username  string  `json:"username"`
	Email     *string `json:"email,omitempty"`     // Nullable
	Age       *int    `json:"age,omitempty"`       // Nullable
	IsActive  *bool   `json:"is_active,omitempty"` // Nullable
}

// DeserializeNullable deserializes with nullable fields
func DeserializeNullable(jsonStr string) (NullableUser, error) {
	var user NullableUser
	err := json.Unmarshal([]byte(jsonStr), &user)
	if err != nil {
		return NullableUser{}, err
	}
	return user, nil
}

// Usage Examples
func main() {
	fmt.Println("=== Web Go JSON Deserialization Examples ===
")

	// 1. Basic struct
	fmt.Println("--- 1. Basic Struct Deserialization ---")
	userJSON := `{"id":1,"username":"john_doe","email":"[email protected]","full_name":"John Doe","is_active":true}`
	user, err := DeserializeUser(userJSON)
	if err == nil {
		fmt.Printf("User: %+v
", user)
	}

	// 2. Map
	fmt.Println("
--- 2. Map Deserialization ---")
	dataJSON := `{"name":"test","value":123,"active":true}`
	data, err := DeserializeToMap(dataJSON)
	if err == nil {
		fmt.Printf("Map: %+v
", data)
	}

	// 3. Slice
	fmt.Println("
--- 3. Slice Deserialization ---")
	usersJSON := `[{"id":1,"username":"user1","email":"[email protected]"},{"id":2,"username":"user2","email":"[email protected]"}]`
	users, err := DeserializeUserSlice(usersJSON)
	if err == nil {
		fmt.Printf("Users: %+v
", users)
	}

	// 4. Nested struct
	fmt.Println("
--- 4. Nested Struct Deserialization ---")
	orderJSON := `{"order_id":1001,"user_id":1,"items":[{"product_id":10,"quantity":2,"price":29.99}],"total":59.98,"status":"pending","metadata":{"source":"web","reference":"REF123"}}`
	order, err := DeserializeOrder(orderJSON)
	if err == nil {
		fmt.Printf("Order: %+v
", order)
	}

	// 5. Custom deserialization
	fmt.Println("
--- 5. Custom Deserialization ---")
	personJSON := `{"first_name":"John","last_name":"Doe","age":30}`
	person, err := DeserializePerson(personJSON)
	if err == nil {
		fmt.Printf("Person: %+v
", person)
		fmt.Printf("Full Name: %s
", person.FullName)
	}

	// 6. Validation
	fmt.Println("
--- 6. JSON Validation ---")
	valid := ValidateJSON(userJSON)
	fmt.Printf("Valid JSON: %t
", valid)

	invalid := "{invalid json"
	valid = ValidateJSON(invalid)
	fmt.Printf("Invalid JSON valid: %t
", valid)

	// 7. Optional fields
	fmt.Println("
--- 7. Optional Fields ---")
	configJSON := `{"host":"localhost","port":8080}`
	config, err := DeserializeOptionalConfig(configJSON)
	if err == nil {
		fmt.Printf("Config: %+v
", config)
		if config.Port != nil {
			fmt.Printf("Port: %d
", *config.Port)
		}
	}

	// 8. Nullable fields
	fmt.Println("
--- 8. Nullable Fields ---")
	nullableJSON := `{"id":1,"username":"john"}`
	nullableUser, err := DeserializeNullable(nullableJSON)
	if err == nil {
		fmt.Printf("Nullable User: %+v
", nullableUser)
		if nullableUser.Email != nil {
			fmt.Printf("Email: %s
", *nullableUser.Email)
		} else {
			fmt.Println("Email: <null>")
		}
	}

	// 9. Raw message
	fmt.Println("
--- 9. Raw Message ---")
	flexJSON := `{"type":"user","payload":{"username":"john"}}`
	flexMsg, err := DeserializeFlexible(flexJSON)
	if err == nil {
		fmt.Printf("Message type: %s
", flexMsg.Type)
		var payload map[string]string
		ExtractPayload(flexMsg, &payload)
		fmt.Printf("Payload: %+v
", payload)
	}

	// 10. Number precision
	fmt.Println("
--- 10. Number Precision ---")
	numericJSON := `{"int_value":42,"float_value":3.14159,"string_value":"hello"}`
	numeric, err := DeserializeNumeric(numericJSON)
	if err == nil {
		fmt.Printf("Numeric: %+v
", numeric)
	}

	fmt.Println("
=== All JSON Deserialization Examples Completed ===")
}

💻 Analyse XML go

🟡 intermediate ⭐⭐⭐

Analyser et générer des documents XML en utilisant le paquet encoding/xml de Go

⏱️ 35 min 🏷️ go, web, serialization, xml
Prerequisites: Intermediate Go, encoding/xml package
// Web Go XML Parsing Examples
// Parsing and generating XML documents

package main

import (
	"encoding/xml"
	"fmt"
	"io"
	"strings"
)

// 1. Basic XML Structs

// Person represents a person in XML
type Person struct {
	XMLName   xml.Name `xml:"person"`
	ID        int      `xml:"id,attr"`
	FirstName string   `xml:"first-name"`
	LastName  string   `xml:"last-name"`
	Age       int      `xml:"age"`
	Email     string   `xml:"email"`
}

// ParsePerson parses XML to Person struct
func ParsePerson(xmlStr string) (Person, error) {
	var person Person
	err := xml.Unmarshal([]byte(xmlStr), &person)
	if err != nil {
		return Person{}, fmt.Errorf("error parsing person: %v", err)
	}
	return person, nil
}

// PersonToXML converts Person to XML
func PersonToXML(person Person) (string, error) {
	data, err := xml.MarshalIndent(person, "", "  ")
	if err != nil {
		return "", err
	}
	return string(data), nil
}

// 2. Nested Structures

// Address represents an address
type Address struct {
	Street  string `xml:"street"`
	City    string `xml:"city"`
	State   string `xml:"state"`
	ZipCode string `xml:"zip-code"`
	Country string `xml:"country"`
}

// Employee represents an employee
type Employee struct {
	XMLName  xml.Name `xml:"employee"`
	ID       int      `xml:"id,attr"`
	Name     string   `xml:"name"`
	Email    string   `xml:"email"`
	Address  Address  `xml:"address"`
	Department string `xml:"department"`
	Salary   float64  `xml:"salary"`
}

// ParseEmployee parses XML to Employee
func ParseEmployee(xmlStr string) (Employee, error) {
	var employee Employee
	err := xml.Unmarshal([]byte(xmlStr), &employee)
	if err != nil {
		return Employee{}, fmt.Errorf("error parsing employee: %v", err)
	}
	return employee, nil
}

// EmployeeToXML converts Employee to XML
func EmployeeToXML(employee Employee) (string, error) {
	data, err := xml.MarshalIndent(employee, "", "  ")
	if err != nil {
		return "", err
	}
	return xml.Header + string(data), nil
}

// 3. Collections and Lists

// Company represents a company with employees
type Company struct {
	XMLName   xml.Name  `xml:"company"`
	Name      string    `xml:"name"`
	Founded   int       `xml:"founded"`
	Employees []Employee `xml:"employees>employee"`
}

// ParseCompany parses XML to Company
func ParseCompany(xmlStr string) (Company, error) {
	var company Company
	err := xml.Unmarshal([]byte(xmlStr), &company)
	if err != nil {
		return Company{}, fmt.Errorf("error parsing company: %v", err)
	}
	return company, nil
}

// CompanyToXML converts Company to XML
func CompanyToXML(company Company) (string, error) {
	data, err := xml.MarshalIndent(company, "", "  ")
	if err != nil {
		return "", err
	}
	return xml.Header + string(data), nil
}

// 4. XML with Mixed Content

// Article represents an article
type Article struct {
	XMLName  xml.Name `xml:"article"`
	ID       int      `xml:"id,attr"`
	Title    string   `xml:"title"`
	Author   string   `xml:"author"`
	Content  string   `xml:",innerxml"` // Raw inner XML
	Keywords []string `xml:"keywords>keyword"`
	Tags     []Tag    `xml:"tags>tag"`
}

// Tag represents a tag
type Tag struct {
	Name  string `xml:",chardata"`
	Count int    `xml:"count,attr"`
}

// ParseArticle parses article XML
func ParseArticle(xmlStr string) (Article, error) {
	var article Article
	err := xml.Unmarshal([]byte(xmlStr), &article)
	if err != nil {
		return Article{}, fmt.Errorf("error parsing article: %v", err)
	}
	return article, nil
}

// ArticleToXML converts Article to XML
func ArticleToXML(article Article) (string, error) {
	data, err := xml.MarshalIndent(article, "", "  ")
	if err != nil {
		return "", err
	}
	return xml.Header + string(data), nil
}

// 5. Streaming XML Parsing

// StreamParsePerson streams XML parsing
func StreamParsePerson(reader io.Reader) ([]Person, error) {
	decoder := xml.NewDecoder(reader)
	var people []Person

	for {
		var person Person
		err := decoder.Decode(&person)
		if err != nil {
			if err == io.EOF {
				break
			}
			return nil, err
		}
		people = append(people, person)
	}

	return people, nil
}

// 6. XML Path Navigation

// FindElement finds element by tag name
func FindElement(xmlStr, tagName string) (string, error) {
	decoder := xml.NewDecoder(strings.NewReader(xmlStr))

	for {
		token, err := decoder.Token()
		if err != nil {
			if err == io.EOF {
				break
			}
			return "", err
		}

		switch se := token.(type) {
		case xml.StartElement:
			if se.Name.Local == tagName {
				var content string
				if err := decoder.DecodeElement(&content, &se); err != nil {
					return "", err
				}
				return content, nil
			}
		}
	}

	return "", fmt.Errorf("element not found: %s", tagName)
}

// ExtractAttribute extracts attribute from element
func ExtractAttribute(xmlStr, elementName, attrName string) (string, error) {
	decoder := xml.NewDecoder(strings.NewReader(xmlStr))

	for {
		token, err := decoder.Token()
		if err != nil {
			if err == io.EOF {
				break
			}
			return "", err
		}

		switch se := token.(type) {
		case xml.StartElement:
			if se.Name.Local == elementName {
				for _, attr := range se.Attr {
					if attr.Name.Local == attrName {
						return attr.Value, nil
					}
				}
			}
		}
	}

	return "", fmt.Errorf("attribute not found: %s on %s", attrName, elementName)
}

// 7. XML Validation

// ValidateXML validates XML structure
func ValidateXML(xmlStr string) bool {
	decoder := xml.NewDecoder(strings.NewReader(xmlStr))
	for {
		_, err := decoder.Token()
		if err != nil {
			if err == io.EOF {
				return true
			}
			return false
		}
	}
}

// 8. Custom XML Marshaling

// Config with custom marshaling
type Config struct {
	XMLName xml.Name `xml:"config"`
	Host    string   `xml:"host"`
	Port    int      `xml:"port"`
	Options Options  `xml:"options"`
}

// Options represents config options
type Options struct {
	Debug   bool `xml:"debug"`
	Verbose bool `xml:"verbose"`
	LogFile string `xml:"log-file"`
}

// ParseConfig parses config XML
func ParseConfig(xmlStr string) (Config, error) {
	var config Config
	err := xml.Unmarshal([]byte(xmlStr), &config)
	if err != nil {
		return Config{}, err
	}
	return config, nil
}

// ConfigToXML converts Config to XML
func ConfigToXML(config Config) (string, error) {
	data, err := xml.MarshalIndent(config, "", "  ")
	if err != nil {
		return "", err
	}
	return xml.Header + string(data), nil
}

// 9. CDATA Handling

// Document with CDATA
type Document struct {
	XMLName xml.Name `xml:"document"`
	Title   string   `xml:"title"`
	Content string   `xml:"content,omitempty"`
	Data    string   `xml:",innerxml"` // For CDATA
}

// ParseDocument parses document with CDATA
func ParseDocument(xmlStr string) (Document, error) {
	var document Document
	err := xml.Unmarshal([]byte(xmlStr), &document)
	if err != nil {
		return Document{}, err
	}
	return document, nil
}

// DocumentToXML converts Document to XML
func DocumentToXML(document Document) (string, error) {
	data, err := xml.MarshalIndent(document, "", "  ")
	if err != nil {
		return "", err
	}
	return xml.Header + string(data), nil
}

// 10. Namespaces

// Book with namespace
type Book struct {
	XMLName  xml.Name `xml:"http://example.com/books book"`
	Title    string   `xml:"title"`
	Author   string   `xml:"author"`
	ISBN     string   `xml:"isbn"`
	Price    float64  `xml:"price"`
	Currency string   `xml:"currency,attr"`
}

// ParseBook parses book with namespace
func ParseBook(xmlStr string) (Book, error) {
	var book Book
	err := xml.Unmarshal([]byte(xmlStr), &book)
	if err != nil {
		return Book{}, err
	}
	return book, nil
}

// BookToXML converts Book to XML
func BookToXML(book Book) (string, error) {
	data, err := xml.MarshalIndent(book, "", "  ")
	if err != nil {
		return "", err
	}
	return xml.Header + string(data), nil
}

// 11. XML Attributes

// Product with attributes
type Product struct {
	XMLName    xml.Name `xml:"product"`
	ID         string   `xml:"id,attr"`
	Name       string   `xml:"name,attr"`
	Price      float64  `xml:"price,attr"`
	Category   string   `xml:"category,attr"`
	Available  bool     `xml:"available,attr"`
	Attributes []Attribute `xml:"attributes>attribute"`
}

// Attribute represents a custom attribute
type Attribute struct {
	Name  string `xml:"name,attr"`
	Value string `xml:",chardata"`
}

// ParseProduct parses product with attributes
func ParseProduct(xmlStr string) (Product, error) {
	var product Product
	err := xml.Unmarshal([]byte(xmlStr), &product)
	if err != nil {
		return Product{}, err
	}
	return product, nil
}

// ProductToXML converts Product to XML
func ProductToXML(product Product) (string, error) {
	data, err := xml.MarshalIndent(product, "", "  ")
	if err != nil {
		return "", err
	}
	return xml.Header + string(data), nil
}

// 12. XML Transformations

// TransformElement transforms XML element
func TransformElement(xmlStr, oldElement, newElement string) string {
	return strings.ReplaceAll(xmlStr, "<"+oldElement, "<"+newElement)
}

// RemoveElement removes element from XML
func RemoveElement(xmlStr, elementName string) string {
	// Simple element removal (for production, use proper XML parser)
	startTag := "<" + elementName + ">"
	endTag := "</" + elementName + ">"
	result := strings.ReplaceAll(xmlStr, startTag, "")
	result = strings.ReplaceAll(result, endTag, "")
	return result
}

// Usage Examples
func main() {
	fmt.Println("=== Web Go XML Parsing Examples ===
")

	// 1. Basic parsing
	fmt.Println("--- 1. Basic XML Parsing ---")
	personXML := `<?xml version="1.0" encoding="UTF-8"?>
<person id="1">
  <first-name>John</first-name>
  <last-name>Doe</last-name>
  <age>30</age>
  <email>[email protected]</email>
</person>`

	person, err := ParsePerson(personXML)
	if err == nil {
		fmt.Printf("Person: %+v
", person)
	}

	// 2. Nested structures
	fmt.Println("
--- 2. Nested Structures ---")
	employeeXML := `<?xml version="1.0" encoding="UTF-8"?>
<employee id="101">
  <name>Jane Smith</name>
  <email>[email protected]</email>
  <address>
    <street>123 Main St</street>
    <city>New York</city>
    <state>NY</state>
    <zip-code>10001</zip-code>
    <country>USA</country>
  </address>
  <department>Engineering</department>
  <salary>95000</salary>
</employee>`

	employee, err := ParseEmployee(employeeXML)
	if err == nil {
		fmt.Printf("Employee: %+v
", employee)
		fmt.Printf("Address: %+v
", employee.Address)
	}

	// 3. Collections
	fmt.Println("
--- 3. Collections ---")
	companyXML := `<?xml version="1.0" encoding="UTF-8"?>
<company>
  <name>Tech Corp</name>
  <founded>2010</founded>
  <employees>
    <employee id="1">
      <name>John Doe</name>
      <email>[email protected]</email>
      <salary>80000</salary>
    </employee>
    <employee id="2">
      <name>Jane Smith</name>
      <email>[email protected]</email>
      <salary>90000</salary>
    </employee>
  </employees>
</company>`

	company, err := ParseCompany(companyXML)
	if err == nil {
		fmt.Printf("Company: %s
", company.Name)
		fmt.Printf("Employees: %d
", len(company.Employees))
	}

	// 4. XML generation
	fmt.Println("
--- 4. XML Generation ---")
	newPerson := Person{
		ID:        2,
		FirstName: "Jane",
		LastName:  "Smith",
		Age:       28,
		Email:     "[email protected]",
	}
	generatedXML, _ := PersonToXML(newPerson)
	fmt.Printf("Generated XML:
%s
", generatedXML)

	// 5. Validation
	fmt.Println("
--- 5. XML Validation ---")
	valid := ValidateXML(personXML)
	fmt.Printf("Valid XML: %t
", valid)

	invalidXML := "<invalid><unclosed>"
	valid = ValidateXML(invalidXML)
	fmt.Printf("Invalid XML valid: %t
", valid)

	// 6. Extract element
	fmt.Println("
--- 6. Extract Element ---")
	content, err := FindElement(personXML, "email")
	if err == nil {
		fmt.Printf("Email element: %s
", content)
	}

	// 7. Extract attribute
	fmt.Println("
--- 7. Extract Attribute ---")
	id, err := ExtractAttribute(personXML, "person", "id")
	if err == nil {
		fmt.Printf("ID attribute: %s
", id)
	}

	// 8. Config parsing
	fmt.Println("
--- 8. Config Parsing ---")
	configXML := `<?xml version="1.0" encoding="UTF-8"?>
<config>
  <host>localhost</host>
  <port>8080</port>
  <options>
    <debug>true</debug>
    <verbose>false</verbose>
    <log-file>app.log</log-file>
  </options>
</config>`

	config, err := ParseConfig(configXML)
	if err == nil {
		fmt.Printf("Config: %+v
", config)
	}

	// 9. Product with attributes
	fmt.Println("
--- 9. Product with Attributes ---")
	productXML := `<?xml version="1.0" encoding="UTF-8"?>
<product id="P123" name="Laptop" price="999.99" category="Electronics" available="true">
  <attributes>
    <attribute name="color">Silver</attribute>
    <attribute name="weight">2.5kg</attribute>
  </attributes>
</product>`

	product, err := ParseProduct(productXML)
	if err == nil {
		fmt.Printf("Product: %+v
", product)
	}

	fmt.Println("
=== All XML Parsing Examples Completed ===")
}