XPATH surgery - Need help with xpath? post here.

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

Previous topic - Next topic

EagleCall

:o  (blinks)  ...Wow, ok.  Lot to process, there.  Many thanks for both the welcome and the help!


That direct patch method is so much easier!  I think for most of these patches that would indeed be all it needs.  And that principle should also apply to other operations like Add, right?  If it can't find the thing or node you are adding to because the mod isn't there, it just fails (silently because of that success line)-- no magically "adding" the full xpath worth of empty stuff or whatever nonsense like that?  :P  Just checking, lol.

I did not catch or at all expect that bit about */Defs being outdated, but it makes so much sense now.  And I was already trying to watch out for outdated information, but stuff like that is so tricky and easily overlooked!  So, that xpath failure combined with the Invert problem just so to make it run anyway, like a direct patch?  Except... hmm... some of the actual Replace xpaths use */Defs, though only two or three and... I think those are actually unnecessary patches?  As in what they are patching in with Replace is what was already there, at least in the current version of the mod it's patching.  ???  So anyway wow this mod has some problems, more even than I originally thought.  I think it was probably an older mod or based on one, or copying old coding examples or something, and was "updated" (cough cough) for the game release.

Hmm, PatchOperationFindMod probably is better for most cases that need the check, although I think in some cases it may actually make sense to test for the things themselves?  IDK, really.  But in such a case, I wonder, would you use <success>Normal</success> on the Test or remove that line entirely?


(Pretends to crack knuckles)  Welp, anyway, looks like I have some work to do.  Thanks again!  ;D

Trunken

Hey Doc,
i'm using patch files to change the labels from traits. This works.
Now here comes my problem, for some reason the description part changes too from german to english, even though i dont touch it at all :o

Whats going on? Is there any possible reason for this? I dont know to proceed and need your help

here is the code:

<Patch>
  <Operation Class="PatchOperationReplace">
    <xpath>/Defs/TraitDef[defName="TRAITNAME"]/degreeDatas/li/label</xpath>
    <value>
        <label>TEXT</label>
    </value>
  </Operation>
</Patch>

for a workaround, i added this lines to change description too,
but its not working...

Example for Slowpoke:

  <Operation Class="PatchOperationReplace">
    <xpath>/Defs/TraitDef[defName="SpeedOffset"]/degreeDatas/li[label="slowpoke"]/description</xpath>
    <value>
    <description>TEXTTEXTTEXT</description>
    </value>
  </Operation>

Where is my mistake?

Error Log:

[New_Mod] Patch operation Verse.PatchOperationReplace(/Defs/TraitDef[defName="SpeedOffset"]/degreeDatas/li[label="slowpoke"]/description) failed
file: C:\Steam\steamapps\common\RimWorld\Mods\New_Mod\Patches\Core_SpectrumPatch.xml
Verse.Log:Error(String, Boolean)
Verse.PatchOperation:Complete(String)
Verse.LoadedModManager:ClearCachedPatches()

please help me

LWM

#152
Another xpath question:

Are "Parent" xml nodes added to defs before patching happens, or after?

That is, can I patch a thingDef's thingCategories if the thingCategories are defined in a different def with Abstract="true"?

If I can't, is there an easy way to ensure compatibility with other mods?

For example, if I want it to have thingCategory A, and someone else wants it to also have thingCategory B, but we neither of us want it to have its original category, can we both just add

  <!-- Patch Operation Add, correct xpath, etc-->
  <value>
    <thingCategories Inherit="false">
      <li>A</li>
    </thingCategories>
  </value>

Or will we step on each others' feet?  Has anyone done this?  EDIT: They step on each others' feet.

EDIT2: The example on the wiki here https://rimworldwiki.com/wiki/Modding_Tutorials/PatchOperations#PatchOperationConditional looks like EXACTLY this case.

So, original question: do Abstracts get loaded into defs before patching happens?

--LWM

jptrrs

