powershellselect-xml

Errors on converting XML to an object using XPath


I am struggling with Powershell, XML and XPath.

I want a script that will read a file, extract the node I need and convert to an object I can use in the script.

The file looks like:

<?xml version="1.0"?>
<Objs xmlns="http://schemas.microsoft.com/powershell/2004/04" Version="1.1.0.1">
    <Obj RefId="0">
        <TN RefId="0">
            <T>System.Object</T>
        </TN>
        <Props>
            <Obj N="Set1" RefId="1">
                <TN RefId="1">
                    <T>System.Object</T>
                </TN>
                <Props>
                    <S N="Folder">C:\t1</S>
                    <Obj N="Configs" RefId="10">
                        <TN RefId="10">
                            <T>System.Object</T>
                        </TN>
                        <Props>
                            <S N="N1">Geralt</S>
                            <S N="N2">Ciri</S>
                        </Props>
                    </Obj>
                </Props>
            </Obj>
            <Obj N="Set2" RefId="2">
                <TN RefId="2">
                    <T>System.Object</T>
                </TN>
                <Props>
                    <S N="Folder">C:\t2</S>
                    <Obj N="Configs" RefId="20">
                        <TN RefId="20">
                            <T>System.Object</T>
                        </TN>
                        <Props>
                            <S N="N1">Triss</S>
                            <S N="N2">Yen</S>
                        </Props>
                    </Obj>
                </Props>
            </Obj>
        </Props>
    </Obj>
</Objs>

I wrote this code:

$path = "c:\file.xml"
$xpath = "/ns:Objs/ns:Obj/ns:Props/ns:Obj[@N='Set2']"
$ns = "@{ns='http://schemas.microsoft.com/powershell/2004/04'}"

[xml]$apps = Select-Xml -Path $path -XPath $xpath -Namespace $ns

I was expecting to be able to write :

Write-Host "Folder is: $apps.Folder" -> C:\t1 Write-Host "Config is: $apps.Configs.N2" -> Yen

But I can't get an object because of this error:

Cannot convert value "...". Error: "This document already has a 'DocumentElement' node."
At line:1 char:1
+ [xml]$t = Select-Xml -Path $path -XPath "/ns:Objs/ns:Obj/ns:Props/ns:Obj[@N='Set2']"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : MetadataError: (:) [], ArgumentTransformationMetadataException
    + FullyQualifiedErrorId : RuntimeException

Any suggestions ?


Solution

  • This looks like an output from Export-CliXml. It would be easier to deserialize using Import-CliXml:

    $apps = Import-Clixml -Path c:\file.xml
    $apps.Set2.Folder
    $apps.Set2.Configs.N2
    

    In your original code, the namespace has the wrong syntax. It should be a hash table.

    $ns = @{ns='http://schemas.microsoft.com/powershell/2004/04'}
    

    Surrounding the hash table code in double quotes creates a string instead. If we use your XPATH expression for the Obj node that contains Set2, you will need to further drill down the node tree.

    $path = "c:\file.xml"
    $xpath = "/ns:Objs/ns:Obj/ns:Props/ns:Obj[@N='Set2']"
    $ns = @{ns='http://schemas.microsoft.com/powershell/2004/04'}
    
    $apps = Select-Xml -Path $path -XPath $xpath -Namespace $ns
    $apps.Node.Props.S.Innertext # Folder value
    $apps.Node.Props.Obj.Props.S.Innertext # Configs values