Convert XML to PSObject

Viewed 52218

Note: I'm using ConvertTo-XML and cannot use Export-Clixml:

I create a simple PSObject:

$a = New-Object PSObject -Property @{
    Name='New'
    Server = $null
    Database = $null
    UserName = $null
    Password = $null
}

I then convert it into XML using ConvertTo-XML:

$b = $a | Convertto-XML -NoTypeInformation

The XML looks like this:

<?xml version="1.0"?>
<Objects>
  <Object>
    <Property Name="Password" />
    <Property Name="Name">New</Property>
    <Property Name="Server" />
    <Property Name="UserName" />
    <Property Name="Database" />
  </Object>
</Objects>

I'm having trouble figuring out the dot notation or XPath query to extract the attributes/elements and convert $b back to the original PSObject.

3 Answers

I usually parse xml to hash tables but using the convertto function I grabbed from here I adapted the function to convert to pscustom objects

function xmlNodeToPsCustomObject ($node){
    $hash = @{}
    foreach($attribute in $node.attributes){
        $hash.$($attribute.name) = $attribute.Value
    }
    $childNodesList = ($node.childnodes | ?{$_ -ne $null}).LocalName
    foreach($childnode in ($node.childnodes | ?{$_ -ne $null})){
        if(($childNodesList | ?{$_ -eq $childnode.LocalName}).count -gt 1){
            if(!($hash.$($childnode.LocalName))){
                $hash.$($childnode.LocalName) += @()
            }
            if ($childnode.'#text' -ne $null) {
                $hash.$($childnode.LocalName) += $childnode.'#text'
            }
            $hash.$($childnode.LocalName) += xmlNodeToPsCustomObject($childnode)
        }else{
            if ($childnode.'#text' -ne $null) {
                $hash.$($childnode.LocalName) = $childnode.'#text'
            }else{
                $hash.$($childnode.LocalName) = xmlNodeToPsCustomObject($childnode)
            }
        }   
    }
    return $hash | ConvertTo-PsCustomObjectFromHashtable
}

function ConvertTo-PsCustomObjectFromHashtable { 
    param ( 
        [Parameter(  
            Position = 0,   
            Mandatory = $true,   
            ValueFromPipeline = $true,  
            ValueFromPipelineByPropertyName = $true  
        )] [object[]]$hashtable 
    ); 

    begin { $i = 0; } 

    process { 
        foreach ($myHashtable in $hashtable) { 
            if ($myHashtable.GetType().Name -eq 'hashtable') { 
                $output = New-Object -TypeName PsObject; 
                Add-Member -InputObject $output -MemberType ScriptMethod -Name AddNote -Value {  
                    Add-Member -InputObject $this -MemberType NoteProperty -Name $args[0] -Value $args[1]; 
                }; 
                $myHashtable.Keys | Sort-Object | % {  
                    $output.AddNote($_, $myHashtable.$_);  
                } 
                $output
            } else { 
                Write-Warning "Index $i is not of type [hashtable]"; 
            }
            $i += 1;  
        }
    } 
}
Related