逐节点处理XML,但保留前一个元素的节点属性

时间:2017-01-31 19:30:32

标签: xml powershell

我正在尝试处理XML文件(下面的剪辑),我从元素节点中提取了属性。我还想提取标题值(如果存在),并返回该标题值的所有类型属性" group",但仅当它存在时。我不知道如何做到这一点 - 我可以检索标题值,但无法解决如何仅与"组"它有一个标题值。我确定群组是错误的术语,它几乎就像我想从父节点获取标题,但它不会存储在父节点中。

我已经包含了示例输出,希望能够展示我尝试解释的内容。

$xml = [xml]@"
<document document="test">
  <elements>
    <element type="header">Header1</element>
    <element type="link" title="Title1" />
    <element type="link" title="Title2" />
    <element type="link" title="Title3" />
  </elements>
  <elements>
    <element type="link" title="Title200" />
  </elements>
  <elements>
    <element type="header">Header2</element>
    <element type="link" title="Title300" />
    <element type="link" title="Title301" />
  </elements>
</document>
"@

$objs = @()
$nodes = $xml.SelectNodes("//*[@type]")
foreach ($node in $nodes) {
    #$node.ParentNode.ToString()
    $type = $node.Attributes['type'].value
    if ($type -eq "header") {$header = $node.InnerText}
    $title = $node.Attributes['title'].value
    $obj = New-Object PSObject -Prop @{TYPE=$type;TITLE=$title;HEADER=$header}
    $objs += $obj
}
$header = ""
$objs

我目前得到的输出:

TITLE    HEADER  TYPE
-----    ------  ----
         Header1 header
Title1   Header1 link
Title2   Header1 link
Title3   Header1 link
Title200 Header1 link
         Header2 header
Title300 Header2 link
Title301 Header2 link

我希望输出(Title200没有显示标题):

TITLE    HEADER  TYPE
-----    ------  ----
         Header1 header
Title1   Header1 link
Title2   Header1 link
Title3   Header1 link
Title200         link
         Header2 header
Title300 Header2 link
Title301 Header2 link

2 个答案:

答案 0 :(得分:2)

您没有在每个$header次传递的开始时初始化foreach变量,这导致前一个值保留在内部。试试这个:

$objs = @()
$nodes = $xml.SelectNodes("//*[@type]")
foreach ($node in $nodes) {
    #$node.ParentNode.ToString()
    $header = ""
    $type = $node.Attributes['type'].value
    if ($type -eq "header") {$header = $node.InnerText}
    $title = $node.Attributes['title'].value
    $obj = New-Object PSObject -Prop @{TYPE=$type;TITLE=$title;HEADER=$header}
    $objs += $obj
}
$header = ""
$objs

答案 1 :(得分:0)

我终于解决了这个问题 - 我可以通过引用父节点然后使用SelectSingleNode来检索属性type ='header'的元素来获取“group”的标题。

$xml = [xml]@"
<document document="test">
  <elements>
    <element type="header">Header1</element>
    <element type="link" title="Title1" />
    <element type="link" title="Title2" />
    <element type="link" title="Title3" />
  </elements>
  <elements>
    <element type="link" title="Title200" />
  </elements>
  <elements>
    <element type="header">Header2</element>
    <element type="link" title="Title300" />
    <element type="link" title="Title301" />
  </elements>
</document>
"@

cls

$objs = @()
$nodes = $xml.SelectNodes("//*[@type]")
foreach ($node in $nodes) {
    $header = ""
    $type = $node.Attributes['type'].value
    #using the ParentNode, retrieve the element where the attribute type='header' 
    #and then get the InnerText to get the actual value
    $header = $node.ParentNode.SelectSingleNode("element[@type='header']").InnerText
    $title = $node.Attributes['title'].value
    $obj = New-Object PSObject -Prop @{TYPE=$type;TITLE=$title;HEADER=$header}
    if ($type -ne "header") {
    $objs += $obj
    }
}
$header = ""
$objs

这给出了我正在寻找的输出。可能有更有效的方法,但它确实有效,并有望帮助其他人。

TITLE    HEADER  TYPE
-----    ------  ----
Title1   Header1 link
Title2   Header1 link
Title3   Header1 link
Title200         link
Title300 Header2 link
Title301 Header2 link