Documentation
¶
Index ¶
- Constants
- func AsBool(v any) bool
- func AsFloat(v any) float64
- func AsInt(v any) int
- func AsSlice(v any) []any
- func AsString(v any) string
- func AsTime(v any, layouts ...string) (time.Time, error)
- func Attributes(data map[string]any) map[string]any
- func Children(data map[string]any) map[string]any
- func Clone(data map[string]any) map[string]any
- func Delete(data map[string]any, path string) error
- func FilterSlice[T any](input []T, predicate func(T) bool) []T
- func FindFirst[T any](input []T, predicate func(T) bool) (T, bool)
- func Flatten(data map[string]any) map[string]any
- func Get[T any](data map[string]any, path string) (T, error)
- func Has(data map[string]any, key string) bool
- func Keys(data map[string]any) []string
- func MapSlice[T any, R any](input []T, transform func(T) R) []R
- func MapToJSON(data map[string]any) (string, error)
- func MapToStruct(data map[string]any, result any) error
- func MapXML(r io.Reader, opts ...Option) (map[string]any, error)
- func Marshal(data map[string]any, opts ...Option) (string, error)
- func Merge(base, override map[string]any)
- func MergeDeep(base, override map[string]any)
- func Omit(data map[string]any, keys ...string) map[string]any
- func Pick(data map[string]any, keys ...string) map[string]any
- func Query(data any, path string) (any, error)
- func QueryAll(data any, path string) ([]any, error)
- func RegisterQueryFunction(name string, fn QueryFunction)
- func RunCLI()
- func Set(data map[string]any, path string, value any) error
- func Text(data any) string
- func ToJSON(r io.Reader, opts ...Option) ([]byte, error)
- func Validate(data any, rules []Rule) []string
- type ClientOption
- type Encoder
- type Option
- type QueryFunction
- type Rule
- type SoapClient
- type Stream
- type SyntaxError
Examples ¶
Constants ¶
const ( AuthNone = "" AuthBasic = "Basic" AuthBearer = "Bearer" AuthWSSecurity = "WSSecurity" )
Tipos de Autenticación
Variables ¶
This section is empty.
Functions ¶
func AsBool ¶
AsBool parses a boolean leniently. True: true, "true", "1", "yes", "on", "ok". False: everything else.
func AsInt ¶
AsInt attempts to convert any value to an int. Returns 0 if conversion fails. Supports strings like "123", floats (truncated), and bools (1/0).
func AsSlice ¶
AsSlice guarantees the return of a []any. If the input is nil, returns empty slice. If the input is a single element, returns a slice with that element.
func AsString ¶
AsString safely converts any value to a string. It handles primitives, maps (JSON representation), and nil (empty string).
func AsTime ¶
AsTime parses a string into time.Time using a list of potential layouts. Default layouts: RFC3339, YYYY-MM-DD, and generic SQL timestamps.
func Attributes ¶
Attributes returns only the keys that represent XML attributes (starting with "@").
func Children ¶
Children returns only the keys that represent child nodes (excluding attributes and #text).
func Clone ¶
Clone creates a deep copy of the map, ensuring no reference sharing. Crucial for immutable operations or concurrent access.
func Delete ¶
Delete removes a value or a complete node at the specified path. It supports deletion of map keys ("user/email") and array indices ("users/user[1]").
func FilterSlice ¶
FilterSlice returns a new slice containing only elements that satisfy the predicate.
func FindFirst ¶
FindFirst returns the first element satisfying the predicate, or zero value if not found.
func Flatten ¶
Flatten converts a nested map into a single-level map with dot notation. Example: {"a": {"b": 1}} -> {"a.b": 1} Useful for exporting to CSV or searching.
func Get ¶
Get retrieves a value at the specified path and asserts it to type T. Usage: name, err := xml.Get[string](m, "user/name")
func MapToJSON ¶
MapToJSON converts the XML map into a JSON string. This helper is particularly useful for debugging purposes or for preparing API responses.
func MapToStruct ¶
MapToStruct converts the dynamic map into a user-defined struct. It uses JSON serialization as an intermediate layer, which is the cleanest and most robust approach to map dynamic keys to struct fields (respecting tags).
func MapXML ¶
MapXML reads the entire XML input from the reader and returns a dynamic map[string]any. It handles hierarchical data, attributes, CDATA, comments, and preserves mixed-content order via "#seq".
Example ¶
This example will appear in the Go documentation as a real-world use case.
xmlData := `<user><name>Arthur</name><role>Admin</role></user>`
// 1. Convert XML to Map
m, _ := MapXML(strings.NewReader(xmlData))
// 2. Query value
// CORRECTION: Since <name> has no attributes, the parser simplifies it directly to the value.
// No need to use "/#text".
name, _ := Query(m, "user/name")
role, _ := Query(m, "user/role")
fmt.Printf("User: %s, Role: %s\n", name, role)
Output: User: Arthur, Role: Admin
func Merge ¶
Merge recursively merges the 'override' map into the 'base' map. If a key exists in both maps and they are sub-maps, they are merged recursively. Otherwise, the value in 'base' is overwritten by the value from 'override'. Note: This modifies 'base' in place.
func Query ¶
Query is a convenience wrapper around QueryAll that returns the first matching result. It returns an error if no matching node is found. This is useful when you expect a single value or only care about the first match.
Example (Filtering) ¶
ExampleQuery_filtering demonstrates the advanced filtering capabilities. You can search for nodes based on their attributes or child values using [key=value].
xmlData := `
<users>
<user id="1" type="admin"><name>Alice</name></user>
<user id="2" type="guest"><name>Bob</name></user>
<user id="3" type="admin"><name>Charlie</name></user>
</users>`
m, _ := MapXML(strings.NewReader(xmlData), ForceArray("user"))
// 1. Find the name of the user with id=2
guestName, _ := Query(m, "users/user[id=2]/name")
// 2. Find the name of the user with type=admin (First match)
// Note: Use "@" for attributes in filters if needed, though simple keys work too depending on parsing.
adminName, _ := Query(m, "users/user[@type=admin]/name")
fmt.Printf("Guest: %s, Admin: %s\n", guestName, adminName)
Output: Guest: Bob, Admin: Alice
func QueryAll ¶
QueryAll searches the data structure for all nodes matching the provided path. It returns a slice of matches found.
Path Syntax:
- Deep Navigation: "library/section/book" (Traverse nested maps)
- Array Indexing: "users/user[0]" (Access specific index)
- Attribute/Value Filtering: "users/user[id=5]" or "book[@lang=en]"
- Text Extraction: "book/title/#text" (Explicit text node access)
Note: If the path targets a list directly (e.g., "tags"), QueryAll returns the list itself as a single result in the slice, rather than flattening it. QueryAll searches the data structure for all nodes matching the provided path. It returns a slice of matches found.
Path Syntax:
- Deep Navigation: "library/section/book"
- Deep Search: "//error" (Find "error" nodes anywhere)
- Array Indexing: "users/user[0]"
- Filter Logic: "book[price>10]" or "user[role='admin']" or "user[id!=5]"
- Filter Funcs: "book[contains(title, 'Go')]" or "user[starts-with(name, 'A')]"
- Wildcards: "items/*/sku"
- Custom Funcs: "items/func:isNumeric/id"
- Meta-Properties: "items/#count" (Returns number of children)
- Text Extraction: "book/title/#text"
func RegisterQueryFunction ¶
func RegisterQueryFunction(name string, fn QueryFunction)
RegisterQueryFunction registers a custom function for use in Query paths. The name used here must match the segment in the path after "func:". Example: RegisterQueryFunction("startsWithBox", ...) -> Path "items/func:startsWithBox/sku"
func RunCLI ¶
func RunCLI()
RunCLI transforms the program into a basic command-line utility. It detects command arguments, reads XML from STDIN, and outputs JSON.
Usage:
cat data.xml | go run main.go query "users/user[0]/name"
func Set ¶
Set updates or inserts a value at a given path. It supports map keys ("user/name") and specific indices of existing arrays ("users/user[0]/name"). Note: It creates intermediate map keys automatically, but it does NOT create arrays.
Example ¶
ExampleModifyAndSave shows how to read XML, modify values dynamically, and write it back to a clean XML format.
xmlData := `<config><debug>false</debug><timeout>30</timeout></config>` m, _ := MapXML(strings.NewReader(xmlData)) // 1. Update existing values Set(m, "config/debug", "true") // 2. Add new values (automatically creates map keys if parent exists) Set(m, "config/server/port", "8080") // 3. Write back to XML NewEncoder(os.Stdout).Encode(m)
Output: <config><debug>true</debug><server><port>8080</port></server><timeout>30</timeout></config>
func Text ¶
Text extracts ALL text content recursively from a node and its children. Equivalent to jQuery's .text(). Useful for search indexing.
Example ¶
ExampleTextExtraction shows how to extract deep text content from a structure, similar to the jQuery .text() method. Useful for search indexing or summarizing.
xmlData := ` <article> <h1>Breaking News</h1> <content> <p>The <b>stock market</b> reached record highs today.</p> <p>Details at 11.</p> </content> </article>` m, _ := MapXML(strings.NewReader(xmlData)) // 1. Extract all text from the <content> tag, ignoring structure contentNode, _ := Query(m, "article/content") fullText := Text(contentNode) fmt.Println(fullText)
Output: The stock market reached record highs today.Details at 11.
func ToJSON ¶
ToJSON scans the XML from the reader and returns the JSON representation. It performs smart simplification: 1. Unwraps the root element if it's a single key. 2. Removes internal metadata (#seq, #comments, etc.). 3. Renames attributes by removing the '@' prefix.
func Validate ¶
============================================================================ VALIDATION ENGINE ============================================================================ (Mantener el código de Validate igual que tenías, está correcto)
Example ¶
xmlData := `<config><port>8080</port></config>`
m, _ := MapXML(strings.NewReader(xmlData), EnableExperimental())
rules := []Rule{
{Path: "config/port", Type: "int", Min: 1024, Max: 65535},
}
errs := Validate(m, rules)
if len(errs) == 0 {
fmt.Println("Valid Configuration")
}
Output: Valid Configuration
Types ¶
type ClientOption ¶
type ClientOption func(*SoapClient)
ClientOption para configuración funcional.
func WithBasicAuth ¶
func WithBasicAuth(user, pass string) ClientOption
func WithBearerToken ¶
func WithBearerToken(token string) ClientOption
func WithHeader ¶
func WithHeader(key, value string) ClientOption
func WithSoapActionBase ¶
func WithSoapActionBase(base string) ClientOption
func WithTimeout ¶
func WithTimeout(d time.Duration) ClientOption
func WithWSSecurity ¶
func WithWSSecurity(user, pass string) ClientOption
type Encoder ¶
type Encoder struct {
// contains filtered or unexported fields
}
Encoder writes XML directly to an io.Writer.
func NewEncoder ¶
NewEncoder creates a configured encoder.
Example ¶
data := map[string]any{
"response": map[string]any{
"@status": "ok",
"message": "Hello World",
},
}
// Write clean XML to stdout
NewEncoder(os.Stdout).Encode(data)
Output: <response status="ok"><message>Hello World</message></response>
type Option ¶
type Option func(*config)
Option defines a function to modify the parser configuration.
func EnableExperimental ¶
func EnableExperimental() Option
EnableExperimental (Soup Mode) enables aggressive settings for parsing dirty HTML. It activates: 1. Type Inference (strings are converted to int/bool/float if possible). 2. Lenient Mode (ignores strict XML syntax errors). 3. Soup Mode (Case-insensitive normalization for tags and attributes). 4. Void Element support (e.g., <br>, <img>, <input>).
Example ¶
ExampleSoupMode demonstrates how to scrape data from messy, real-world HTML. It uses "EnableExperimental" to handle void tags (like <br>, <img>), case insensitivity, and sanitizes <script> tags automatically.
htmlData := `
<html>
<body bgcolor="#FFF">
<div class="product-list">
<div id="p1" data-stock="yes">
<h2>Gaming Mouse</h2>
<span class="price">$50</span>
<img src="mouse.jpg">
</div>
</div>
</body>
</html>`
// 1. Enable Soup Mode (Lenient + Void Tags + Normalization)
m, _ := MapXML(strings.NewReader(htmlData), EnableExperimental())
// 2. Query using normalized paths (all lowercase) and attributes
name, _ := Get[string](m, "html/body/div/div/h2/#text")
price, _ := Get[string](m, "html/body/div/div/span/#text")
stock, _ := Get[string](m, "html/body/div/div/@data-stock")
fmt.Printf("Product: %s, Price: %s, Stock: %s\n", name, price, stock)
Output: Product: Gaming Mouse, Price: $50, Stock: yes
func EnableLegacyCharsets ¶
func EnableLegacyCharsets() Option
EnableLegacyCharsets habilita el soporte para ISO-8859-1 y Windows-1252.
Example ¶
// IMPORTANTE: Construimos el XML simulando que viene de un archivo antiguo.
// Usamos escapes hexadecimales para forzar bytes ISO-8859-1 reales:
// \xF3 es 'ó' en ISO-8859-1 (en UTF-8 sería \xC3\xB3)
// \xF1 es 'ñ' en ISO-8859-1 (en UTF-8 sería \xC3\xB1)
xmlData := "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n" +
"<transacci\xF3n>\n" +
" <descripci\xF3n>Pago de expensas a\xF1o 2023</descripci\xF3n>\n" +
" <moneda>ARS</moneda>\n" +
"</transacci\xF3n>"
// El parser detectará el encoding en el header y usará nuestro CharsetReader
// para transformar esos bytes \xF3 y \xF1 a UTF-8 válido internamente.
m, err := MapXML(strings.NewReader(xmlData), EnableLegacyCharsets())
if err != nil {
fmt.Println("Error:", err)
return
}
// Buscamos usando nombres de tags normales (en UTF-8/Go nativo)
// Nótese que aquí SÍ escribimos 'ó' normal, porque el mapa 'm' ya está en UTF-8.
desc, _ := Query(m, "transacción/descripción")
fmt.Println(desc)
Output: Pago de expensas año 2023
func ForceArray ¶
ForceArray returns an Option that forces specific tags to be parsed as arrays ([]any). This prevents the common XML-to-JSON ambiguity where single items are parsed as objects.
Example ¶
// Case where there is only one item, but we want to treat it as a list
xmlData := `<list><item>One</item></list>`
m, _ := MapXML(strings.NewReader(xmlData), ForceArray("item"))
// CORRECTION: Same here, we look for the item directly, not its internal #text
items, _ := QueryAll(m, "list/item")
fmt.Println("Items:", len(items))
Output: Items: 1
func RegisterNamespace ¶
RegisterNamespace returns an Option that registers a short alias for a namespace URL. Example: RegisterNamespace("html", "http://www.w3.org/html")
func WithPrettyPrint ¶
func WithPrettyPrint() Option
WithPrettyPrint enables indentation for the Encoder (output beautification).
type QueryFunction ¶
QueryFunction defines the signature for custom key filter functions. It receives a map key (string) and returns true if the key should be traversed.
type Rule ¶
type Rule struct {
// Path to the element to validate (e.g., "server/port").
Path string
// Required enforces that the path must exist.
Required bool
// Type enforces the data type ("int", "float", "string", "array", "bool").
Type string
// Min enforces a minimum numeric value.
Min float64
// Max enforces a maximum numeric value.
Max float64
// Regex enforces a string pattern match.
Regex string
// Enum enforces that the value must be one of the provided strings.
Enum []string
}
Rule defines a validation constraint for the Validate engine. It is used to enforce schema-like requirements on dynamic maps.
type SoapClient ¶
type SoapClient struct {
EndpointURL string
Namespace string
HttpClient *http.Client
SoapActionBase string
Headers map[string]string
// Configuración de Auth
AuthType string
AuthUsername string
AuthPassword string
AuthToken string
}
SoapClient permite llamadas dinámicas a servicios SOAP sin structs.
func NewSoapClient ¶
func NewSoapClient(endpoint, namespace string, opts ...ClientOption) *SoapClient
NewSoapClient crea un nuevo cliente.
type Stream ¶
type Stream[T any] struct { // contains filtered or unexported fields }
Stream allows iterating over huge XML files efficiently without loading the entire content into memory. It leverages Go Generics to yield typed structs directly.
func NewStream ¶
NewStream initializes a new streaming iterator for a specific XML tag. r: The input reader (file, http body, etc). tagName: The local name of the XML element to iterate over (e.g., "Item", "Entry"). opts: Variadic options (e.g., EnableLegacyCharsets)
Example ¶
ExampleStream demonstrates how to process huge XML files efficiently. Instead of loading the entire file into RAM, it iterates element by element using Go Generics to map data directly to a struct.
xmlData := `
<orders>
<Order><Id>101</Id><Total>500</Total></Order>
<Order><Id>102</Id><Total>1200</Total></Order>
<Order><Id>103</Id><Total>300</Total></Order>
</orders>`
type Order struct {
Id int `xml:"Id"`
Total int `xml:"Total"`
}
// 1. Create a Stream for "Order" tags
stream := NewStream[Order](strings.NewReader(xmlData), "Order")
// 2. Iterate efficiently
totalRevenue := 0
for order := range stream.Iter() {
if order.Total > 1000 {
fmt.Printf("High Value Order: %d\n", order.Id)
}
totalRevenue += order.Total
}
fmt.Printf("Total Revenue: %d\n", totalRevenue)
Output: High Value Order: 102 Total Revenue: 2000
func (*Stream[T]) Iter ¶
func (s *Stream[T]) Iter() <-chan T
Iter returns a read-only channel of items of type T. It is a convenience wrapper around IterWithContext using context.Background().
Usage:
stream := xml.NewStream[MyStruct](reader, "MyTag")
for item := range stream.Iter() {
// process item
}
func (*Stream[T]) IterWithContext ¶
IterWithContext returns a channel of items, respecting the provided Context. Use this method if you need to cancel the streaming process early or handle timeouts.
Usage:
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
for item := range stream.IterWithContext(ctx) { ... }
type SyntaxError ¶
SyntaxError wraps the standard xml.SyntaxError but exposes fields publicly and adds context if available.
func (*SyntaxError) Error ¶
func (e *SyntaxError) Error() string
func (*SyntaxError) Unwrap ¶
func (e *SyntaxError) Unwrap() error