• If you have a mod, tool or prefab, please use the Resources section. Click Mods at the top of the forums.

XPath Modding Explanation Thread

This is a large amount of information in these posts. I'll be working on a full, properly formed tutorial as we get access to A17 and we can really make the xpath system shine. I've listed some examples here, and we'll be posting a ton more xpath samples over the coming weeks, as we port the SDX modlets over to use the native hooks.

By all means, begin posting your comments, questions, or requests for clarity.

Since we now know that xpath support will be built-into the vanilla base game, and discussions earlier were getting a bit confusing, I've decided to make a new thread to try to demystify xpath and what it'll mean for mods and modders going forward in A17. The information in this thread has been pieced together from forum and discord discussions. They may not be 100% accurate, but I will update this thread when we know the full implementation.

XPath is a way of adding, changing, or removing XML lines and nodes, without directly editing the XML files. It allows you to apply patches to the XML files without manually editing the vanilla XML files.

SDX has had partial support for this since its initial release, and a lot of the SDX Modlets are already written this way. We will be using some of the SDX's xpath as examples in this thread, but SDX is not required to do this in A17 and onwards.

I believe in using examples to explain concept, so in the next few posts, you'll see a mixture of explanation, along with sample xpath code.

The following Mod structure is expected for A17 and beyond:

Code:
Mods/
   <ModName>/
       Config/
       UIAtlases/ItemIconAtlas/
       ModInfo.xml

   <ModName2>/
       Config/
       ModInfo.xml
You will be able to have multiple mods loaded, and loading will occur as long as the ModInfo.xml exists. This is unchanged from what we've been doing doing with other alphas, with the exception of the Config folder.

This Config folder will support loading XML files, written using xpath, in the following folder structure:

Code:
Config/entityclasses.xml
Config/gamestages.xml
Config/items.xml
The files in the Config folder will not be a full copy of the vanilla file with your changes. Rather, it'll contain the changes you want done to the vanilla files. The files under the Config must match the vanilla file name. You cannot create an entityclasses2.xml file, and expect it to work. Any changes in the entityclasses.xml will have to be done in the same file. However, each mod can have its own entityclasses.xml.

During the game's initialization, it will perform the xpath merge in-memory only; no files will be actually be modified. This would allow us to remove mods we no longer want, without re-validating against steam, or previous copies of the xml. That's a big one. No more half merging of a mod, and not having it work, then trying to pull it back out.

What this means for us is that we'll be able to make a variety of smaller mods, which I've been calling modlets, which can add, remove and change smaller pieces of the game. They can be used together, or they could be added to an overhaul mod, in order to style your game play easier.

These modlets would also exists outside of the Data/Config folder, so if you have made direct XML changes in your Alpha 17.1 Data/Config files, and Steam updated the game to 17.2, you would have lost your changes, or would have to re-merge them in. We've all been there before. But if they existed as modlets, under the Mods folder, they would be safe. And as long as your xpath is still valid to the new XML, it should load up with no additional work on your part.

If we could use xyth's JunkItems modlet, which adds random, scrappable junk items to loot containers, and add them to Valmod Overhaul. Likewise, if Valmod Overhaul did not have the No Ammo modlet (which gives you the ability to unload a gun and get its bullets back without disassembling it), you could drop the NoAmmo modlet into your Mods folder. Headshots only? Want to increase stack sizes? Same deal.

With a properly constructed modlet, we'll be able to piece together new play styles for people to enjoy and share. A modder working on a large overhaul won't have to duplicate work. If they wanted to include the No Ammo mod, they wouldn't have to code it themselves, letting them focus on the bits that make their mod really unique.

Let's get started on your journey...

 
Last edited by a moderator:
Running into a slight headache. Anyone know WHY im getting that extra </item> tag at the end of this code?

Code:
<lootcontainer id="36" count="0,2" size="4,3" sound_open="UseActions/open_suitcase" sound_close="UseActions/close_suitcase" loot_quality_template="baseTemplate">
   <item name="drinkJarBoiledWater" count="1" prob="0.15"><!--Attribute "count" replaced by: "JaxTeller718_LessWaterInLoot"--></item>
   <item group="cannedfood" prob="0.5" />
   <item group="junk" />
   <item name="meleeToolFlashlight02" prob="0.1" />
   <item group="medicine" prob="0.1" />
   <item group="weaponsBasicGuns+ammo" prob="0.03" />
   <item group="weaponsMelee" prob="0.03" />
   <item group="ammo" />
</lootcontainer>
here is the xpath im using for that

