Struggling a bit with two LINQ statements here. Basically I would like to convert the following two XML files into dictionaries (type-detail to follow). Here are snapshots of the XMLs:
Offset XML:
<Offsets>
<PlayerStructBase>0xF24C10</PlayerStructBase>
<HP>
<offset>0x17e8</offset>
</HP>
<MaxHP>
<offset>0x17ec</offset>
</MaxHP>
</Offsets>
Desired output: Dictionary<string, IntPtr>
. I have a method called GetPointerFromBaseOffsets(int[] offsets) that returns the IntPtr from a int array with offsets (example: 0x1234, 0x17e2
).
Skills XML:
<Skills>
<Potion>
<Cast>0.00</Cast>
<ReCast>60.00</ReCast>
<MPCost>0</MPCost>
</Potion>
<Ruin>
<Cast>2.49</Cast>
<ReCast>2.49</ReCast>
<MPCost>9</MPCost>
</Ruin>
</Skills>
Desired output: Dictionary<string, Skill>
. Skill is a class with properties Cast, ReCast and MpCost among other things.
These are my attempts:
Offset XML to Dictionary
OffsetDictionary =
XDocument.Load(folderPath+@"\offsets.xml")
.XPathSelectElements("/Offsets/*[offset]")
.ToDictionary(o => o.Name.LocalName,
o => MemoryManager.GetPointerFromBaseOffsets(Enumerable.Cast<int>(o.Elements()).ToArray()));
Skills XML to Dictionary
SkillDictionary =
XDocument.Load(folderPath + @"\skills.xml")
.XPathSelectElements("/Skills/*")
.ToDictionary(e => e.Name.LocalName, e => new Skill(e.Name.LocalName, (double)e.Element("Cast"), (double)e.Element("ReCast"), (int)e.Element("MPCost")));
Question: On the attempt at creating the Offset dictionary I get my first error-message (run-time), that it cannot be Cast. Could someone show me how to write these two blocks?
Thanks!
Enumerable.Cast
doesn't perform custom conversions, which is what you want. You need to cast directly - but that's pretty simple:
OffsetDictionary =
XDocument.Load(folderPath+@"\offsets.xml")
.XPathSelectElements("/Offsets/*[offset]")
.ToDictionary(o => o.Name.LocalName,
o => MemoryManager.GetPointerFromBaseOffsets(o.Elements()
.Select(x => (int) x)
.ToArray()));
However, that assumes that your offsets are actually just plain decimal integers. In your case, they're not - they're in hex. You'll need to do a bit more work to parse those, e.g.
.Select(x => int.Parse(x.Value.Substring(2), NumberStyles.AllowHexSpecifier))
Alternatively, change your XML format so that the values are in decimal.
I'm not sure about your XPath expression though... I'm not an XPath expert by any means, but don't you just want all the elements directly beneath the root element? If so, you can just use
.Root.Elements()
instead of your XPathSelectElements
call.
See more on this question at Stackoverflow