Path syntax¶
Every addressing method — Get, Keys, Set, Remove — takes the same kind of
path. It is smaller than it looks, and knowing exactly how small saves an
afternoon.
The grammar¶
That is the whole of it. A path is a dotted list of mapping keys, walked from the document root. There is no wildcard, no filter, no escape character and no quoting.
An empty path is only meaningful to Keys, where it means the document root.
Get, Set and Remove reject it.
What a path cannot address¶
This is the section most people arrive here for. None of the following work, and most of them fail quietly rather than loudly.
Sequence elements¶
There is no index syntax. A YAML sequence is opaque to a path: you can address the key that holds it and replace the whole thing, but you cannot reach an item inside it.
doc.Get("servers") // ok — the whole sequence, as a collection node
doc.Set("servers", []string{"alpha", "beta"}) // ok — replaces it wholesale
doc.Get("servers.name") // not found; a sequence is not a mapping
servers[0].port is not a path with an index in it — it is a path whose first
segment is the literal key servers[0]. Nothing in the library rejects that, so:
creates a new top-level key literally named servers[0] containing a mapping
with port: 9090, and reports no error. If you are building paths from user
input, reject bracket syntax yourself before passing it on.
Editing inside a sequence means reading the sequence out, changing it in Go, and setting it back — which loses the comments and styles inside it, because the Go value does not carry them.
Keys containing a dot¶
A dot is always a separator, never part of a key. A document with
lists log.level from Keys("") and cannot be addressed by any path: Get("log.level")
looks for a key log holding a key level, finds no log, and returns false.
Setting it creates the nested pair instead, leaving the flat key in place.
Anything below an alias¶
An *alias is a reference. The walk does not follow it, so Get("use.x") on
use: *base is not found. Address the anchor definition instead.
Documents¶
A path starts inside one document. Which document you are in is decided by which
*Document you called the method on; see
File.Documents.
Where a walk stops, and what you get back¶
Path against a: 1 and b: {c: 2} |
Result |
|---|---|
b.c |
resolves |
b.d |
does not exist yet — Get false, Set creates it |
b.d.e |
does not exist yet — Set creates d as a mapping holding e |
a.b |
blocked: a is a scalar. Set returns ErrNotFound naming a, rather than destroying it |
"" |
ErrInvalidPath: empty |
a..b |
ErrInvalidPath: "a..b" has an empty segment |
a. |
ErrInvalidPath — a trailing dot is an empty segment |
The blocked case is deliberate. Creating a.b would mean deleting the scalar
a first, which is not what the caller asked for, so the walk refuses instead of
choosing for you.
Merge keys are addressable, which is rarely what you want¶
A mapping written with <<: *base has a real key named <<, so Keys lists it
and Get("child.<<") resolves to the alias node.
Removing an anchor a merge key still uses is refused, naming the merge site:
Case and whitespace¶
Keys match exactly — byte for byte, case-sensitively, with no trimming. A path is
only rejected as malformed when a segment is empty; Set(" a", 1) addresses a key
whose name begins with a space, and creates one if it is missing.