Reputation: 23
I am trying to figure out how to delete a xml node by searching the ModelName or PlatformID based on the XML below. I've tried a few ways but I can't seem to get it to work. Any ideas?
XML:
<?xml version="1.0" encoding="ISO-8859-1"?>
<HPModels>
<Model>
<ModelName>HP EliteBook x360</ModelName>
<PlatformID>8725</PlatformID>
</Model>
<Model>
<ModelName>HP EliteBook x360</ModelName>
<PlatformID>876d</PlatformID>
</Model>
</HPModels>
I'm trying to use this but I've had no luck
$file = "C:\Temp\test1.xml"
$xmlfile = [XML](Get-Content $file)
$item = Select-XML -Xml $xmlfile -XPath '//ModelName[Name="HP EliteBook x360"]'
$item.Node.ParentNode.RemoveChild($item.node)
I am getting:
You cannot call a method on a null-valued expression.
At line:4 char:1
Upvotes: 0
Views: 1544
Reputation: 23
Thank you @Mathias R. Jessen. This is the correct way to do it if anyone else wants to know.
XML:
<?xml version="1.0" encoding="ISO-8859-1"?>
<HPModels>
<Model>
<ModelName>HP EliteBook x360</ModelName>
<PlatformID>8725</PlatformID>
</Model>
<Model>
<ModelName>HP EliteBook x360 1030</ModelName>
<PlatformID>876d</PlatformID>
</Model>
</HPModels>
$modelselect = "HP EliteBook x360"
$file = "C:\Temp\test1.xml"
$xmlfile = [XML](Get-Content $file)
$item = Select-Xml $xmlFile -XPath "//Model[./ModelName = '$modelselect']"
foreach($node in $item.Node)
{
$node.ParentNode.RemoveChild($node)
}
$xmlFile.Save($file)
Upvotes: 0
Reputation: 174485
From your comments:
I would want to delete the whole
<Model>
node if a match is found.
In that case, I would suggest using the following as the base expression//Model
- then you can use your existing expression as a predicate [...]
:
$items = Select-Xml $xmlFile -XPath '//Model[./ModelName = "HP EliteBook x360"]'
Here, we get Select-Xml
to select all <Model>
nodes that have an immediate child <ModelName>
, the inner value of which is "HP EliteBook x360"
You can also use the ..
selector to "walk back up" to the parent node after resolving the appropriate child node:
$items = Select-Xml $xmlFile -XPath '//ModelName[. = "HP EliteBook x360"]/..'
I (personally) don't like this pattern, but it is perfectly valid XPath :)
Once the selector expression is fixed, make sure you process the results 1 at a time - Select-Xml
might return multiple nodes:
foreach($item in $items){
$node = $item.Node
$node.ParentNode.RemoveChild($node)
}
If you want to accept different model names as parameter arguments, add a param()
block on the first line of the script and then use that in the XPath expression:
param(
[Parameter(Mandatory)]
[string]$FilePath,
[Parameter(Mandatory)]
[string]$ModelName
)
if($ModelName -like "*'*"){
throw 'Cannot process model name with apostrophe'
return
}
$file = Convert-Path $FilePath
$xmlfile = [XML](Get-Content $file)
$items = Select-XML -Xml $xmlfile -XPath "//ModelName[Name='${ModelName}']"
foreach($item in $items){
$node = $item.Node
$node.ParentNode.RemoveChild($node)
}
$xmlfile.Save($file)
Then pass the parameter arguments for the file path and model name when calling the script:
.\Remove-ModelFromXml.ps1 -FilePath .\path\to\file.xml -ModelName "HP EliteBook x360"
Upvotes: 4