Home > Software design >  How to read attribute values from XML nodes with Powershell
How to read attribute values from XML nodes with Powershell

Time:03-16

I'm currently trying to get a Powershell script to extract information from an XML file and I've been trying a few different things like Select-Xml and SelectNodes, but I'm struggling. The information is in a format like this:

<school>
   <students>
      <student name="Bob" subject="Math" year="5">
         <details SID="38571273" code="1122" group="" />
      </student>
        
      <student name="John" subject="Science" year="5">
         <details SID="38343555" code="1123" group="" />
      </student>
   </students>
</school>

I want to extract information like the name, subject, year, SID, code, and group and store it in an array for each student so I can process it. I'm writing a Powershell script to do this, but I'm quite new to it, as well as XML. Any help would be greatly appreciated!

CodePudding user response:

For simple tasks like this one, you can access the XML items with dot notation, i.e. $xml.school.students.student will give an array of <student> elements.

After that, you can use select (aka Select-Object) to pick out certain properties. Either direct properties by name, or name/expression pairs (@{name='...', expression={...}} for more complex ones, or if you want to rename the result "columns":

$xml.school.students.student | select name,subject,year,@{n='SID'; e={$_.details.SID}}

gives an array of PSCustomObjects:

name subject year SID     
---- ------- ---- ---     
Bob  Math    5    38571273
John Science 5    38343555

CodePudding user response:

With the updated XML I revised my answer -

I think this is what you're looking for. You would just have to update the path to your xml.

$XMLPath = "ENTER_PATH"
function Get-StudentInfo {
    param (
        $xPATH,
        $title)
    Select-Xml -Path $XMLPath -XPath "/school/students/$xPATH" | ForEach-Object { $_.Node.$title }
}

$students = [PSCustomObject]@{
    Names    = Get-StudentInfo -xPath "student" -title "name"
    Subjects = Get-StudentInfo -xPath "student" -title "subject"
    Years    = Get-StudentInfo -xPath "student" -title "year"
    SIDs     = Get-StudentInfo -xPath "student/details" -title "SID"
    Codes    = Get-StudentInfo -xPath "student/details" -title "code"
    Groups   = Get-StudentInfo -xPath "student/details" -title "group"
}

$students.Names


From there you would have an object $students that has properties with an array for each property.

Names    : {Bob, John}
Subjects : {Math, Science}
Years    : {5, 5}
SIDs     : {38343555, 38343555}
Codes    : {1123, 1123}
Groups   : {, }

To get a list of all the students names you would use $students.names or for subject $students.subjects


A version that loads the XML file only once, instead of once per call to Get-StudentInfo:

$students = Select-Xml -Path "test.xml" -XPath '/school/students/student' | Select-Object @(
    @{name='Name';    expr={ $_ | Select-Xml '@name' }}
    @{name='Subject'; expr={ $_ | Select-Xml '@subject' }}
    @{name='Year';    expr={ $_ | Select-Xml '@year' }}
    @{name='SID';     expr={ $_ | Select-Xml 'details/@SID' }}
    @{name='Code';    expr={ $_ | Select-Xml 'details/@code' }}
    @{name='Group';   expr={ $_ | Select-Xml 'details/@group' }}
)
$students

result

Name Subject Year SID      Code Group
---- ------- ---- ---      ---- -----
Bob  Math    5    38571273 1122      
John Science 5    38343555 1123 
  • Related