0

I have xml that looks like this:

<?xml version="1.0" encoding="utf-8"?>
<Configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Physicals>
    <Physical>
      <Model>6900</Model>
      <DefaultId>19</DefaultId>
      <IDs>
        <DID Size="6x8" ID="19" />
      </IDs>
     </Physical>
  </Physicals>
<\Configuration>

There's repeated Physical tags, within the Physicals tag.

I'm trying to use powershell to match the DefaultID and obtain the size in the DID tag. How can I do that? This is what I have so far.

[xml]$xml = [xml](Get-Content  C:\Users\me\configured.xml)

$Physicals = $xml.SelectNodes('//Physicals/Physical')
foreach($p in $Physicals)
{
   $p.Model
   $id = $p.DefaultId
   if($p.IDs.DID.ID=$id)  #error here
   {
      $p.IDs.DID.Size
   }
}

It has the error The property ID cannot be found on this object. I just don't know how to use xml notation and powershell to match that ID and return the size. There can be multiple id's and sizes listed in that section, but only one matching the default.

I searched online, and what I'm seeing isn't close enough to what I'm doing.

xml and powrshell foreach powershell xml nodes by attribute name

Update:

@mklement pointed out my error in using = instead of -eq (thank you):

if($p.IDs.DID.ID -eq $id)  
{
          $p.IDs.DID.Size
}

Running this, it returns the following:

6900
6x8
dl2100
A4
LETTER
8810
8x36
8x30
8x12
8x10

But I only have one default per Model.

There's a 2100 Model, and that one has two DID's:

  <IDs>
    <DID Size="A4" ID="6" />
    <DID Size="LETTER" ID="8" />
  </IDs>

For that one, the default is 8, so it should return Letter, but it returns both Letter and A4. Any idea why my if isn't working for that?

mklement0
  • 382,024
  • 64
  • 607
  • 775
Michele
  • 3,617
  • 12
  • 47
  • 81
  • 1
    Thanks for updating. `$p.IDs.DID.ID=$id` _assigns_ (`=`) `$id` to `$p.IDs.DID.ID`, and if [member-access enumeration](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_Member-Access_Enumeration) is involved in the nested property access - e.g. if there are _multiple_ `IDs` elements - such an assignment predictably fails. – mklement0 Apr 14 '23 at 17:20

1 Answers1

1

Replace:

if ($p.IDs.DID.ID -eq $id) 
{
  $p.IDs.DID.Size
}

with:

@($p.IDs.DID).Where({ $id -eq $_.ID }).Size

That is, you must filter the $p.IDs.DID elements to find the one element whose .ID attribute value is $id, and then access its .Size attribute.

Note the @(...) around $p.IDs.DID, which ensures the availability of the intrinsic .Where() method even if there's only one <DID> element, to work around a bug in Windows PowerShell (which has since been fixed in PowerShell (Core) 7+).

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • It seems to be working for the cases where there are multiple DID tags for the sizes, but for the case where there's just one DID in the xml, I get this error: Method invocation failed because [System.Xml.XmlElement] does not contain a method named 'Where' – Michele Apr 14 '23 at 20:23
  • 1
    @Michele, you've hit a bug in Windows PowerShell (fixed in PS v7+). The workaround is to use `@($p.IDs.DID)` instead of `$p.IDs.DID` - please see my update. – mklement0 Apr 14 '23 at 23:48