**** xref:xlat/misc/config.adoc[Server Configuration]
**** xref:xlat/misc/length.adoc[length]
**** xref:xlat/misc/misc.adoc[Miscellaneous]
-**** xref:xlat/misc/pairs.adoc[pairs.print]
**** xref:xlat/misc/rand.adoc[rand]
+*** xref:xlat/pairs/index.adoc[Pairs]
+**** xref:xlat/pairs/debug.adoc[Write to debug output]
+**** xref:xlat/pairs/immutable.adoc[Mark as immutable]
+**** xref:xlat/pairs/print.adoc[Print to string]
+
*** xref:xlat/str/index.adoc[String Handling]
**** xref:xlat/str/concat.adoc[Concatenation]
**** xref:xlat/str/split.adoc[Split Strings]
| xref:xlat/misc/config.adoc[Server Configuration] | Examine configuration items
| xref:xlat/misc/length.adoc[length] | Get the length of data
| xref:xlat/misc/misc.adoc[Miscellaneous] | Functions to execute regular expression search on string, using pattern.
-| xref:xlat/misc/pairs.adoc[pairs.print] | print attributes with name and value.
| xref:xlat/misc/rand.adoc[rand] | random integers
|===
+== Pair Manipulation
+
+.Pair Manipulation
+[options="headers, autowidth]
+|===
+| *Function* | *Description*
+| xref:xlat/pairs/debug.adoc[debug] | Print attributes to the debug output
+| xref:xlat/pairs/immutable.adoc[immutable] | Mark attributes as immutable (cannot be changed)
+| xref:xlat/pairs/print.adoc[print] | Print attribute name and value to string
+|===
+
== String Manipulation
.String manipulation
Maximum should be 12300000000
```
-== %pairs(<list>.[*])
-
-Serialize attributes as comma-delimited string.
-
-.Return: _string_
-
-.Example
-
-[source,unlang]
-----
-control.Tmp-String-0 := { "This is a string", "This is another one" }
-reply.Reply-Message := "Serialize output: %pairs(control.[*])"
-----
-
-.Output
-
-```
-Serialize output: Tmp-String-0 = "\"This is a string\", Tmp-String-0 = \"This is another one\""
-```
-
-== %str.rand( ...)
-
-Get random string built from character classes.
-
-.Return: _string_
-
-.Example
-
-[source,unlang]
-----
-reply.Reply-Message := "The random string output is %str.rand(aaaaaaaa}"
-----
-
-.Output
-
-```
-The random string output is 4Uq0gPyG
-```
-
== %str.lower( ... )
Dynamically expands the string and returns the lowercase version of
| xref:xlat/misc/config.adoc[Server Configuration] | Examine configuration items
| xref:xlat/misc/length.adoc[length] | Get the length of data
| xref:xlat/misc/misc.adoc[Miscellaneous] | Functions to execute regular expression search on string, using pattern.
-| xref:xlat/misc/pairs.adoc[pairs.print] | print attributes with name and value.
| xref:xlat/misc/rand.adoc[rand] | random integers
|===
--- /dev/null
+= Pair Functions
+
+These functions manipulate attribute-value pairs.
+
+.Pair Manipulation
+[options="headers, autowidth]
+|===
+| *Function* | *Description*
+| xref:xlat/pairs/debug.adoc[debug] | Print attributes to the debug output
+| xref:xlat/pairs/immutable.adoc[immutable] | Mark attributes as immutable (cannot be changed)
+| xref:xlat/pairs/print.adoc[print] | Print attribute name and value to string
+|===
+
+// Copyright (C) 2025 Network RADIUS SAS. Licenced under CC-by-NC 4.0.
+// This documentation was developed by Network RADIUS SAS.
Note that there is no "parse string into pairs" function. Instead,
you can simply assign the string to a structural attribute (`group`,
`tlv`, etc.) and the string will be parsed as assigning a value to a
-given attribute.
+given attribute. e.g. `reply += "User-Name := 'hello'"`.
.Example
[source,unlang]
----
control.Tmp-String-0 := { "This is a string", "This is another one" }
-reply.Reply-Message := "Serialize output: %pairs.print('control.[*]')"
+reply.Reply-Message := "Serialize output: %pairs.print(control.[*])"
----
.Output