从XML中删除多个子元素

时间:2016-03-24 00:26:34

标签: xml powershell

<?xml version="1.0"?>
<Root>
  <Book>
    <Name>Title1</Name>
    <Name>Title2</Name>
    <Name>Title3</Name>
    <Name>Title3</Name>
    <Name>Title3</Name>
  </Book>
</Root>

我想从Book节点中删除一些选定的Name元素。我尝试了以下方法,但似乎没有效果。使用给定数组删除子节点的正确方法是什么(例如$delnode)?

$delnode = 'Title1','Title2'
$xml.Root.Book | ? {$delnode -eq $_.Name} | % {$xml.Root.Book.RemoveChild($_)}

提前致谢。

3 个答案:

答案 0 :(得分:0)

$delnode = @('Title1','Title2')
($xml.Root.Book.ChildNodes | ? {$delnode -eq $_.InnerText}) | % {
    $xml.Root.Book.RemoveChild($_) | Out-Null
}

几点说明:

  • 您希望迭代 $ xml.Root.Book 元素的ChildNodes
  • 这些子节点没有名为“Name”的属性。它们是元素,因此它们具有InnerText属性。
  • RemoveChild()返回已删除的元素。由于您不希望此元素显示在您的输出中,因此对RemoveChild()的调用会通过管道传递到Out-Null
  • For-Each ChildNodes)调用之前,请注意围绕?%来电的括号。这些是必需的,因为您不想在当前正在迭代的集合上调用RemoveChild()

答案 1 :(得分:0)

  • 您需要枚举Book
  • 的ChildNodes集合
  • 您正在比较错误的元素属性。您需要根据文本值进行比较,而不是元素名称(返回“名称”)
  • 您应该使用-contains来检查当前节点是否在要删除的项目数组中
    $delnode = 'Title1','Title2'
    $xml.Root.Book.ChildNodes | ? { $delnode -contains $_.'#text'} | %  {
        $xml.Root.Book.RemoveChild($_)
    }

答案 2 :(得分:0)

当管道给我带来麻烦时,我的第一条规则就是停止使用管道,将代码重构为部分,并使用ISE来调试中间变量上的断点,而不仅仅是调试,而是发现每个对象具有哪些属性(如#textInnerChild等)。

这与JamesQMurphy给出的答案非常类似,但也可能导致更容易理解,更改和/或调试的代码。

[xml]$xml = (Get-Content D:\test\t1.xml)

Write-Output "`nbefore..."
$xml.Root.Book | ft

$delnode = 'Title1','Title2'
$nodesToDelete = @()
foreach ($title in $delnode) {
    $nodesToDelete += $xml.Root.Book.ChildNodes | ? {$_.InnerText -eq $title}
}

Write-Output "`nto delete..."
$nodesToDelete | ft

Write-Output "`ndeleting..."
$nodesToDelete | % {$xml.Root.Book.RemoveChild($_) | Out-Null}

Write-Output "`nafter..."
$xml.Root.Book | ft