使用Powershell进行XML解析

使用Powershell进行XML解析,xml,powershell,parsing,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

我正在尝试使用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>
所需输出:

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
这是因为第2行的Select对象创建了一个非xml的新对象

我不是处理XML的专家,因此可能有更好的方法,但我会将其编码为您想要的输出:

[xml]$inputFile=获取内容C:\RolesnPer.xml $Nodelist=$inputFile.SelectNodes//Role $ParsedOutput=@ $Nodelist中的foreach$Role{ $Name=$Role.Name $Privilege=$Role.Privilege |选择对象-扩展属性名称 $Obj=新对象-类型名称psobject $Obj |添加成员-成员类型NoteProperty-名称名称-值$Name $Obj |添加成员-成员类型NoteProperty-名称权限-值$Privilege $ParsedOutput+=$Obj } $ParsedOutput 正确诊断您的问题选择对象发射[pscustomobject]实例,而不是XML节点,但有一个更简单的解决方案:

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

姓名特权 -- ----- VirtualMachinePowerUser{Datastore.Browse,Global.CancelTask,ScheduledTask.Create} 虚拟机用户{Global.CancelTask,ScheduledTask.Create} 说明:

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

每个匹配的节点都可以通过ForEach对象脚本块内的$\节点进行访问,PowerShell方便地将XML元素节点的子元素和属性公开为直接属性,因此.Name报告Name属性的值,.Privilege将所有特权子元素作为数组返回,并且,由于,访问其.Name属性将返回其所有名称属性的数组

[pscustomobject]@{…}是PSv3+语法糖,用于使用哈希表语法构造自定义对象

注意:虽然输出格式并不完全符合您的要求,但输出对象而不是使用字符串格式为后续编程处理提供了更大的灵活性

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


我知道已经提供了关于访问元素数据的答案,但这篇文章主要是为了解决输出格式要求:

$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对象数组具有两个属性Name和Privilege而不进行格式化,则只需要前两行。然后输出变量$nodes。

非常感谢这是我期望的结果我得到了相同的结果感谢您的帮助
# The format string to use with the -f operator below.
# The first column is 30 chars. wide; adjust as needed.
$fmtStr = '{0,-30} {1}'

# Output the header line.
$fmtStr -f 'Name', 'Privilege'

# Query the XML document and output the data lines.
Select-Xml -LiteralPath t.xml '//Role' | ForEach-Object {
  $name = $_.Node.Name
  foreach ($priv in $_.Node.Privilege.Name) {
    $fmtStr -f $name, $priv
    $name = ''
  }
}
$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