XPATH surgery - Need help with xpath? post here.

Started by skullywag, June 02, 2017, 04:26:23 AM

Previous topic - Next topic

TeflonJim

Quote from: tcjaime on July 23, 2018, 09:17:32 AM
Help!  I'm new to patching and I'm stuck. Can someone tell me why this is changing all the power consumptions (ex wind gen) to 5 instead of just the lamp? Thank you!
You need to make a comparison inside your expression or it'll always evaluate to true.
<xpath>/Defs/ThingDef[defName="StandingLampBase"]/comps/li["CompProperties_Power"]/basePowerConsumption</xpath>
You'll need something similar for CompProperties_Power, but I don't have rimworld on this computer to check exactly what that should be.

tcjaime

#106
Fixed!  Thank you all. 

Here's the correct version:

<?xml version="1.0" encoding="utf-8" ?>
<Patch>
   <Operation Class="PatchOperationReplace">
   <xpath>*/ThingDef[@Name="StandingLampBase"]/comps/li[@Class="CompProperties_Power"]/basePowerConsumption</xpath>
      <value><basePowerConsumption>5</basePowerConsumption></value>
   </Operation>
</Patch>

Boartato

#107
<?xml version="1.0" encoding="utf-8" ?>

<Patch>
<Operation Class="PatchOperationReplace">
<xpath>Defs/RecipeDef[defName="CookMealBase"]/workSkill</xpath>
<value>
<workSkill>Intellectual</workSkill>
</value>
</Operation>
</Patch>


Is there some semantics related to abstract classes that's needed for xpath? Changing only CookMealBase to CookMealSimple I can edit things like the labels, but if I try to do it on CookMealBase it errors continually.

https://rimworldwiki.com/wiki/Modding_Tutorials/XML_file_structure

This tutorial seems to suggest that abstract classes cease to exist after loading, and I seem to remember relatively recently that Xpathing happens after loading now instead of before. Would that mean that instead of being able to Xpath an abstract, I will have to xpath each file that inherits the abstract instead?
There are many mods like it, but this mod is mine.

Haplo

Ok, I have a strange problem here.
Can somebody tell me why this patch works for 'Bow_' but not for 'Gun_'?


<!-- Check if <comps /> exists. If not, add it -->
<Operation Class="PatchOperationSequence">
<success>Always</success>
<operations>
<li Class="PatchOperationTest">
<xpath>*/ThingDef[starts-with(defName, 'Gun_')]/comps</xpath>
<success>Invert</success>
</li>
<li Class="PatchOperationAdd">
<xpath>*/ThingDef[starts-with(defName, 'Gun_')]</xpath>
<value>
<comps />
</value>
</li>
</operations>
</Operation>

<!-- Find entries and add the new comp -->
<Operation Class="PatchOperationAdd">
<xpath>*/ThingDef[starts-with(defName, 'Gun_')]/comps</xpath>
<value>
<li Class="WeaponRepair.CompProperties_WeaponRepairTwo2One">
<worktableDefs>
<li>TableMachining</li>
</worktableDefs>
<allowedDefSubName>Gun_</allowedDefSubName>
<compareQuality>false</compareQuality>
<jobDef>WeaponRepairTwo2One</jobDef>
<workTypeDef>Smithing</workTypeDef>
<maxRepair>0.95</maxRepair>
</li>
</value>
</Operation>

Boartato

#109
After hours of racking my brains, googling and testing:

I can modify workSkill in CookMealSimple
I cannot modify workSkill in CookMealBase (abstract limitation maybe...?)
I cannot modify defaultIngredientFilter in CookMealSimple.

Edit: Found my answer. My tutorials were wrong or I misread them, xpath is not applied after inheritance at all. I still can't modify abstract classes, but the reason why trying to add to the defaultIngredientFilter was failing is because it didn't exist yet (not yet inherited from parent). However if I create one in the CookMealSimple, it adds anything in its filter to the one it inherits from base, so I'll take it. Still feels hacky needing to do it to every meal individually, but eh.
There are many mods like it, but this mod is mine.

Mehni

@Haplo -- Don't know how it is in 1.0 but at least in B18 PatchOperationSequences were limited to one XML-file, for some reason unknown to me. All Defs starting with Bow_ reside in one file, whereas the Gun_ is spread out over four. Maybe target the parent instead? Read on:

@Boartato -- tcjaime had the exact same issue one page ago and posted the solution on this page. If you want to target by attribute, such as Name="StandingLampBase", you use @Name="StandingLampBase". The @ is one of the many special symbols in xpath; in this case it targets attributes. * would be a wildcard. See also https://gist.github.com/Zhentar/4a1b71cea45b9337f70b30a21d868782#patching-abstracts

