mirror of
https://github.com/imgproxy/imgproxy.git
synced 2025-12-23 22:11:10 +02:00
139 lines
3.3 KiB
Go
139 lines
3.3 KiB
Go
package xmlparser
|
|
|
|
import (
|
|
"iter"
|
|
"slices"
|
|
)
|
|
|
|
// Attribute represents a single XML attribute.
|
|
type Attribute struct {
|
|
Name Name
|
|
Value string
|
|
}
|
|
|
|
// Attributes represents a collection of XML attributes.
|
|
type Attributes struct {
|
|
s []*Attribute // Slice for ordered iteration
|
|
m map[Name]*Attribute // Map for quick lookup
|
|
}
|
|
|
|
// NewAttributes creates a new [Attributes] instance from the given attributes.
|
|
func NewAttributes(attrs ...*Attribute) *Attributes {
|
|
// If no attributes are provided, return an empty Attributes instance
|
|
if len(attrs) == 0 {
|
|
return &Attributes{}
|
|
}
|
|
|
|
// Create a map for quick lookup
|
|
m := make(map[Name]*Attribute, len(attrs))
|
|
for _, attr := range attrs {
|
|
m[attr.Name] = attr
|
|
}
|
|
|
|
return &Attributes{
|
|
s: attrs,
|
|
m: m,
|
|
}
|
|
}
|
|
|
|
// Get retrieves the value of the attribute with the given name.
|
|
// It returns the value and true if the attribute exists, or an empty string and false otherwise.
|
|
func (a *Attributes) Get(name Name) (string, bool) {
|
|
if attr, ok := a.m[name]; ok {
|
|
return attr.Value, true
|
|
}
|
|
return "", false
|
|
}
|
|
|
|
// GetByString is like Get but accepts a string name.
|
|
func (a *Attributes) GetByString(name string) (string, bool) {
|
|
return a.Get(Name(name))
|
|
}
|
|
|
|
// Set sets the value of the attribute with the given name.
|
|
// If the attribute does not exist, it is created.
|
|
func (a *Attributes) Set(name Name, value string) {
|
|
// Initialize the map if it is nil
|
|
if a.m == nil {
|
|
a.m = make(map[Name]*Attribute)
|
|
}
|
|
|
|
// If attribute exists, update its value
|
|
if attr, exists := a.m[name]; exists {
|
|
attr.Value = value
|
|
return
|
|
}
|
|
|
|
// Otherwise, create a new attribute
|
|
attr := &Attribute{Name: name, Value: value}
|
|
a.m[name] = attr
|
|
a.s = append(a.s, attr)
|
|
}
|
|
|
|
// SetByString is like Set but accepts a string name.
|
|
func (a *Attributes) SetByString(name, value string) {
|
|
a.Set(Name(name), value)
|
|
}
|
|
|
|
// Delete removes the attribute with the given name.
|
|
func (a *Attributes) Delete(name Name) {
|
|
// If attribute does not exist, nothing to do
|
|
attr, exists := a.m[name]
|
|
if !exists {
|
|
return
|
|
}
|
|
|
|
// Remove from map
|
|
delete(a.m, name)
|
|
|
|
// Remove from slice
|
|
if idx := slices.Index(a.s, attr); idx != -1 {
|
|
a.s = slices.Delete(a.s, idx, idx+1)
|
|
}
|
|
}
|
|
|
|
// DeleteByString is like Delete but accepts a string name.
|
|
func (a *Attributes) DeleteByString(name string) {
|
|
a.Delete(Name(name))
|
|
}
|
|
|
|
// Has returns true if the attribute with the given name exists.
|
|
func (a *Attributes) Has(name Name) bool {
|
|
_, exists := a.m[name]
|
|
return exists
|
|
}
|
|
|
|
// HasByString is like Has but accepts a string name.
|
|
func (a *Attributes) HasByString(name string) bool {
|
|
return a.Has(Name(name))
|
|
}
|
|
|
|
// Len returns the number of attributes.
|
|
func (a *Attributes) Len() int {
|
|
return len(a.s)
|
|
}
|
|
|
|
// Iter returns an iterator over the attributes.
|
|
//
|
|
// !WARNING! Don't delete items from the Attributes while iterating.
|
|
// If you need to filter attributes, use the Filter method.
|
|
func (a *Attributes) Iter() iter.Seq[*Attribute] {
|
|
return slices.Values(a.s)
|
|
}
|
|
|
|
// Filter removes all attributes that do not satisfy the predicate function.
|
|
func (a *Attributes) Filter(pred func(*Attribute) bool) {
|
|
a.s = slices.DeleteFunc(a.s, func(attr *Attribute) bool {
|
|
del := !pred(attr)
|
|
if del {
|
|
delete(a.m, attr.Name)
|
|
}
|
|
return del
|
|
})
|
|
}
|
|
|
|
// Sort sorts the attributes according to the provided function.
|
|
func (a *Attributes) Sort(cmp func(i, j *Attribute) int) {
|
|
slices.SortFunc(a.s, cmp)
|
|
}
|