XPATH surgery - Need help with xpath? post here.

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

Previous topic - Next topic

kaptain_kavern

Hey, you're welcome. More importantly, have you understand why it wasn't working?

It's dumb as hell but when I'm writing a xpath patch I always copy paste tag names from the actual vanilla file I intend to patch/modify to be sure of my path. In order to avoid head-scratching sessions ... And even that way I always end up missing the obvious ^^

Have fun patching everything now :p

Sixdd

I have another probably obvious problem. I've been trying to figure this one out for a day now and no luck no matter what I try.
<Patch>

  <Operation Class="PatchOperationSequence">
    <!-- <success>Always</success> -->
    <Operations>
      <li Class="PatchOperationTest">
        <xpath>*/ThingDef[defName="Cinnabar"]</xpath>
      </li>
      <li Class="PatchOperationAdd">
        <xpath>RecipeDefs</xpath>
        <value>
          <RecipeDef ParentName="DrillMetalRecipeBase">
          <defName>DrillCinnabar</defName>
          <label>Extract Cinnabar</label>
          <workAmount>7200</workAmount>
            <products>
              <IndustrialPDA>1</IndustrialPDA>
              <Cinnabar>10</Cinnabar>
            </products>
          </RecipeDef>
        </value>
      </li>
    </Operations>
  </Operation>

</Patch>



When I try this I get an error but I feel like I've tried a dozen different ways to go about it and nothing has worked so far. The Parent is in the same mod so I thought I could reference it without issue. Any help is appreciated.

~Six

skullywag

im not sure what that xpath is supposed to be doing? that will add everything in value to all RecipeDefs, or fail miserably. Im sure thats not what youre trying to do. Xpath has to be the fullpath each time if that helps.
Skullywag modded to death.
I'd never met an iterator I liked....until Zhentar saved me.
Why Unity5, WHY do you forsake me?

Sixdd

Basically what I was trying to do is add a recipe if the condition is met. But yeah failed miserably is more like it.

skullywag

I think its just you second xpath on the add. It needs to be a fully qualified xpath. Ill have a proper look later on (not at my pc) but check the xpath help thread here. Zorba put a sequence example up. May hold a clue.
Skullywag modded to death.
I'd never met an iterator I liked....until Zhentar saved me.
Why Unity5, WHY do you forsake me?

Sixdd

Yeah I think I can fix it by defining empty recipes in the mods main recipe file and just replace them, that should work. I'm taking a break right now, eyes were bugging out, but I'll let you all know the outcome.

JT

[Never mind.  There was a stray E.  Sigh. =P]

JT

For reasons which I assume are similar to the stuff in Antaios' post, I'm having trouble getting a check-for-other-mod-and-then-edit-my-own-mod patch to work.

Here goes:


<Operation Class="PatchOperationSequence">
<!-- If Combat Extended is installed, add Combat Extended items to the Security Contractor -->
<operations>
<li Class="PatchOperationTest">
<xpath>/Defs/ThingDef[@Class="CombatExtended.AmmoDef"]</xpath>
</li>
<li Class="PatchOperationAdd">
<xpath>/Defs/TraderKindDef[defName="JTTraderKindSecurityContractor"]/stockGenerators</xpath>
<value>
<li Class="StockGenerator_Tag">
<tradeTag>CE_Ammo</tradeTag>
<thingDefCountRange>
<min>2</min>
<max>5</max>
</thingDefCountRange>
<price>Cheap</price>
<totalPriceRange>
<min>200</min>
<max>700</max>
</totalPriceRange>
</li>
<li Class="StockGenerator_SingleDef">
<thingDef>Ammo_303British_FMJ</thingDef>
<totalPriceRange>
<min>110</min>
<max>170</max>
</totalPriceRange>
</li>
<li Class="StockGenerator_SingleDef">
<thingDef>Ammo_45ACP_FMJ</thingDef>
<totalPriceRange>
<min>70</min>
<max>130</max>
</totalPriceRange>
</li>
</value>
</li>
</operations>
</Operation>


This purportedly searches for any XML item that derives from a Combat Extended class and if it finds one, we know that Combat Extended is installed and can proceed to add appropriate items to our trader.

However, it fails.  Without debugging messages to be able to identify where specifically it is failing, I wasn't able to rule out what was happening.

Until I tried separating the operations out of the sequence entirely...


