Determine XML Node Exists
Solution 1
It appears that I was using the wrong syntax for SelectSingleNode. Here is a working example.
[xml]$xml = @'
<?xml version="1.0" encoding="UTF-8"?>
<!-- Vendors we will send and retreive files from Get-Send means we will get a file and send them a file Send means we will only send them a file-->
<Vendors>
<Vendor Type="Get-Send">
<Name>Vendor1</Name>
<RemotePath>/Remote/Path1/</RemotePath>
<EncKey>pgpenc.key</EncKey>
</Vendor>
<Vendor Type="Send">
<Name>Vendor2</Name>
<RemotePath>/Remote/Path2/</RemotePath>
<!-- This one has no EncKey -->
</Vendor>
</Vendors>
'@
foreach ($vendor in $xml.Vendors.Vendor| Where-Object {$_.Type -match "Send"}) {
$NodeExists = $vendor.SelectSingleNode("./EncKey")
if ($NodeExists -ne $null) {
write-host "EncKey is null"
}
else {
write-host "EncKey is not null"
}
}
EncKey is null
EncKey is not null
Thanks everyone for your help.
Solution 2
The easiest way I can think of is to try to write the node value to a variable, and then to see if that variable is null. Here's an example with the standard bookstore xml file.
[xml]$bookstore = Get-Content .\bookstore.xml
foreach ($book in $bookstore.bookstore.book | Where-Object {$_.Type -match "novel"}) {
$NodeExists = $book.author
if($NodeExists){
Write-Host $book.author
}
else{
Write-Host 'No Author'
}
}
So for your script, I would think it might be
$NodeExists = $null
foreach ($vendor in $xml.Vendors.Vendor| Where-Object {$_.Type -match "Send"}) {
$NodeExists = $vendor.EncKey
if ($NodeExists) {
# Do something
}
else {
# something else
}
}
Solution 3
Provided you load the $xml object as an XmlDocument using
$xml = new-object System.Xml.XmlDocument
$xml.LoadXml( (get-content $pathToXmlFile) )
Then you can do this, which is much simpler:
if ($vendor.encKey -ne $null) {
# does exist
} else {
# does not exist
}
Solution 4
Use XPath to select matching nodes. InnerText is searchable by text()
. You can use where-object
, or ?
too; behaviour is a bit different. Without sample XML it's hard to be more precise. Use XPath like so,
[xml]$doc = @'
<root>
<Vendors>
<Vendor>
<Type>Send</Type>
</Vendor>
<Vendor>
<Type>Receive</Type>
</Vendor>
</Vendors>
</root>
'@
# Xpath query will return a NodeList, even if no match is found
$node1 = $doc.SelectNodes("//Vendor/Type[text() = 'Send']")
$node2 = $doc.SelectNodes("//Vendor/Type[text() = 'Sent']")
$node1.Count
1
$node2.Count
0
# where-object will return $null if no match is found
$node1 = $doc.SelectNodes("//Vendor/Type") | ? { $_.InnerText -eq "Send" }
$node2 = $doc.SelectNodes("//Vendor/Type") | ? { $_.InnerText -eq "Sent" }
$node1 -eq $null
False
$node2 -eq $null
True
Related videos on Youtube
mack
Updated on May 16, 2020Comments
-
mack almost 4 years
This is probably simple, but I'm trying to determine if a node exists in an XML document. I thought I found an answer in this post, How to check whether a node exists or not using powershell without getting exception?, but I didn't get it to work. This is my latest attempt.
foreach ($vendor in $xml.Vendors.Vendor| Where-Object {$_.Type -match "Send"}) { $NodeExists = $vendor.SelectSingleNode($vendor.EncKey) if ($NodeExists -ne $null) { # Do something } else { # something else } }
Any help would be greatly appreciated.
EDIT: Here is XML from my test file. I need to find out of EncKey exists or note for each vendor.
<?xml version="1.0" encoding="UTF-8"?> <!-- Vendors we will send and retreive files from Get-Send means we will get a file and send them a file Send means we will only send them a file--> <Vendors> <Vendor Type="Get-Send"> <Name>Vendor1</Name> <RemotePath>/Remote/Path1/</RemotePath> <EncKey>pgpenc.key</EncKey> </Vendor> <Vendor Type="Send"> <Name>Vendor2</Name> <RemotePath>/Remote/Path2/</RemotePath> <!-- This one has no EncKey --> </Vendor> </Vendors>
-
Victor Zakharov over 10 yearsCould you please provide a reduced test case for your issue? Something we can paste into our favorite Powershell editor and play with it?
-
-
mack over 10 yearsThanks Alex. This is along the lines of what I was attempting to do, but if $vendor.EncKey does not exists I get an exception: Property 'EncKey' cannot be found on this object. Make sure that it exists. and I never get to the "else" part of the statement.
-
Jay almost 9 yearsYou can shorten this with "if ( $vendor.EncKey ) {" -- also, this is case insensitive, as compared to SelectSingleNode which did not work for me. I did not have any exception issue with this.
-
Jay almost 9 yearsAccording to my tests, SelectSingleNode is case sensitive, unless there is a way to change its behavior.
-
LosManos over 5 yearsDownvote because if the element does not exist an exception is thrown.
-
laika over 5 years@mack you'll actually get an exception when you have strict mode turned on. When the strict mode is turned off, then
$vendor.EncKey
evaluates to$false
in the statementif ( $vendor.EncKey )
, as provided by @Jay -
Raf over 5 yearsGood, but should be opposite. if ($NodeExists -ne $null) { write-host "EncKey is NOT null" }
-
kalenwatermeyer almost 4 yearsAn excellent article which simplifies the
SelectSingleNode(..)
implementation, using XML namespaces: https://blog.danskingdom.com/powershell-functions-to-get-an-xml-node-and-get-and-set-an-xml-elements-value-even-when-the-element-does-not-already-exist/