【问题标题】:nested loop through xml-nodes using powershell使用powershell通过xml节点嵌套循环
【发布时间】:2016-05-19 15:19:32
【问题描述】:

我想从 xml 文件中提取所有窗口和所有视点节点的名称属性值。

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

我的预期:

仪表板 工作表 D1 V1 D1 V2 D1 V3 D2 V10 D2 V11

我得到了什么:

仪表板 工作表 D1 V1 D1 V2 D1 V3 D1 V10 D1 V11 D1 V14 D2 V1 D2 V2 D2 V3 D2 V10 D2 V11 D2 V14

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

【问题讨论】:

    标签: xml powershell


    【解决方案1】:

    / 字符开头的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
    

    【讨论】:

    • 你拯救了我的一天。谢谢你。我花了几个小时找到错误,它只是缺少一点点......
    【解决方案2】:

    您还可以简化它并采用您的 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}
        }
    }
    

    【讨论】:

    • Upps,你是对的 - 我修正了我的答案(现在使用 ParentNode 属性来获取仪表板)。我还将在几分钟内为您提供一个没有 xpath 的示例。
    • 嗯,$worksheets = $doc.SelectNodes("//window[@class= 'dashboard']//viewpoint[@name]") 行会产生错误。 (从德语翻译:不可能为值为 NULL 的表达式调用方法)
    • @jisaak:谢谢你的第二段代码。我刚试了一下。无论出于何种原因,它什么都不返回。 :-(
    • 我省略了打印结果的$objs,我只将结果分配给它。只需在最后一行写上$objs 即可看到输出。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-01
    • 2021-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多