#153
Ok, so here's a though nut to crack.
I'm trying to use xml patch to remove some defs added by Fluffy's Stuffed Floors. He uses custom defs, like this one:

    <StuffedFloors.FloorTypeDef ParentName="StuffedFloorsWoodBasicBase">
    <defName>StuffedWoodFloorRoughHorizontal</defName>
    <label>rough horizontal planks</label>
    <description>A rough plank flooring.</description>
        <texturePath>Floors/Wood/WoodFloor2</texturePath>
        <obsoletes>
            <li>FloorWood1</li>
        </obsoletes>
    </StuffedFloors.FloorTypeDef>


I want to track and remove just some of them, but for the sake of clarity let's say I need all them gone. So I tried this, and it didn't work:

    <Operation Class="PatchOperationRemove">
        <xpath>/Defs/StuffedFloors.FloorTypeDef</xpath>
    </Operation>


also this:
    <Operation Class="PatchOperationRemove">
        <xpath>//StuffedFloors.FloorTypeDef</xpath>
    </Operation>


I figured RW could be hiding this custom defs somewhere, so I've been researching alternate methods to look for a xml node. I tried this as well, and it floped too:

<Operation Class="PatchOperationRemove">
<xpath>//[contains(local-name(),'StuffedFloors.FloorTypeDef')]</xpath>
</Operation>


Any thoughts?

LWM

Well, I would think it would work.

Are you getting any errors?


jptrrs

#155
That's what's wierd, I get SOME errors. Allow me explain the way his code works:
Those custom defs are used to generate some regular TerrainDefs based on what materials are in use. Say there's mod-created stone def, basalt for instance. It would be recognized as a new building material for a tiled stone floor, so Stuffed Floors would use his custom def as a base to generate a basalt stone floor. So, with those patches I wrote, the errors I get are saying things like: "basalt stone floor has no fertility rating", showing that info was really suppressed somehow. But the button to build the basalt stone floor remains active, and it can be built. Whereas if instead of trying to patch that def I simply delete it from the mod's xml files, that type of floor does vanish from the game. My conclusion is that there must be something wrong with my patch!

NinjaSiren

An xpath question,
Can PatchOperationFindMod be ok and not show errors, when the mod to find is disabled or not-installed, and without using C#/Assembly codes?

I am the current modder for Yes, Vehicles and there's a guy that keeps pushing me to try running the game where there will be automated mod compatibility using xpath and XML xpath only with or without the mod installed or enabled.

Link of the Combat Extended patch
[v0.83.4] [v1.0] Yes, Vehicles, Finally! - A somewhat* new way to travel the planet!

jptrrs

Quote from: NinjaSiren on August 17, 2019, 07:29:09 AM
An xpath question,
Can PatchOperationFindMod be ok and not show errors, when the mod to find is disabled or not-installed, and without using C#/Assembly codes?

I am the current modder for Yes, Vehicles and there's a guy that keeps pushing me to try running the game where there will be automated mod compatibility using xpath and XML xpath only with or without the mod installed or enabled.

Link of the Combat Extended patch

Yes. Lots of mods do that.

Vakari

#158
I'm leaving this post in case anyone else ever runs into this error.  Maybe it can help with debugging.  In addition, if anyone knows a more elegant way to combine both "<graphicData>" changes into one element, please let me know.  Anyway, I was able to figure this out for myself.  Here is what worked:

<?xml version="1.0" encoding="utf-8" ?>
<Patch>
   <Operation Class="PatchOperationReplace">
      <xpath>/Defs/ThingDef[defName="MineableUranium"]/graphicData/color</xpath>
      <value>
         <color>(255,249,105)</color>
      </value>
   </Operation>
   <Operation Class="PatchOperationReplace">
      <xpath>/Defs/ThingDef[defName="MineableUranium"]/graphicData/colorTwo</xpath>
      <value>
         <colorTwo>(240,178,17)</colorTwo>
      </value>
   </Operation>