<Operation Class="PatchOperationTest">
<xpath>/Defs/ThingDef[@Class="CombatExtended.AmmoDef"]</xpath>
</Operation>
<Operation Class="PatchOperationAdd">
<xpath>/Defs/TraderKindDef[defName="JTTraderKindSecurityContractor"]/stockGenerators</xpath>
<value>
<li Class="StockGenerator_Tag">
<tradeTag>CE_Ammo</tradeTag>
<thingDefCountRange>
<min>2</min>
<max>5</max>
</thingDefCountRange>
<price>Cheap</price>
<totalPriceRange>
<min>200</min>
<max>700</max>
</totalPriceRange>
</li>
<li Class="StockGenerator_SingleDef">
<thingDef>Ammo_303British_FMJ</thingDef>
<totalPriceRange>
<min>110</min>
<max>170</max>
</totalPriceRange>
</li>
<li Class="StockGenerator_SingleDef">
<thingDef>Ammo_45ACP_FMJ</thingDef>
<totalPriceRange>
<min>70</min>
<max>130</max>
</totalPriceRange>
</li>
</value>
</Operation>


...which succeeds with absolutely no errors, but obviously means that the Security Contractor receives the items even when Combat Extended is not installed (which of course would produce def errors in a game running without it once the defs are instantiated).

This has me completely perplexed: how is it possible that the sequence can fail when performing the two operations, when those exact same operations will succeed independently?

skullywag

#38
Does it require a <success>Always</success> inside the PatchOperationSequence

NIA spotted the issue, you are testing per MOD the patching system works per xml FILE. You cannot test per file for the ammodef and then patch the stockgenerator as no file contains both.
Skullywag modded to death.
I'd never met an iterator I liked....until Zhentar saved me.
Why Unity5, WHY do you forsake me?

JT

Hm.  Well, then I'm proper screwed. =P

Combat Extended, ironically, includes an extension PatchOperation which checks to see if another mod is loaded.  This, of course, requires Combat Extended to use. ;-)

skullywag

Copy it into yours, that method didnt originate there, others are using it.
Skullywag modded to death.
I'd never met an iterator I liked....until Zhentar saved me.
Why Unity5, WHY do you forsake me?

JT

I was actually hoping to keep this mod XML-only.  After all, if I had an assembly I wouldn't even need the patching operations, since I'd have direct access to the definitions at runtime when I could guarantee their mutability.

I'll throw up a feature request if there isn't one already.  If others are using it, it's clearly a popular enough requirement that it should be there in the spec.  I don't hold anything against it, the patching feature is young. =)

skullywag

I think (Not 100%) that Zorba will be adding a "does mod exist" patch operation for next release. Dont quote me on that but hes been talking to us modders about it all on the modding discord so he is very aware of the issue.
Skullywag modded to death.
I'd never met an iterator I liked....until Zhentar saved me.
Why Unity5, WHY do you forsake me?

Tamias

Hey guys, modding noob here with a couple of xpath questions that may or may not be related.

1. I know that standard procedure now is to start off an xpath patch with either "/" or "*/", and to avoid using "//" altogether. However, are there any valid instances to use "//" ever in Rimworld modding applications? I know that it searches every possible node, but wouldn't there be some limited situations where that function is useful?

2. Is it possible, through xpath patching, to simply replace all instances of "X" with "Y" (like a "replace all" function)? Or even remove all instances of "X" altogether, no matter where it is? For example, lets say you wanted to create a compatability patch between two mods, and you need to either remove or change all instances of a particular weapon or apparel tag for all factions. Instead of searching for every single instance of tag X throughout the two mods, and writing an individual "replace" or "remove" patch for each one, would it be possible to write a single patch that searches for all instances of that tag no matter where it is, and performs the desired operation? This is just an example, but there have been several situations where this thought has occured to me.

skullywag

The only time to use // is if you DO NOT KNOW THE STRUCTURE OF THE XML, which we always do in Rimworld land. So no never use that. :)

xpath is run PER FILE, thats the key here, ive seen people trying to run tests looking in 1 file to change something in another, that will not work. You can literally say "if that thing exists in this file, than change it to this other thing" but its getting the selector in the xpath robust enough to not grab something it shouldnt thats the issue. It really depends on what you are trying to do here.
Skullywag modded to death.
I'd never met an iterator I liked....until Zhentar saved me.
Why Unity5, WHY do you forsake me?