使用Powershell进行XML解析

时间:2019-05-09 09:26:49

标签: xml powershell parsing

我正在尝试使用powershell解析xml文件。我想打印每个节点及其子节点。我是xml解析的新手。

<?xml version="1.0" encoding="UTF-8"?>
<Inventory>
  <Roles>
    <Role Name="VirtualMachinePowerUser" Label="Virtual machine power user (sample)" Summary="Provides virtual machine interaction and configuration permissions">
      <Privilege Name="Datastore.Browse" />
      <Privilege Name="Global.CancelTask" />
      <Privilege Name="ScheduledTask.Create" />
</Role>
    <Role Name="VirtualMachineUser" Label="Virtual machine user (sample)" Summary="Provides virtual machine interaction permissions">
      <Privilege Name="Global.CancelTask" />
      <Privilege Name="ScheduledTask.Create" />
</Role>

我的下面的代码

[xml]$inputFile = Get-Content "C:\RolesnPer.xml"     
$nodelist = $inputFile.Inventory.Roles.Role |Select-Object -Property Name
foreach ($Role in $nodelist)
{
    $Role
    $XMLprinterPath = $Role.selectSingleNode("Privilege").get_innerXml()
}

必填输出:

Name                      Privilege
VirtualMachinePowerUser   Datastore.Browse
                          Global.CancelTask
                          ScheduledTask.Create
VirtualMachineUser        Global.CancelTask
                          ScheduledTask.Create

但是我得到以下输出:

Name
----
VirtualMachinePowerUser
Method invocation failed because [Selected.System.Xml.XmlElement] does not contain a method named 'selectSingleNode'.
At C:\Mandy\Code\transformation.ps1:25 char:1
+ $XMLprinterPath = $Role.selectSingleNode("Privilege").get_innerXml()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (selectSingleNode:String) [], RuntimeException
    + FullyQualifiedErrorId : MethodNotFound

VirtualMachineUser
Method invocation failed because [Selected.System.Xml.XmlElement] does not contain a method named 'selectSingleNode'.
At C:\Mandy\Code\transformation.ps1:25 char:1
+ $XMLprinterPath = $Role.selectSingleNode("Privilege").get_innerXml()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (selectSingleNode:String) [], RuntimeException
    + FullyQualifiedErrorId : MethodNotFound

3 个答案:

答案 0 :(得分:2)

Deadrobot's helpful answer可以正确诊断您的问题(Select-Object发出[pscustomobject]实例,而不是XML节点),但是有一个更简单的解决方案:

Select-Xml -LiteralPath C:\RolesnPer.xml '//Role' | ForEach-Object {
  [pscustomobject] @{
    Name = $_.Node.Name
    Privilege = $_.Node.Privilege.Name
  }
}

以上结果:

Name                    Privilege
----                    ---------
VirtualMachinePowerUser {Datastore.Browse, Global.CancelTask, ScheduledTask.Create}
VirtualMachineUser      {Global.CancelTask, ScheduledTask.Create}

说明:

  • Select-Xml cmdlet可以直接对文件进行操作,以使用XPath查询提取匹配的节点。

  • 可以通过$_.Node脚本块内的ForEach-Object访问每个匹配的节点,PowerShell方便地将XML元素节点的子元素和属性公开为直接属性,因此{{1 }}报告.Name属性的值,Name返回所有.Privilege个子元素作为数组,并感谢member enumeration来访问它们的Privilege属性返回其所有.Name属性的数组。

  • Name是PSv3 +语法糖,用于使用哈希表语法构造自定义对象。

注意:虽然输出格式不是您要求的 ,但是输出对象 (而不是使用字符串格式)为您为以后的程序处理提供了更大的灵活性


如果您确实需要问题中指定的精确输出格式

[pscustomobject] @{ ... }

答案 1 :(得分:1)

之所以会这样,是因为第2行上的Select-Object创建了一个不是xml的新对象。

我不是处理XML的专家,所以也许有更好的方法,但是我会对其进行编码以获得所需的输出:

[xml]$inputFile = Get-Content "C:\RolesnPer.xml"  
$Nodelist = $inputFile.SelectNodes("//Role")
$ParsedOutput = @()
foreach ($Role in $Nodelist) {
    $Name = $Role.Name
    $Privilege = $Role.Privilege |Select-Object -ExpandProperty name
    $Obj = New-Object -TypeName psobject
    $Obj | Add-Member -MemberType NoteProperty -Name Name -Value $Name
    $Obj | Add-Member -MemberType NoteProperty -Name Privilege -Value $Privilege
    $ParsedOutput += $Obj
}

$ParsedOutput

答案 2 :(得分:1)

我知道已经提供了有关访问元素数据的答案,但是本文主要是针对输出格式要求:

$inputFile = [xml](Get-Content "C:\RolesnPer.xml")
$nodes = $inputFile.Inventory.Roles.Role | Select-Object -Property Name,Privilege
$NameColWidth = ($nodes.name | Foreach-Object { $_.length } | Sort-Object -Desc)[0] + 2
$FormattedOutput = @("{0,-$NameColWidth}{1}" -f "Name","Privilege") -as [collections.arraylist]
foreach ($node in $nodes) {
    $null = $FormattedOutput.Add(("{0,-$NameColWidth}{1}" -f $node.name,($node.privilege.name | Select-Object -First 1)))
    $node.Privilege | Select -expand Name -skip 1 | Foreach-Object {
        $null = $FormattedOutput.Add(("{0,-$NameColWidth}{1}" -f " ",$_))
    }
}
$FormattedOutput

如果只希望PowerShell对象数组具有两个属性(名称和特权)而不进行格式化,则只需要前两行。然后输出变量$nodes