PowerShell: выполните синтаксический анализ через xml-узлы через xpath и создайте выходную строку

#xml #powershell

#xml #powershell

Вопрос:

у меня есть следующий пример XML

 <AlarmGroup xmlns="http://.." Name="example">
  <TextGroup>
   <TextLayer LanguageId="en">
      <Text ID="1" Value="not used / unknown"/>
      <Text ID="2" Value="not used / unknown"/>
      <Text ID="3" Value="not used / unknown"/>
      <Text ID="4" Value="not used / unknown"/>
    </TextLayer>
    <TextLayer LanguageId="de">  
      <Text ID="1" Value="not used / unknown"/>
      ...   
    </TextLayer> 
  


Я пытаюсь просмотреть каждый текстовый слой и создать строку, подобную следующей:

ru;1;не используется / неизвестно

ru;2;не используется / неизвестно

Я перепробовал много способов, например:

  $AlarmgroupLanguageText = Select-Xml -Xml $Content -XPath "//example:TextLayer" -namespace $ns | select -ExpandProperty node

    $AlarmgroupLanguageText.TextLayer |foreach{
      $AlarmgroupLanguageText |foreach{
        $output  = $_.LanguageID   ";"   $_.Text.ID   ";"   $_.Text.Value   "`r`n"

    }   
  

Было бы здорово, если бы кто-нибудь мог помочь мне запросить этот вопрос непрофессионала.

TIA

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

1. Я попробовал это. Выглядит лучше, но у меня нет? доступ? для атрибута ID и Value текста

2. Я думаю, что выражение XPath, которое вы хотите, это //AlarmGroup[@Name="example"]//TextLayer

3. Можете ли вы показать, как вы создаете свою $ns переменную (предположительно, менеджер пространства имен / таблицу)? Это повлияет на префикс пространства имен, который вам нужно использовать для выбора ваших узлов.

Ответ №1:

Как предположил @Matthias R. Jessen в комментариях, ваш XPath немного шаткий. Однако, как только вы это заработаете, в вашем коде также обнаружатся некоторые другие ошибки, поэтому, отступив немного назад, вот немного другой способ сделать это:

 $xml = [xml] @"
<AlarmGroup xmlns="http://.." Name="example">
  <TextGroup>
   <TextLayer LanguageId="en">
      <Text ID="1" Value="not used / unknown"/>
      <Text ID="2" Value="not used / unknown"/>
      <Text ID="3" Value="not used / unknown"/>
      <Text ID="4" Value="not used / unknown"/>
    </TextLayer>
    <TextLayer LanguageId="de">  
      <Text ID="1" Value="not used / unknown"/>
    </TextLayer>
  </TextGroup>
</AlarmGroup>
"@;

# 1. find a root <AlarmGroup> where Name="example"
$alarmGroup = @( $xml.AlarmGroup | where-object { $_.Name -eq "example" } )[0];

# 2. get all the child <Text> nodes nested under the <AlarmGroup>
$textNodes = @( $alarmGroup.TextGroup.TextLayer.Text );

# 3. format each <Text> node into a string
$textLines = $textNodes | foreach-object {
    $_.ParentNode.LanguageId   ";"   $_.ID   ";"   $_.Value
};

# 4. concatenate all the strings together
$output = $textLines -join "`r`n";

# 5. show the result
$output
# en;1;not used / unknown
# en;2;not used / unknown
# en;3;not used / unknown
# en;4;not used / unknown
# de;1;not used / unknown
  

Сложность в том, $alarmGroup.TextGroup.TextLayer.Text что здесь используется перечисление элементов для расширения узлов TextGroup и TextLayer , чтобы получить все вложенные Text узлы — в данном случае это в основном эквивалентно XPath //TextGroup/TextLayer/Text .

Надеюсь, остальное не требует пояснений…