Powershell — замена XML-узла в памяти во время итерации

#xml #powershell

#xml #powershell

Вопрос:

У меня есть следующий xml:

 <messages>
  <message name="Advertisement" msgtype="7" msgcat="app">
    <field name="AdvId" required="Y" />
    <field name="AdvTransType" required="Y" />
    <field name="AdvRefID" required="N" />
    <component name="Instrument" required="Y" />
    <field name="AdvSide" required="Y" />
    <field name="Quantity" required="Y" />
  </message>
</messages>
<components>
  <component name="Instrument">
    <field name="Symbol" required="Y" />
    <field name="SymbolSfx" required="N" />
    <field name="SecurityID" required="N" />
    <field name="SecurityIDSource" required="N" />
    <group name="NoSecurityAltID" required="N">
      <field name="SecurityAltID" required="N" />
      <field name="SecurityAltIDSource" required="N" />
    </group>
    <field name="Product" required="N" />
    <field name="CFICode" required="N" />
  </component>
</components>
  

Я хочу перебирать каждое сообщение, и когда я сталкиваюсь с component тегом, я хочу заменить компонентный xml на поля / группы компонента.

Я пытался использовать ReplaceChild , но он работал не так, как ожидалось.

   [void]LoadComponents() {
    $this.xml.messages.message | ForEach-Object {
      $m = $_
      foreach ($node in $m.ChildNodes){
        if ($node.LocalName -eq "component") {
          Write-Host "Old Message: "
          Write-Host ($m.field | Format-Table | Out-String)
          $c = $this.GetComponent($node.name)
          Write-Host "Component: "
          Write-Host ($c.group | Format-Table | Out-String)
          $m.ReplaceChild($c, $node)
          Write-Host "New Message: "
          Write-Host ($m.field | Format-Table | Out-String)
        }
      }
    }
  }

  [System.Xml.XmlElement]GetComponent([string]$name) {
    return $this.xml.components.component | Where-Object { $_.name -eq $name }
  }
  

Редактировать:

Я включаю тот факт, что я использую powershell версии 6.0.0.10 alpha в OSX, потому что, по-видимому, в нем отсутствует много функций.

Ответ №1:

Используйте XPath для непосредственного выбора узлов компонентов и клонирования узла замены в replaceChild.

 $xml.SelectNodes('/root/messages/message/component') | ForEach {
    $comp = $xml.SelectSingleNode('/root/components/component[@name="'   $_.name   '"]')
    $message = $_.ParentNode
    $message.ReplaceChild($comp.Clone(), $_)
}
  

Код предполагает, что корневой узел root .

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

1. Спасибо @wOxxOm, но я получаю [System.Xml.XmlDocument] does not contain a method named 'SelectNodes'

2. версия powershell: 6.0.0 alpha

3. Я не использую глючные / неполные альфа-версии, поэтому понятия не имею, как он мог пропустить такую базовую функциональность. Это так же абсурдно, как строка без indexOf .