Code:
<set xpath="/lootcontainers/lootcontainer[@id='36']/item[@name='drinkJarBoiledWater']/@count">1</set>
That is valid XML, although it may look a bit weird. The modding hooks inserts that comment after each change.

Code:
<item name="drinkJarBoiledWater" count="10" prob="0.15" />
is the same as

Code:
<item name="drinkJarBoiledWater" count="10" prob="0.15" > </item>
Just on a single line xml node, a short cut can be used.

If it's causing a parsing error, than that is a bug. But otherwise, I'd expect that line to be functionally the same as the others.

- - - Updated - - -

How do i add an item to a lootgroup?
I want to add the fuellog to loot group Tools, i came up with this

Code:
<config>

<set xpath="/lootgroups/lootgroup[@name='tools']/item[@name='fuellog']/@count">1</set>

</config>
If you want to add a new line, it'd be append

Code:
<config>
   <append xpath="/lootgroups/lootgroup[@name='tools']">
       <item name="fuellog"' count="1" />
   </append>
</config>
 
Is this right to add fuellog to multiple groups?

Code:
<config>

   <append xpath="/lootgroups/lootgroup[@name='tools']">
       <item name="fuellog"' count="1" />


   <append xpath="/lootgroups/lootgroup[@name='junk']">
       <item name="fuellog"' count="1" />

   </append>	

</config>
 
Is this right to add fuellog to multiple groups?

Code:
<config>

   <append xpath="/lootgroups/lootgroup[@name='tools']">
       <item name="fuellog"' count="1" />


   <append xpath="/lootgroups/lootgroup[@name='junk']">
       <item name="fuellog"' count="1" />

   </append>	

</config>
Close. You'd need to </append> the first one, before you start working on a different xpath command.

 
So each new addition needs closed?

Code:
<config>
   <append xpath="/lootgroups/lootgroup[@name='tools']">
       <item name="fuellog"' count="1" />
  </append>

   <append xpath="/lootgroups/lootgroup[@name='junk']">
       <item name="fuellog"' count="1" />
   </append>	

</config>
 
So each new addition needs closed?


Code:
<config>
   <append xpath="/lootgroups/lootgroup[@name='tools']">
       <item name="fuellog"' count="1" />
  </append>

   <append xpath="/lootgroups/lootgroup[@name='junk']">
       <item name="fuellog"' count="1" />
   </append>	

</config>
Yup! The append looks good.

I think your xpath may be a bit off.

xpath="/lootcontainers/lootgroup[@name=tools]" may be more accurate, since the loogroup is under the <lootcontainers> node.

 
Yup! The append looks good.
I think your xpath may be a bit off.

xpath="/lootcontainers/lootgroup[@name=tools]" may be more accurate, since the loogroup is under the <lootcontainers> node.
Now im confusd. Containers and groups are in different sections? Add the item to the group, and it goes into the containers?

 
getting error in loot

Code:
2018-11-23T10:06:17 34.678 ERR Failed loading and parsing XML (loot.xml):
2018-11-23T10:06:17 34.679 EXC Unexpected token. Name is required here.  Line 3, position 29.
XmlException: Unexpected token. Name is required here.  Line 3, position 29.
 at Mono.Xml2.XmlTextReader.ReadAttributes (Boolean isXmlDecl) [0x00000] in <filename unknown>:0 
 at Mono.Xml2.XmlTextReader.ReadStartTag () [0x00000] in <filename unknown>:0 
 at Mono.Xml2.XmlTextReader.ReadContent () [0x00000] in <filename unknown>:0 
 at Mono.Xml2.XmlTextReader.Read () [0x00000] in <filename unknown>:0 
 at System.Xml.XmlTextReader.Read () [0x00000] in <filename unknown>:0 
 at System.Xml.XmlDocument.ReadNodeCore (System.Xml.XmlReader reader) [0x00000] in <filename unknown>:0 
 at System.Xml.XmlDocument.ReadNodeCore (System.Xml.XmlReader reader) [0x00000] in <filename unknown>:0 
 at System.Xml.XmlDocument.ReadNodeCore (System.Xml.XmlReader reader) [0x00000] in <filename unknown>:0 
 at System.Xml.XmlDocument.ReadNode (System.Xml.XmlReader reader) [0x00000] in <filename unknown>:0 
 at System.Xml.XmlDocument.Load (System.Xml.XmlReader xmlReader) [0x00000] in <filename unknown>:0 
 at System.Xml.XmlDocument.LoadXml (System.String xml) [0x00000] in <filename unknown>:0 
 at XmlFile.toXml (System.String _data, System.String _filename) [0x00000] in <filename unknown>:0 
