web stats

KATA 2 OF 8 · XML LAYER

The XPath Toolkit: All Seven Commands

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.

What you'll build

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.

The seven commands

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 attribute

Changes 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 attribute

Unlike 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 node

Where 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 node

Deletes the node(s) the xpath selects. Self-closing - there is no content.

<remove xpath="/items/item[@name='gunHandgunT1Pistol']/property[@name='UnlockedBy']" />

removeattribute - delete one attribute

Deletes a single attribute, leaving the node in place.

<removeattribute xpath="/items/item[@name='meleeToolStoneAxe']/@category" />

Aiming them: the XPath you need

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:

PatternSelects
/items/itemevery <item> directly under <items>
/items/item//property<property> at any depth under an item (note the double slash)
/items/item/@namethe name attribute of those items
[@name='resourceWood']only the node whose name equals that (a predicate)
[@value > 2] / [@value < 4]numeric comparison - write &gt; / &lt; 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.

A combined example

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>

Test it the smart way

You do not have to relaunch and play to verify XPath. Two faster loops:

  • Read the log on load. A bad xpath that matches nothing usually logs a warning (for set) or a clear error; a malformed file logs a red XML error with the line number. Watch the startup log first, every time.
  • Confirm the node names against vanilla. Open the game's own 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.

Common pitfalls

  • set vs setattribute. set only edits attributes that already exist; to create a new attribute use setattribute, to add a whole node use append.
  • Unescaped comparison operators. A literal < or > inside an xpath breaks the XML. Always write &lt; and &gt;.
  • Too-greedy selectors. /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.
  • Load order matters for conflicts. If two modlets 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.