Powershell xml xpath

В Powershell, предположим, что у меня есть следующий xml:

  <Users>
    <User Name="Foo">
      <Friends>
        <Friend Name="Bar"/>
      </Friends>
    </User>
    <User Name="Foo2" />
    <User Name="Foo3">
      <Friends>
        <Friend Name="Bar"/>
      </Friends>
    </User>
  </Users>

Как я могу получить всех пользователей, у которых есть "Бар" в качестве друга? (В этом примере это будет Foo, Foo3).

Должен ли я использовать xpath?

Спасибо!

Ответ 1

Я предпочитаю использовать XPath в эти дни. Я столкнулся с проблемами с помощью адаптера xls PowerShell, которые раздражают, как столкновение имен на item:

$xml = [xml]@'
  <Users> 
    <User Name="Foo"> 
      <Friends> 
        <Friend Name="Bar"/> 
      </Friends> 
    </User> 
    <User Name="Foo2" /> 
    <User Name="Foo3"> 
      <Friends> 
        <Friend Name="Bar"/> 
      </Friends> 
    </User> 
  </Users> 
'@

Select-Xml '//User[contains(Friends/Friend/@Name, "Bar")]' $xml |%{$_.Node.Name}

Ответ 2

В этом случае я бы использовал XPath. @TomWij предоставил правильный xpath.

Если выражение xpath будет слишком сложным, я бы наверняка использовал "классический" подход.

$x.Users.User | ? { $_.Friends.Friend.Name -eq 'Bar' }

(в этом случае, если у вас нет режима script, не имеет значения, что нет элемента Friends. $_.Friends вернет $null и $null.Friend возвращает $null как ну и т.д. Итак, наконец, $null -eq 'Bar' возвращает false и элемент удаляется Where-Object)

Ответ 4

Хотя другие ответы вполне приемлемы, я лично предпочитаю делать это с помощью SelectNodes.

Учитывая вопрос XML в переменной $xml, следующий будет возвращать массив.

$names = $xml.SelectNodes("//User[contains(Friends/Friend/@Name, 'Bar')]/@Name")

Переменная $names - это XPathNodeList, которая получена из XmlNodeList и выдаст следующее.

#text
-----
Foo
Foo3

Если вы хотите получить значения, вы можете выполнить итерацию или получить по индексу. Например, $names[1].Value будет производить Foo3.