使用powershell通过xml节点嵌套循环

时间:2016-05-19 06:52:07

标签: xml powershell

我想从xml文件中提取所有窗口和所有视点节点中name-attributes的值。

<?xml version='1.0' encoding='utf-8' ?>
        <workbook>
            <windows>
                <window class='dashboard' name='D1'>
                  <viewpoints>
                    <viewpoint name='V1'> </viewpoint>
                    <viewpoint name='V2'> </viewpoint>
                    <viewpoint name='V3'> </viewpoint>
                </viewpoints>
                </window>
                <window class='dashboard' name='D2'>
                  <viewpoints>
                    <viewpoint name='V10'> </viewpoint>
                    <viewpoint name='V11'> </viewpoint>
                  </viewpoints>
                 </window>
            </windows>
        </workbook>

这是我写的代码:

[XML]$doc = get-content -path 'W:\Demo1.xml'


$objs = @()
$dashboards = $doc.SelectNodes("//window[@class = 'dashboard']")

foreach ($dashboard in $dashboards)
{
   $worksheets = $dashboard.SelectNodes("//viewpoint[@name]")

    foreach ($worksheet in $worksheets)
    {
        $obj = new-object psobject -prop @{Dashboard=$dashboard.name; Worksheet = $worksheet.name}; 
        $objs += $obj;

    }  
 } 

$objs

我的期望:

dashboard   worksheet   
D1          V1
D1          V2
D1          V3
D2          V10
D2          V11

我得到了什么:

dashboard   worksheet   
D1          V1
D1          V2
D1          V3
D1          V10
D1          V11
D1          V14
D2          V1
D2          V2
D2          V3
D2          V10
D2          V11
D2          V14

这里有什么问题?结果与我对嵌套循环如何工作的理解完全矛盾。

2 个答案:

答案 0 :(得分:2)

/字符开头的XPath意味着它将从文档根节点开始。要从上下文节点创建相对XPath,您需要在.之前放置/

所以你的代码应该是:

[XML]$doc = get-content -path 'W:\Demo1.xml'


$objs = @()
$dashboards = $doc.SelectNodes("//window[@class = 'dashboard']")

foreach ($dashboard in $dashboards)
{
   $worksheets = $dashboard.SelectNodes(".//viewpoint[@name]")

    foreach ($worksheet in $worksheets)
    {
        $obj = new-object psobject -prop @{Dashboard=$dashboard.name; Worksheet = $worksheet.name}; 
        $objs += $obj;

    }  
 } 

$objs

答案 1 :(得分:1)

您还可以简化并采用xpath从信息中心窗口中选择所有viewpoint个节点:

[XML]$doc = get-content -path 'W:\Demo1.xml'

$objs = @()
$worksheets = $doc.SelectNodes("//window[@class = 'dashboard']//viewpoint[@name]")

foreach ($worksheet in $worksheets)
{
    $obj = new-object psobject -prop @{Dashboard=$worksheet.ParentNode.ParentNode.name; Worksheet = $worksheet.name}; 
    $objs += $obj;
}  

$objs

这是一个没有xpath的解决方案:

[XML]$doc = get-content -path 'W:\Demo1.xml'

$objs = $doc.DocumentElement.windows.window | Where class -eq 'dashboard' | foreach {
    $dashboardName = $_.name
    $_.viewpoints.viewpoint | foreach {
        new-object psobject -prop @{Dashboard=$dashboardName; Worksheet = $_.name}
    }
}