UnityEngine.DebugLogHandler:Internal_LogException(Exception, Object)
UnityEngine.DebugLogHandler:LogException(Exception, Object)
UnityEngine.Logger:LogException(Exception, Object)
UnityEngine.Debug:LogException(Exception)
Logger:masterLogException(Exception)
Logger:Exception(Exception)
Log:Exception(Exception)
XmlFile:toXml(String, String)
XmlFile:.ctor(String, String, String)
XmlPatcher:LoadAndPatchConfig(String)
<loadSingleXml>c__Iterator1:MoveNext()
UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)

(Filename:  Line: -1)
 
Now im confusd. Containers and groups are in different sections? Add the item to the group, and it goes into the containers?
In loot.xml, the <lootcontainers> is the root XML node.

M7bQMCl.png


 
getting error in loot

Code:
2018-11-23T10:06:17 34.678 ERR Failed loading and parsing XML (loot.xml):
2018-11-23T10:06:17 34.679 EXC Unexpected token. Name is required here.  Line 3, position 29.
XmlException: Unexpected token. Name is required here.  Line 3, position 29.
 at Mono.Xml2.XmlTextReader.ReadAttributes (Boolean isXmlDecl) [0x00000] in <filename unknown>:0 
 at Mono.Xml2.XmlTextReader.ReadStartTag () [0x00000] in <filename unknown>:0 
 at Mono.Xml2.XmlTextReader.ReadContent () [0x00000] in <filename unknown>:0 
 at Mono.Xml2.XmlTextReader.Read () [0x00000] in <filename unknown>:0 
 at System.Xml.XmlTextReader.Read () [0x00000] in <filename unknown>:0 
 at System.Xml.XmlDocument.ReadNodeCore (System.Xml.XmlReader reader) [0x00000] in <filename unknown>:0 
 at System.Xml.XmlDocument.ReadNodeCore (System.Xml.XmlReader reader) [0x00000] in <filename unknown>:0 
 at System.Xml.XmlDocument.ReadNodeCore (System.Xml.XmlReader reader) [0x00000] in <filename unknown>:0 
 at System.Xml.XmlDocument.ReadNode (System.Xml.XmlReader reader) [0x00000] in <filename unknown>:0 
 at System.Xml.XmlDocument.Load (System.Xml.XmlReader xmlReader) [0x00000] in <filename unknown>:0 
 at System.Xml.XmlDocument.LoadXml (System.String xml) [0x00000] in <filename unknown>:0 
 at XmlFile.toXml (System.String _data, System.String _filename) [0x00000] in <filename unknown>:0 
UnityEngine.DebugLogHandler:Internal_LogException(Exception, Object)
UnityEngine.DebugLogHandler:LogException(Exception, Object)
UnityEngine.Logger:LogException(Exception, Object)
UnityEngine.Debug:LogException(Exception)
Logger:masterLogException(Exception)
Logger:Exception(Exception)
Log:Exception(Exception)
XmlFile:toXml(String, String)
XmlFile:.ctor(String, String, String)
XmlPatcher:LoadAndPatchConfig(String)
<loadSingleXml>c__Iterator1:MoveNext()
UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)

(Filename:  Line: -1)
Can you post your full xml snippet?

 
The full error or modlet?

Code:
<config>
   <append xpath="/lootcontainers/lootgroup[@name='tools']">
       <item name="fuellog"' count="1" />
  </append>

   <append xpath="/lootcontainers/lootgroup[@name='junk']">
       <item name="fuellog"' count="1" />
   </append>	

</config>
 
The full error or modlet?


Code:
<config>
   <append xpath="/lootcontainers/lootgroup[@name='tools']">
       <item name="fuellog"' count="1" />
  </append>

   <append xpath="/lootcontainers/lootgroup[@name='junk']">
       <item name="fuellog"' count="1" />
   </append>	

</config>
Found it, I think. You have an extra ' after "fuellog".

 
Now im getting error fuellog not found.

Full error log

heres my Items

Code:
<configs>
    <append xpath="/items">

           	<item name="fuelLog">

                   <property name="Meshfile" value="Items/Misc/sackPrefab"/>
                   <property name="DropMeshfile" value="Items/Misc/sack_droppedPrefab"/>
   	               <property name="Material" value="Mwood"/>
                   <property name="HoldType" value="45"/>
	               <property name="Stacknumber" value="50" />
				   	<property name="Weight" value="5"/>
   	               <property name="SellableToTrader" value="true"/>
	               <property name="EconomicValue" value="34"/>
	               <property name="FuelValue" value="580" />
                   <property name="Group" value="Resources,Basics"/>
                   <property name="CraftingSkillGroup" value="craftSkillScience"/>
				   <property name="CraftingIngredientTime" value="0.25"/>


             </item>

	</append>
