Given an XmlElement
with various child nodes, and a $invalidElements
array of invalid child node names, I want to delete all the offending child nodes. I started with this
foreach ($childNode in $sourceElement.ChildNodes) {
if ($childNode.LocalName -in $invalidElements) {
[Void]$childNode.ParentNode.RemoveChild($childNode)
}
}
And it works up to the first delete, with the loop ending then. Because I am mutating the object I am trying to loop through. So I wondering what the most efficient way to do this is. $invalidElements
is an Array
from a HashSet
, so duplicate invalid elements aren't represented, since this was initially intended for logging only. My thought is to create a new array that contains all the invalid names. Then I can loop While
that array is populated, and inside that I can loop until the first instance of an invalid element, then delete the element and an instance of the name from the array. But that seems ugly.
Seems to me there has to be a more elegant way of doing this?
EDIT: So, an alternative to what @mathias-r-jessen posted. I'll need to decide which of the two I like better. :)
$elementsToRemove = $sourceElement.ChildNodes.Where({$_.LocalName -in $invalidElements})
foreach ($elementToRemove in $elementsToRemove) {
[Void]$elementToRemove.ParentNode.RemoveChild($elementToRemove)
}
As you've found yourself, you can preempt invalidating the enumerator on mutation by materializing an array of child nodes ahead of time and then iterate over that instead - the easiest way to do so is probably to evaluate .ChildNodes
in a subarray expression @()
:
foreach ($childNode in @($sourceElement.ChildNodes)) {
if ($childNode.LocalName -in $invalidElements) {
[Void]$childNode.ParentNode.RemoveChild($childNode)
}
}
While modifying the collection underpinning $sourceElement.ChildNodes
would still invalidate any enumerator obtained through $sourceElement.ChildNodes
, it won't make a difference to the array created and populated by @(...)