</Patch>




First of all:  Thank you to the author of this post and everyone helping.  For a noob like myself, it's invaluable.

So, I'm trying to learn xpathing, and so I've read tons of articles, other posts, wikis, and looked at actual downloaded mods.  I think I've actually confused myself by information overload.

So, I thought I'd start small and just try a simple replace operation.  I want to change "color" and "colorTwo" values for the mineable uranium ore.

Everything I've tried causes errors.  I am sure there is a way to list both values in the same operation, but I can't make it work.  I've even tried separating each (color vs colorTwo) into separate operations.  I still get errors.  Would some generous soul please help me out?

EDIT:  The file with the change is:  Defs\ThingDefs_Buildings\Buildings_Natural.xml.

Again, thank you for any help!

Here is what I've tried last:


<?xml version="1.0" encoding="utf-8" ?>
<Patch>
   <Operation Class="PatchOperationReplace">
      <xpath>*/ThingDef/[defName = "MineableUranium"]/graphicData/color</xpath>
      <value>
            <color>(255,255,64)</color>
      </value>
   </Operation>
   
      <Operation Class="PatchOperationReplace">
      <xpath>*/ThingDef/[defName = "MineableUranium"]/graphicData/colorTwo</xpath>
      <value>
            <colorTwo>(240,178,17)</colorTwo>   
      </value>
   </Operation>
</Patch>


Here is the error log.  I've tried googling this but couldn't figure out what is wrong:

Error in patch.Apply(): System.Xml.XPath.XPathException: Error during parse of */ThingDef/[defName = "MineableUranium"]/graphicData/color ---> Mono.Xml.XPath.yyParser.yyException: irrecoverable syntax error
  at Mono.Xml.XPath.XPathParser.yyparse (yyInput yyLex) [0x00000] in <filename unknown>:0
  at Mono.Xml.XPath.XPathParser.Compile (System.String xpath) [0x00000] in <filename unknown>:0
  --- End of inner exception stack trace ---
  at Mono.Xml.XPath.XPathParser.Compile (System.String xpath) [0x00000] in <filename unknown>:0
  at System.Xml.XPath.XPathExpression.Compile (System.String xpath, IXmlNamespaceResolver nsmgr, IStaticXsltContext ctx) [0x00000] in <filename unknown>:0
  at System.Xml.XPath.XPathExpression.Compile (System.String xpath) [0x00000] in <filename unknown>:0
  at System.Xml.XPath.XPathNavigator.Compile (System.String xpath) [0x00000] in <filename unknown>:0
  at System.Xml.XmlNode.SelectNodes (System.String xpath, System.Xml.XmlNamespaceManager nsmgr) [0x00000] in <filename unknown>:0
  at System.Xml.XmlNode.SelectNodes (System.String xpath) [0x00000] in <filename unknown>:0
  at Verse.PatchOperationReplace.ApplyWorker (System.Xml.XmlDocument xml) [0x00000] in <filename unknown>:0
  at Verse.PatchOperation.Apply (System.Xml.XmlDocument xml) [0x00000] in <filename unknown>:0
  at Verse.LoadedModManager.ApplyPatches (System.Xml.XmlDocument xmlDoc, System.Collections.Generic.Dictionary`2 assetlookup) [0x00000] in <filename unknown>:0
Verse.Log:Error(String, Boolean)
Verse.LoadedModManager:ApplyPatches(XmlDocument, Dictionary`2)
Verse.LoadedModManager:LoadAllActiveMods()
Verse.PlayDataLoader:DoPlayLoad()
Verse.PlayDataLoader:LoadAllPlayData(Boolean)
Verse.Root:<Start>m__1()
Verse.LongEventHandler:RunEventFromAnotherThread(Action)
Verse.LongEventHandler:<UpdateCurrentAsynchronousEvent>m__1()


Thank you in advance for any assistance with my learning this process!