Синтаксический анализ XML с использованием Powershell - PullRequest
2 голосов
/ 09 мая 2019

Я пытаюсь проанализировать XML-файл с помощью powershell. Я хочу напечатать каждый узел и его подузлы. Я новичок в разборе 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 ]

2 голосов
/ 09 мая 2019

Полезный ответ Deadrobot правильно диагностирует вашу проблему (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 может напрямую работать с файлами для извлечения совпадающих узлов с запросами XPath.

  • Каждый соответствующий узел может быть доступен через $_.Node внутри блока сценария ForEach-Object, и PowerShell удобно представляет дочерние элементы и атрибуты узлов элементов XML как прямые свойства, так что .Name сообщает значение Name attribute и .Privilege возвращают все Privilege дочерние элементы в виде массива, и, благодаря перечислению членов , доступ к их свойству .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 = ''
  }
}
1 голос
/ 09 мая 2019

Я знаю, что ответы уже были предоставлены при доступе к данным элемента, но этот пост предназначен главным образом для ответа на запрос форматирования вывода:

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

1 голос
/ 09 мая 2019

Это происходит потому, что Select-Object в строке 2 создает новый объект, который не является 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...