# anynode **Repository Path**: zoppax/anynode ## Basic Information - **Project Name**: anynode - **Description**: No description available - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-03-16 - **Last Updated**: 2026-04-03 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Anynode A typed, ordered tree node for Go. Wraps `any` with metadata, replaces `map` with an ordered map, and provides path-based access, serialization, and JSON/TOML I/O. ## Install ```bash go get gitee.com/zoppax/anynode ``` ## Core Types ```go type AnynodeDef struct { Name string NodeType string // object/array/string/int/number/bool/date/time/datetime Label string Required bool Optional bool DefaultValue any Options string // comma-separated options Comment string } type Anynode struct { NodeDef *AnynodeDef Value any // *ObjectType | *ArrayType | scalar ParentNode *Anynode } ``` ## Quick Start ```go root := anynode.NewAnynode() // Put: add child to object node, returns current node root.Put("name", "Alice", "string") root.Put("age", 30, "int") // PutAndMove: add child, returns the new child addr := root.PutAndMove("address", nil, "object") addr.Put("city", "Beijing", "string") // Append / AppendAndMove on array nodes root.Put("tags", nil, "array") tags := root.Locate("tags") tags.Append("go", "string").Append("tree", "string") ``` ## API ### Build | Method | Returns | Description | | ----------------------------------------------- | -------------- | ------------------------------------------------ | | `NewAnynode()` | `*Anynode` | Create root node (object, no parent) | | `Put(name, value, nodetype, nodedef...)` | `*Anynode` | Add/overwrite child in object node, return self | | `PutAndMove(name, value, nodetype, nodedef...)` | `*Anynode` | Add/overwrite child, return new child | | `Append(value, nodetype, nodedef...)` | `*Anynode` | Append element to array node, return self | | `AppendAndMove(value, nodetype, nodedef...)` | `*Anynode` | Append element, return new element | | `MergeObject(m)` | `*Anynode` | Merge object m into current object node | | `MergeArray(m)` | `*Anynode` | Merge array m into current array node | | `FillObject(v)` | `*Anynode` | Fill object node with values from v | | `Remove(name)` | `*Anynode` | Delete named child from object node, return self | | `Def(deflist)` | `*Anynode` | Batch-define subtree from text DSL, return self | | `Get(path)` | `(any, error)` | Get value at path | | `Set(path, value)` | `*Anynode` | Set value at path, return self | ### Navigate | Method | Returns | Description | | -------------- | ---------- | ------------------------------- | | `Locate(path)` | `*Anynode` | Path lookup; `nil` if not found | | `Parent()` | `*Anynode` | Return parent node | ### Query | Method | Returns | Description | | ----------------------- | ----------------- | ---------------------------------- | | `GetDefaultValue(path)` | `(any, error)` | Get `NodeDef.DefaultValue` at path | | `GetOptions(path)` | `(string, error)` | Get `NodeDef.Options` at path | ### Path Syntax ``` "name" child field "a/b/c" nested fields "[0]" array index ".." parent "/" absolute from root "." or "" current node ``` ### Serialize / Deserialize ```go // Custom binary-safe format str := anynode.Serialize(root) // compact str = anynode.Serialize(root, true) // pretty root, err := anynode.Deserialize(str) ``` ### JSON ```go str, err := anynode.ToJson(root) // compact str, err = anynode.ToJson(root, true) // pretty, preserves field order root, err := anynode.FromJson(str) ``` ### TOML ```go str, err := anynode.ToToml(root) root, err := anynode.FromToml(str) ``` ### Def DSL Batch-define a subtree with an indented text format: ```go root.Def(` - {user} : 用户 : object - name : 姓名 : required=true - age : 年龄 : int - [tags] : 标签 : array `) ``` Each line: `- name : label : nodetype : key=value ...` `{name}` → object node, `[name]` → array node. ### ParseOptions ```go items := anynode.ParseOptions("a, b, a, c") // ["a", "b", "c"] — trimmed, deduped, ordered ``` ## Config Map `Put`, `Append`, and `Def` accept optional `map[string]any` nodedef: ```go root.Put("score", 0, "int", map[string]any{ "label": "Score", "default": 100, "options": "0,50,100", "comment": "user score", "required": true, }) ``` ## Examples ### Using Put() to add children ```go root := anynode.NewAnynode() // Add scalar values root.Put("name", "Bob", "string") root.Put("age", 25, "int") root.Put("active", true, "bool") root.Put("score", 95.5, "number") // Add container types with nil value (auto-initialized) root.Put("config", nil, "object") root.Put("items", nil, "array") ``` ### Using Put() with existing Anynode nodes ```go root := anynode.NewAnynode() // Create a standalone Anynode child := anynode.NewAnynode() child.Put("key", "value", "string") childNode := child.Locate("key") // Put the existing node into root // nodetype and nodedef are ignored root.Put("data", childNode, "ignored", map[string]any{"label": "ignored"}) ``` ### Using Append() to add array elements ```go root := anynode.NewAnynode() root.Put("list", nil, "array") list := root.Locate("list") // Add scalar elements list.Append("first", "string") list.Append(100, "int") list.Append(true, "bool") // Chain calls list.Append("second", "string").Append("third", "string") ``` ### Using Append() with existing Anynode nodes ```go root := anynode.NewAnynode() root.Put("items", nil, "array") items := root.Locate("items") // Create standalone Anynode nodes objNode := anynode.NewAnynode() objNode.Put("name", "test", "string") scalarNode := anynode.NewAnynode() scalarNode.Put("temp", 42, "int") scalarChild := scalarNode.Locate("temp") // Append existing nodes items.Append(objNode) // append object node items.Append(scalarChild) // append scalar node // nodetype and nodedef are ignored when value is Anynode ``` ### Using AppendAndMove() ```go root := anynode.NewAnynode() root.Put("items", nil, "array") items := root.Locate("items") // AppendAndMove returns the new element item := items.AppendAndMove(nil, "object") item.Put("id", 1, "int") item.Put("name", "Item 1", "string") // Also works with existing Anynode nodes existing := anynode.NewAnynode() existing.Put("id", 2, "int") item2 := items.AppendAndMove(existing) // item2 is the same as existing ``` ### Using MergeObject() ```go n := anynode.NewAnynode() n.Put("a", 1, "int") n.Put("b", 2, "int") m := anynode.NewAnynode() m.Put("b", 20, "int") // will overwrite n's "b" m.Put("c", 30, "int") // will add new field "c" n.MergeObject(m) // n now has {a:1, b:20, c:30} ``` ### Using MergeArray() ```go n := anynode.NewAnynode() n.Put("items", nil, "array") arr := n.Locate("items") arr.Append(1, "int").Append(2, "int") m := anynode.NewAnynode() m.Put("items", nil, "array") mArr := m.Locate("items") mArr.Append(3, "int").Append(4, "int") arr.MergeArray(mArr) // arr now has [1, 2, 3, 4] ``` ### Using FillObject() ```go n := anynode.NewAnynode() n.Put("name", "", "string") n.Put("age", 0, "int") n.Put("active", false, "bool") // Fill from map[string]any v1 := map[string]any{ "name": "Alice", "age": 25, "ignored": "this will be skipped", } n.FillObject(v1) // n now has {name:"Alice", age:25, active:false} // Fill from another Anynode source := anynode.NewAnynode() source.Put("age", 26, "int") source.Put("active", true, "bool") n.FillObject(source) // n now has {name:"Alice", age:26, active:true} ``` ## Dependencies - [`github.com/zoppax/mval`](https://gitee.com/zoppax/mval) — ordered map - [`github.com/BurntSushi/toml`](https://github.com/BurntSushi/toml) v1.6.0 — TOML decode ## License MIT