Powershell & XML: How to count specific elements for each node

Tostito80 picture Tostito80 · Aug 29, 2014 · Viewed 10.8k times · Source

Here is another one for my server for the PC Game - Space Engineers. The answer to this seems like it should be simple but it has me stuck as i can not find the right way to call this information.

What I would like to do is get the count of how many times a specific element appears in each node. I have this partially working but not exactly what I want.

Here is what I have so far:

An excerpt from the XML (nodes folded except for target node)

<MyObjectBuilder_Sector xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <Position>
  <SectorEvents>
  <AppVersion>
  <SectorObjects>
     <MyObjectBuilder_EntityBase xsi:type="MyObjectBuilder_CubeGrid">
        <CubeBlocks>
           <MyObjectBuilder_CubeBlock xsi:type="MyObjectBuilder_Reactor">
           <MyObjectBuilder_CubeBlock xsi:type="MyObjectBuilder_Thrust">
           <MyObjectBuilder_CubeBlock xsi:type="MyObjectBuilder_Drill">
           <MyObjectBuilder_CubeBlock xsi:type="MyObjectBuilder_Drill">
              <SubtypeName>SmallBlockDrill</SubtypeName>
              <EntityId>72280681079646079</EntityId>
              <Min x="1" y="1" z="-7" />
              <BlockOrientation Forward="Forward" Up="Left" />
              <ColorMaskHSV x="0" y="-1" z="0" />
              <Owner>144256542526969420</Owner>
              <ShareMode>None</ShareMode>
              <ShowOnHUD>false</ShowOnHUD>
              <Enabled>false</Enabled>
              <Inventory>
                <Items />
                <nextItemId>0</nextItemId>
              </Inventory>
           </MyObjectBuilder_CubeBlock>

and my powershell code that gives me back the number of cube blocks per

<MyObjectBuilder_EntityBase xsi:type="MyObjectBuilder_CubeGrid">

cube grid.

$filePath = 'F:\DedicatedServer\DataDir\SE Survival 2\Saves\VPS RC 1\SANDBOX_0_0_0_.sbs'
[xml]$myXML = Get-Content $filePath
$ns = New-Object System.Xml.XmlNamespaceManager($myXML.NameTable)
$ns.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance")

$infos = $myXML.SelectNodes("//SectorObjects/MyObjectBuilder_EntityBase[(@xsi:type='MyObjectBuilder_CubeGrid')]" ,$ns)

foreach ($info in $infos ){

        $info.CubeBlocks.MyObjectBuilder_CubeBlock.count 
}

So I am trying to get this to feed back the number of small drills per cube grid. seen here in the XML

<MyObjectBuilder_CubeBlock xsi:type="MyObjectBuilder_Drill">
      <SubtypeName>SmallBlockDrill</SubtypeName>

I feel Like this is close to solved but its returning the same number for every cube grid so that can not be correct.

$info = $info.SelectNodes("//CubeBlocks/MyObjectBuilder_CubeBlock[(@xsi:type='MyObjectBuilder_Drill')]/SubtypeName['SmallBlockDrill']" ,$ns).InnerText
$info.count

Results below. I believe this is the total number of both large and small drills in the world just repeating for every grid it finds. feels close but i'm betting the subtype value selection is not working as I want it to.

490
490
490
490
490
490
490
490

Answer

har07 picture har07 · Aug 29, 2014

Add a dot (.) at the beginning of your XPath to make it recognized as relative to current $info :

foreach ($info in $infos ){
    $info.SelectNodes("./CubeBlocks/MyObjectBuilder_CubeBlock[(@xsi:type='MyObjectBuilder_Drill')]/SubtypeName['SmallBlockDrill']" ,$ns).count
}