</configs>
recipes

Code:
<configs>
    <append xpath="/recipes">

               <recipe name="fuelLog" count="1">
                  <ingredient name="resourceWood" count="20"/>
                  <ingredient name="resourceTallow" count="1" />
               </recipe>

	</append>
</configs>
loot

Code:
<config>
   <append xpath="/lootcontainers/lootgroup[@name='tools']">
       <item name="fuellog" count="1" />
  </append>

   <append xpath="/lootcontainers/lootgroup[@name='junk']">
       <item name="fuellog" count="1" />
   </append>	

</config>
Ok i fixed it, i didnt have the 2nd L capitalized

 
Last edited by a moderator:
Now im getting error fuellog not found.
Full error log

heres my Items

Code:
<configs>
    <append xpath="/items">

           	<item name="fuelLog">

                   <property name="Meshfile" value="Items/Misc/sackPrefab"/>
                   <property name="DropMeshfile" value="Items/Misc/sack_droppedPrefab"/>
   	               <property name="Material" value="Mwood"/>
                   <property name="HoldType" value="45"/>
	               <property name="Stacknumber" value="50" />
				   	<property name="Weight" value="5"/>
   	               <property name="SellableToTrader" value="true"/>
	               <property name="EconomicValue" value="34"/>
	               <property name="FuelValue" value="580" />
                   <property name="Group" value="Resources,Basics"/>
                   <property name="CraftingSkillGroup" value="craftSkillScience"/>
				   <property name="CraftingIngredientTime" value="0.25"/>


             </item>

	</append>
</configs>
recipes

Code:
<configs>
    <append xpath="/recipes">

               <recipe name="fuelLog" count="1">
                  <ingredient name="resourceWood" count="20"/>
                  <ingredient name="resourceTallow" count="1" />
               </recipe>

	</append>
</configs>
loot

Code:
<config>
   <append xpath="/lootcontainers/lootgroup[@name='tools']">
       <item name="fuellog" count="1" />
  </append>

   <append xpath="/lootcontainers/lootgroup[@name='junk']">
       <item name="fuellog" count="1" />
   </append>	

</config>
Ok i fixed it, i didnt have the 2nd L capitalized
Case matters. Mind your "L" in log. Make sure it's consistent.

 
ok Im reading it but I just dont get it

can someone show me a way to add an xpath mod that will change this line in items.xml

<!-- jar from cooking food <property name="Create_item" value="drinkJarEmpty"/> -->

to this

<property name="Create_item" value="drinkJarEmpty"/>

 
Here is a snippet that I used to add it to various food types. I originally did it for each recipe individually, but you can chain some 'or' commands in the name section to add them all at once.

<append xpath="/items/item[@name=foodBoiledMeat] /property[@class=Action0]">

<property name="Create_item" value="drinkJarEmpty"/>

</append>

 
Here is a snippet that I used to add it to various food types. I originally did it for each recipe individually, but you can chain some 'or' commands in the name section to add them all at once.

<append xpath="/items/item[@name=foodBoiledMeat] /property[@class=Action0]">

<property name="Create_item" value="drinkJarEmpty"/>

</append>
ok but could you tell me how to do that like I have no clue what Im doing LOL

where do I put that

what file name

and how do I apply it to all items with that line

 
ok but could you tell me how to do that like I have no clue what Im doing LOLwhere do I put that

what file name

and how do I apply it to all items with that line
Be more specific. Where do you want the change?

You'd probably have to use append to add the line of code to the drinks you want the jar back added to.

 
Last edited by a moderator:
Noob question: Are you able to do a simple operation on a value? From everything I've seen has been hard replacements, but no arithmetic examples.

For example:

Code:
Value = 10, want to increase by 20% 

<set xpath="/something/somethingelse/@value">*1.2</set>

Will this result in 12?
 
Noob question: Are you able to do a simple operation on a value? From everything I've seen has been hard replacements, but no arithmetic examples.
For example:

Code:
Value = 10, want to increase by 20% 

<set xpath="/something/somethingelse/@value">*1.2</set>

Will this result in 12?
No sorry, there's no math operation in the current xpath system. xpath is just a method of finding stuff in the XML. The game uses the xpath to make the appropriate changes.

 
Back
Top