Haplo

Thanks for the info. That might be the reason. Strange as it is...
I've now added it to the weapon base for the Gun_ part and there it works :)

Boartato

Quote from: Mehni on July 25, 2018, 02:45:14 AM
@Haplo -- Don't know how it is in 1.0 but at least in B18 PatchOperationSequences were limited to one XML-file, for some reason unknown to me. All Defs starting with Bow_ reside in one file, whereas the Gun_ is spread out over four. Maybe target the parent instead? Read on:

@Boartato -- tcjaime had the exact same issue one page ago and posted the solution on this page. If you want to target by attribute, such as Name="StandingLampBase", you use @Name="StandingLampBase". The @ is one of the many special symbols in xpath; in this case it targets attributes. * would be a wildcard. See also https://gist.github.com/Zhentar/4a1b71cea45b9337f70b30a21d868782#patching-abstracts

Thanks! I actually ran across that naming convention, but didn't realize why it was being used. That link in particular is awesome, I don't know how I haven't found it but that'll be very useful! And I'll remember haplo's lesson as well :)
There are many mods like it, but this mod is mine.

Chehalden

I am trying to make a small change to the standing lamp but the section I need to change doesn't appear to have any easy unique identifiers (no defname)

This is the section I am trying to make a change to, the <basePowerConsumption> specifically.
  <ThingDef Abstract="True" Name="StandingLampBase" ParentName="LampBase">
    <graphicData>
      <texPath>Things/Building/Furniture/LampStanding</texPath>
    </graphicData>
    <costList>
      <Steel>20</Steel>
    </costList>
    <statBases>
      <Mass>4</Mass>
    </statBases>
    <comps>
      <li Class="CompProperties_Power">
        <compClass>CompPowerTrader</compClass>
        <basePowerConsumption>75</basePowerConsumption>
      </li>
    </comps>
  </ThingDef>


I cannot for the life of me figure out how to specifically target this section based on the <ThingDef> for this. There is <defName> in this section, it is in another child section. This section is also a child of another.

This has been my latest attempt hoping i could get into the right section

<Operation Class="PatchOperationReplace">
   <xpath>/Defs/ThingDefs_Buildings[texPath = "Things/Building/Furniture/LampStanding"]/comps</xpath>
     <value>
      <li Class="CompProperties_Power">
        <compClass>CompPowerTrader</compClass>
        <basePowerConsumption>30</basePowerConsumption>
      </li>
     </value>
   </Operation>
   


I have a feeling there is something simple I am missing as I am new to XPATH stuff. I was able to use the patch method before when I was working on an animal, but that one had a clear easy defName to work off of.

Any help would be greatly appreciated

AileTheAlien

#114
You can target other stuff besides just what tag to look for, like attributes on the tag, child tags, siblings, etc. (You'll probably want to read some tutorials on this stuff; It helped me out a lot!) For your specific case, I believe this would work (unless I made a typo :P ):

<?xml version="1.0" encoding="utf-8"?>
<Patch>
    <Operation Class="PatchOperationReplace">
        <xpath>/Defs/ThingDef[@Name="StandingLampBase"]/comps/li[@Class="CompProperties_Power"]/basePowerConsumption</xpath>
        <value>
            <basePowerConsumption>30</basePowerConsumption>
        </value>
    </Operation>
</Patch>


Note that your method of looking for a thing that has a graphicData tag (you missed this part), which has a texPath tag, which has a specific value, could also work; It's just a bit more complicated than you need in this case. (Although, that type of patch is definitely useful; I had to do something weird like that, plus or minus child / grandparent / whatever tags, although I cannot for the life of me, remember which of my mods it was in...)

Chehalden

@AileTheAlien -- Awesome it is working perfectly! Thank you for showing me how to use @attributes correctly. That really simplifies what I was trying to do.

dninemfive

How can I target specific list items by the value they hold? I'm trying to remove the tag <li>Western</li> from other tags. I know I could just overwrite the tags, but I want to avoid potential mod compatibility issues.

the relevant code is as follows:


<tags>
    <li>Industrial</li>
    <li>Western</li>
    <li/> <!-- &c. -->
</tags>


And the patch I've tried is as follows:


<Operation Class="PatchOperationRemove">
   <xpath>*/<correct path>/tags/li[*="Western"]</xpath>
</Operation>


(Note that any syntax errors in this example code are not present in mine; the file loads properly and I've confirmed that the path is correct.)

I've also tried replacing the '*' in my code with a '.', something I saw somewhere in some xpath tutorial, but that doesn't work either.

AileTheAlien

You want to use text(), so the last part would be li[text()='Western']

dninemfive


Dr_Zhivago

#119
Edit: Got help from the Discord