KATA 2 OF 8 · XML LAYER
In Kata 1 you used <set> to change one value. That is one of seven XML modification commands the game exposes. Learn all seven and the XPath that aims them, and you can change, add, or remove anything in the game's XML - which is the entire job for the next two katas. This is the reference you will come back to most.
No single mod this time - this kata is the toolkit itself, with a verified example of each command, then a small combined modlet at the end that uses three of them together.
All take an xpath attribute that points at a node or attribute. (These were introduced in Alpha 17 and are the same in V2.6 and V3.0.)
set - change an existing attributeChanges a value that already exists. If the target attribute does not exist, it does not create it - it logs a warning. This is the Kata 1 command.
<set xpath="/items/item[@name='meleeToolStoneAxe']/property[@name='DegradationMax']/@value">500</set>
setattribute - add or change a named attributeUnlike set, this can create an attribute on a node that did not have it. You give the node in xpath and the attribute in name.
<setattribute xpath="/items/item[@name='meleeToolStoneAxe']/property[@name='Weight']" name="measure">kilograms</setattribute>
append - add new nodes (or extend an attribute)The workhorse for adding content. Point at a parent node and the content inside the tag becomes a new child. (Point at an attribute instead and the text is appended to that attribute's value - handy for adding a tag.)
<!-- add a whole new property to an item -->
<append xpath="/items/item[@name='gunHandgunT1Pistol']">
<property name="MyCustomProp" value="1" />
</append>
<!-- or append to an attribute value (note the leading comma) -->
<append xpath="/items/item[@name='gunHandgunT1Pistol']/property[@name='Tags']/@value">,myNewTag</append>
insertAfter / insertBefore - place a sibling nodeWhere append adds a child inside a node, these add a sibling directly after or before the targeted node - useful when order matters (recipes, progression, UI elements).
<insertAfter xpath="/items/item[@name='gunHandgunT1Pistol']/property[@name='Tags']">
<property name="AddedAfterTags" value="a,b,c" />
</insertAfter>
remove - delete a nodeDeletes the node(s) the xpath selects. Self-closing - there is no content.
<remove xpath="/items/item[@name='gunHandgunT1Pistol']/property[@name='UnlockedBy']" />
removeattribute - delete one attributeDeletes a single attribute, leaving the node in place.
<removeattribute xpath="/items/item[@name='meleeToolStoneAxe']/@category" />
The command is the verb; the XPath is the address. Ninety percent of modding is writing an XPath that selects exactly the node you mean and nothing else. The pieces:
| Pattern | Selects |
|---|---|
/items/item | every <item> directly under <items> |
/items/item//property | <property> at any depth under an item (note the double slash) |
/items/item/@name | the name attribute of those items |
[@name='resourceWood'] | only the node whose name equals that (a predicate) |
[@value > 2] / [@value < 4] | numeric comparison - write > / < inside the XML |
[@name='x' or @name='y'] | logical OR; and and not(...) work too |
[starts-with(@name,'gun')] | string match - also ends-with and contains |
[1] / [last()] | the first / last matching sibling by position |
[@category] | nodes that simply have a category attribute |
/.. | step up to the parent node |
Combine them freely: /items/item[contains(@name,'gun') and not(@name='gunHandgunT1Pistol')]/property[@name='Magazine_size']/@value selects the magazine size of every gun except that one pistol.
Here is a single Config/items.xml that uses three commands together - the kind of small, real modlet you will write constantly:
<configs>
<!-- bump every stone tool's durability -->
<set xpath="/items/item[starts-with(@name,'meleeToolStone')]/property[@name='DegradationMax']/@value">1000</set>
<!-- give the stone axe a new tag -->
<append xpath="/items/item[@name='meleeToolStoneAxe']/property[@name='Tags']/@value">,reinforced</append>
<!-- strip the perk requirement off the wrench -->
<remove xpath="/items/item[@name='meleeToolRepairT1Wrench']/property[@name='UnlockedBy']" />
</configs>
You do not have to relaunch and play to verify XPath. Two faster loops:
set) or a clear error; a malformed file logs a red XML error with the line number. Watch the startup log first, every time.Data/Config/items.xml (and blocks.xml, recipes.xml...) and search for the exact name before you write the xpath. Most "my mod did nothing" cases are a misremembered name, and these files are the only source of truth.set vs setattribute. set only edits attributes that already exist; to create a new attribute use setattribute, to add a whole node use append.< or > inside an xpath breaks the XML. Always write < and >./items/item hits every item in the game. Add a predicate, or you will edit thousands of things and wonder why balance feels off. Test broad selectors against vanilla first.set the same attribute, the one that loads later wins. Kata 8 covers controlling that.Next: Kata 3 - Add an Item, Recipe & Localization. You can now edit, add, and remove. Next you combine append across items.xml and recipes.xml with a Localization entry to ship a genuinely new, craftable, properly-named item.