【问题标题】:Powershell xml select node based on parent's infoPowershell xml根据父信息选择节点
【发布时间】:2018-12-24 03:38:05
【问题描述】:

我正在编写一个 powershell 脚本,我需要根据父母的信息(属性名称、id ......)获取节点的一些值

例子:

<?xml version="1.0" encoding="UTF-8"?>
<GrandParent>
    <Parent id="1">
        <foo></foo>
        <bar></bar>
        <buzz></buzz>
        <Child Name="correct">
            <Content>Value1</Content>
        </Child>
        <Child Name="wrong">
            <Content>Value2</Content>
        </Child>
        <Child Name="wrong">
            <Content>Value3</Content>
        </Child>
    </Parent>
    <Parent id="2">
        <foo></foo>
        <bar></bar>
        <buzz></buzz>
        <Child Name="correct">
            <Content>Value4</Content>
        </Child>
        <Child Name="wrong">
            <Content>Value5</Content>
        </Child>
        <Child Name="wrong">
            <Content>Value6</Content>
        </Child>
    </Parent>
    <Parent id="3">
        <foo></foo>
        <bar></bar>
        <buzz></buzz>
        <Child Name="correct">
            <Content>Value7</Content>
        </Child>
        <Child Name="wrong">
            <Content>Value8</Content>
        </Child>
        <Child Name="wrong">
            <Content>Value9</Content>
        </Child>
    </Parent>
</GrandParent>

我想得到一些输出,例如: 父 1:值 1 父 2:值 4 父级 3:值 7

说明:对于每个父节点,我想查看具有“正确”名称的“子”节点并获取其子节点的值

我在 ForEach-Object 中使用 ForEach-Object 进行循环,但我的上下文“$_”总是指整个 xml 而不是当前范围:

$total_xml.GrandParent.Parent | ForEach-Oject {
   $_.Parent.Child | ForEach-Object{
      $_ #This refers back to the total_xml
   }
}

PS:我是 Powershell 脚本的新手 :(

有人可以帮我写一个简单的脚本吗?

【问题讨论】:

  • 查看the -PipelineVariable common parameter。你也在看错误的东西。您的第一个foreach 应该是$_.Child,因为$_ 指的是Parent 节点,然后您的第二个foreach 将指向该Parent 内的每个Child 节点。

标签: xml powershell foreach


【解决方案1】:

以你为例:

[xml] $xml = Get-Content -Path .\test.xml

你可以得到你想要的输出:

Parent 1: value1
Parent 2: value4
Parent 3: value7

像这样:

$Parents = @($xml.GrandParent.Parent)
for ($i = 0; $i -lt $Parents.Count; $i++) {
    "Parent ${i}: " + @($Parents[$i].Child).Where{$_.Name -eq 'Correct'}.Content
}

或者使用ForEach-Object(没注意到父母有id):

$xml.GrandParent.Parent |
    ForEach-Object {
        "Parent $($_.id): " + @($_.Child).Where{$_.Name -eq 'Correct'}.Content
    }

【讨论】:

  • @JavascriptDeveloper 这很明确,所以我可以使用Where 数组方法。您也可以在要过滤的管道中将对象传递给Where-Object$_.Child | Where-Object Name -eq 'Correct'
【解决方案2】:

这不是最佳做法,但我喜欢它,因为它易于阅读。

$xml = new-object -typename xml
$xml.Load("C:\temp\le.xml")
#To get stuff
$xml.GrandParent.Parent | Where-Object {$_.id -like 1}
#To edit stuff
($xml.GrandParent.Parent | Where-Object {$_.id -like 1}).foo = "test"
#To save stuff
$xml.Save("C:\temp\le.xml")

【讨论】:

  • 虽然此代码可以回答问题,但提供有关 如何为什么 解决问题的附加上下文将提高​​答案的长期价值。
  • 嗯有什么建议吗?
  • @Xiakit 的建议是:添加有关 如何为什么 解决问题的附加上下文。这适用于您提供的所有答案(作为最佳实践)
猜你喜欢
  • 2021-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-10
相关资源
最近更新 更多