以空的SelectNodes集为条件

时间:2018-12-27 11:54:43

标签: powershell xpath

给出这样的XML

<?xml version="1.0"?>
<Definitions>
    <Products>
        <Product_Group id="Revit">
            <Product id="RVT2017">
                <RSAccelerator>RSACCELERATOR2017</RSAccelerator>
                <ShortcutPath os="6.0 6.1">C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Autodesk\Revit 2017</ShortcutPath>
                <ShortcutPath os="6.2 6.3 10.0">C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Revit 2017</ShortcutPath>
            </Product>
        </Product_Group>
    </Products>
</Definitions>

我想测试OS属性的存在,以便当有两个节点通过该属性值与完全没有属性进行区分时,我可以以不同的方式处理该值。

我以为这可以正常工作,并为两个变量设置适当的值。

if ($script:pxResources.SelectNodes("//Product[@id='$product']/$resource[@os]")) {

但是,即使没有选择任何节点,这也将返回true。我可以使用

if ($script:pxResources.SelectNodes("//Product[@id='$product']/$resource[@os]").count -gt 0) {

但是看起来很笨拙。有没有更好的方法来解决这个问题,还是测试空集是唯一的选择?

2 个答案:

答案 0 :(得分:1)

AFAIK,您将始终必须进行测试,因为 SelectNodes 将返回 System.Xml.XPathNodeList 对象,即使PowerShell将其视为真实对象是空的。

同意添加一些代码进行测试并不是一件容易的事,但是AFAIK是必须的。

我首选的方法是 IsNullOrEmpty

[String]::IsNullOrEmpty(<thing>)

# example
$exp = $script:pxResources.SelectNodes("//Product[@id='$product']/$resource[@os]")
if (-not [String]::IsNullOrEmpty($exp)) {# do something}

答案 1 :(得分:0)

There's a;so the approach where you don't use XPath:

[xml]$xml = @"
<?xml version="1.0"?>
<Definitions>
    <Products>
        <Product_Group id="Revit">
            <Product id="RVT2017">
                <RSAccelerator>RSACCELERATOR2017</RSAccelerator>
                <ShortcutPath os="6.0 6.1">C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Autodesk\Revit 2017</ShortcutPath>
                <ShortcutPath os="6.2 6.3 10.0">C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Revit 2017</ShortcutPath>
                <ShortcutPath os="">C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Anything\Revit 2017</ShortcutPath>
                <ShortcutPath>C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Something\Revit 2017</ShortcutPath>
            </Product>
        </Product_Group>
    </Products>
</Definitions>
"@

$product  = "RVT2017"
$resource = "ShortcutPath"

($xml.Definitions.Products.Product_Group.Product | Where-Object { $_.id -eq $product }).$resource | ForEach-Object {
    if ($null -eq $_.os) { 
        Write-Host "'os' attribute missing on $_"
    }
    elseif ([string]::IsNullOrWhiteSpace($_.os)) { 
        Write-Host "'os' attribute empty on element $($_.outerXml)"
    }
    else { 
        Write-Host "'os' = $($_.os) on element $($_.outerXml)"
    }
}

This will output

'os' = 6.0 6.1 on element <ShortcutPath os="6.0 6.1">C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Autodesk\Revit 2017</ShortcutPath>
'os' = 6.2 6.3 10.0 on element <ShortcutPath os="6.2 6.3 10.0">C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Revit 2017</ShortcutPath>
'os' attribute empty on element <ShortcutPath os="">C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Anything\Revit 2017</ShortcutPath>
'os' attribute missing on C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Something\Revit 2017