Проблемы с циклом XML с помощью PowerShell - PullRequest
0 голосов
/ 13 марта 2020

Мне нужно l oop - XML, создать новый элемент со значениями из существующих элементов, а затем удалить существующие элементы. Я сделал это довольно далеко, и он работает, как и ожидалось, для первого l oop, но некоторые части выходят из строя в последующих циклах. Надеюсь, что кто-то может взглянуть и дать направление, поскольку я исчерпал свои тонкие знания PowerShell. Вот пример начала XML. Обратите внимание, что элемент может быть вложен непоследовательно:

<val:root xmlns:val="urn:dummy">
  <bla>foo</bla>
  <value>
    <sometag>foo</sometag>
    <displayx>1x</displayx>
    <displayy>1y</displayy>
    <displaywidth>1w</displaywidth>
    <displayheight>1h</displayheight>
    <someothertag>foo</someothertag>
  </value>
  <value>
    <sometag>foo</sometag>
    <displayx>2x</displayx>
    <displayy>2y</displayy>
    <someothertag>foo</someothertag>
    <yetanothertag>foo</yetanothertag>
  </value>
  <nest>
      <value>
        <displayx>3x</displayx>
        <displayy>3y</displayy>
        <displaywidth>3w</displaywidth>
        <displayheight>3h</displayheight>
        <someothertag>foo</someothertag>
      </value>
  </nest>
</val:root>

Когда выполняется, вот вывод:

<val:root xmlns:val="urn:dummy">
  <bla>foo</bla>
  <value>
    <sometag>foo</sometag>
    <someothertag>foo</someothertag>
    <display x="1x" y="1y" w="1w" h="1h" />
  </value>
  <value>
    <sometag>foo</sometag>
    <someothertag>foo</someothertag>
    <yetanothertag>foo</yetanothertag>
    <display x="" y="" />
  </value>
  <nest>
    <value>
      <someothertag>foo</someothertag>
    </value>
  </nest>
</val:root>

Первый узел идеален. Значения существующих элементов отображения были добавлены в новый элемент в качестве атрибутов. Последующие элементы значений не являются захватывающими значениями, а третий (вложенный) даже не создал новый элемент.

Вот текущий скрипт:

# Define the document
$filename = "2.xml";

# Read Content
$xml = [System.Xml.XmlDocument](Get-Content (Resolve-Path $fileName));

$nodes = $xml.SelectNodes("*/value")
#$nodes = $xml.root.value

# Loop through each <value> element, capture <display*> values, write values to new element as attributes
foreach ($v in $nodes) {
    # Create new element
    $newDisplay = $v.AppendChild($xml.CreateElement("display"));
    # Collect existing x value and write as attribute
    $x = $v.displayx
    $newDisplay.SetAttribute("x","$x");
    # Collect existing y value and write as attribute
    $y = $v.displayy
    $newDisplay.SetAttribute("y","$y");
    # Collect existing w value, if available, and write as attribute
    $w = $v.displaywidth
    if($v.displaywidth -ne $null) {
        $newDisplay.SetAttribute("w","$w");
        }
    # Collect existing w value, if available, and write as attribute
    $h = $v.displayheight
    if($v.displayheight -ne $null) {
        $newDisplay.SetAttribute("h","$h");
        }

    # Delete old elements
    $node = $xml.SelectSingleNode("//displayx")
    while ($node -ne $null)
    {
        $node.ParentNode.RemoveChild($node)
        $node = $xml.SelectSingleNode("//displayx")
    }
    $node = $xml.SelectSingleNode("//displayy")
    while ($node -ne $null)
    {
        $node.ParentNode.RemoveChild($node)
        $node = $xml.SelectSingleNode("//displayy")
    }
    $node = $xml.SelectSingleNode("//displaywidth")
    while ($node -ne $null)
    {
        $node.ParentNode.RemoveChild($node)
        $node = $xml.SelectSingleNode("//displaywidth")
    }
    $node = $xml.SelectSingleNode("//displayheight")
    while ($node -ne $null)
    {
        $node.ParentNode.RemoveChild($node)
        $node = $xml.SelectSingleNode("//displayheight")
    }
} 

# Save
$xml.Save((Resolve-Path $filename));

Ширина и элементы height являются необязательными, поэтому для них используются операторы if.

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

Заранее спасибо.

1 Ответ

0 голосов
/ 14 марта 2020

Это потому, что все старые элементы были удалены в первый раз foreach l oop. Удаление только дочерних элементов $v решает эту проблему.

$filename = "2.xml"

$doc = [xml](Get-Content $filename)

# get all value elements
$values = $doc.SelectNodes("//value")

foreach ($v in $values) {

    # create and append new element
    $newDisplay = $v.AppendChild($doc.CreateElement("display"))

    # get old elements
    $x, $y, $w, $h = $v["displayx", "displayy", "displaywidth", "displayheight"]

    # set attributes of new element
    $newDisplay.SetAttribute("x", $x.InnerText)
    $newDisplay.SetAttribute("y", $y.InnerText)
    if ($w -and $h) {
        $newDisplay.SetAttribute("w", $w.InnerText)
        $newDisplay.SetAttribute("h", $h.InnerText)
    }

    # delete old elements
    @($x, $y, $w, $h) -ne $null | foreach { [void]$v.RemoveChild($_) }
}

$doc.Save("$pwd/result.xml");
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...