【问题标题】:XML Parsing using Powershell使用 Powershell 进行 XML 解析
【发布时间】:2019-09-27 02:33:24
【问题描述】:

我正在尝试使用 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

【问题讨论】:

    标签: xml powershell parsing


    【解决方案1】:

    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 查询提取匹配节点。

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

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

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


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

    # 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 = ''
      }
    }
    

    【讨论】:

      【解决方案2】:

      这是因为第 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
      

      【讨论】:

      • 感谢您的帮助
      【解决方案3】:

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

      $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。

      【讨论】:

      • 非常感谢,这是我所期望的,我得到了相同的结果
      猜你喜欢
      • 2020-02-21
      • 2013-08-04
      • 2020-12-30
      • 1970-01-01
      • 2013-07-18
      • 1970-01-01
      • 1970-01-01
      • 2013-06-25
      相关资源
      最近更新 更多