Перебор иерархии XML и получение всех узлов с определенными свойствами

#xml #powershell

#xml #powershell

Вопрос:

Я извлек некоторые данные из решения, которое поддерживает только некоторые довольно подозрительные XML-экспорты. Мне нужно пройти по иерархии в Powershell, чтобы перечислить все объекты типа = «node», независимо от того, насколько глубоко они находятся в иерархии, которые имеют свойство «KeySecret» и возвращают значение свойства «name» этого объекта и значение свойства «name» родительского объекта type =»Domain», к которому он принадлежит.

Не могу разобраться в этом, основываясь на том, что я пробовал select-xml -xpath.

Короткая и простая версия моего XML

 <?xml version="1.0"?>
<Object id="1.1622157565" type="Domain">
  <Property type="String" name="name" value="ROOTDOMAIN"/>
  <Object id="1.1131962319" type="Node">
    <Property type="String" name="name" value="AGENTLESS NODE 1"/>
  </Object>
  <Object id="1.1132169655" type="Domain">
    <Property type="String" name="name" value="SUBDOMAIN"/>
    <Object id="1.1132121638" type="Node">
      <Property type="BigNum" name="keySecret" value="1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"/>
      <Property type="String" name="name" value="AGENT NODE 1"/>
    </Object>
  </Object>
</Object>
  

Есть какие-нибудь подсказки относительно того, как в конечном итоге получить эту таблицу:

 Domain        Node
------        ------
SUBDOMAIN     AGENT NODE 1
  

Ответ №1:

Вот что у меня получилось на данный момент. Я надеюсь, что это укажет вам правильное направление.

 [xml]$XML = @"
<?xml version="1.0"?>
<Object id="1.1622157565" type="Domain">
  <Property type="String" name="name" value="ROOTDOMAIN"/>
  <Object id="1.1131962319" type="Node">
    <Property type="String" name="name" value="AGENTLESS NODE 1"/>
  </Object>
  <Object id="1.1132169655" type="Domain">
    <Property type="String" name="name" value="SUBDOMAIN"/>
    <Object id="1.1132121638" type="Node">
      <Property type="BigNum" name="keySecret" value="1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"/>
      <Property type="String" name="name" value="AGENT NODE 1"/>
    </Object>
  </Object>
</Object>
"@

$keyNode = $xml.SelectNodes("//*[@*[contains(translate(name(.),'n','N'),'Name')]]") | Where-Object {$_.Name -like "keySecret"} 

$keyParent = $keyNode

do {
    $keyParent = $keyParent.ParentNode
} 
Until ($keyParent.type -like "Domain")

$output = New-Object PSObject
$output | Add-Member -MemberType NoteProperty Domain ($keyParent.ChildNodes | Where-Object {$_.type -eq "String"}).Value
$output | Add-Member -MemberType NoteProperty Node $keyNode.NextSibling.value

$output
  

Ключевой узел: выбирает все узлы из XML, которые похожи 'Name=' , а затем выбирает все, что похоже 'keySecret'

Цикл Do,Until будет выполнять поиск по родительским узлам до тех пор, пока тип родительского узла не будет ‘Domain’. Это позволит вам найти узел, скрытый глубоко в иерархии. Узел ‘Domain’ задан как $keyParent .

Комментарии:

1. О, огромное спасибо, это определенно было не то, что я мог себе представить. Единственная проблема — в реальном сценарии свойство «name» не обязательно находится рядом с полем KeySecret. По большей части (возможно, весь, это 30-мегабайтный XML-файл, который я не проверял), это будет третий следующий родственный файл из KeySecret, поэтому мне нужно либо обратиться к нему конкретно, либо каким-то образом пропустить 2 родственных файла. Но, безусловно, это огромный шаг и то, что для меня очень близко к совершенству 🙂