问题 确定XML节点存在


这可能很简单,但我正在尝试确定XML文档中是否存在节点。我以为我在这篇文章中找到了答案, 如何使用PowerShell检查节点是否存在而不会出现异常?,但我没有得到它的工作。这是我最近的尝试。

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
    }
   }

任何帮助将不胜感激。

编辑:这是我的测试文件中的XML。我需要找出每个供应商存在的EncKey或注释。

<?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>

7919
2017-12-06 21:31


起源

您能否为您的问题提供简化的测试用例?我们可以粘贴到我们最喜欢的Powershell编辑器中并使用它吗? - Neolisk


答案:


我能想到的最简单的方法是尝试将节点值写入变量,然后查看该变量是否为null。这是标准书店xml文件的示例。

[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'
 }
} 

所以对于你的脚本,我认为它可能是

$NodeExists = $null
foreach ($vendor in $xml.Vendors.Vendor| Where-Object  {$_.Type -match "Send"}) {
 $NodeExists = $vendor.EncKey
 if ($NodeExists) {
  # Do something
 }
 else {
  # something else
  }
}

4
2017-12-06 22:49



谢谢Alex。这与我试图做的一致,但如果$ vendor.EncKey不存在,我得到一个例外: 无法在此对象上找到属性“EncKey”。确保它存在。 而且我从未接触过声明中的“其他”部分。 - mack
您可以使用“if($ vendor.EncKey){”来缩短它,这也是不区分大小写的,与SelectSingleNode相比,它对我不起作用。我没有任何异常问题。 - Jay


如果使用,则将$ xml对象作为XmlDocument加载

$xml = new-object System.Xml.XmlDocument
$xml.LoadXml( (get-content $pathToXmlFile) )

然后你可以这样做,这更简单:

if ($vendor.encKey -ne $null) {
  # does exist
} else {
  # does not exist
}

4
2018-05-15 18:20



Downvote因为如果该元素不存在则抛出异常。 - LosManos


使用XPath选择匹配的节点。 InnerText可以搜索 text()。您可以使用 where-object, 要么 ? 太;行为有点不同。没有样本XML,很难更精确。像这样使用XPath,

[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

3
2017-12-06 22:07





看来我使用的是SelectSingleNode的错误语法。这是一个有效的例子。

[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

谢谢大家的帮助。


1
2017-12-09 16:41



根据我的测试,SelectSingleNode区分大小写,除非有办法改变其行为。 - Jay