按层次结构中的位置而不是名称从 XML 文件中提取元素

Extract an element from an XML file by position in the hierarchy rather than by name

我有一个这样的 XML 文件 :

<note>
  <to>Tove</to>
  <from>Jani</from>
  <heading>Reminder</heading>
  <body>Don't forget me this weekend!</body>
</note>

我有这样的 Powershell 脚本:

$xmlData = New-Object -TypeName System.Xml.XmlDocument
$xmlData.Load('c:\test\data.xml')
$xmlData.note.body # I want to remove "note.body" to change to use function

我能否在不必使用元素 names 的情况下获取当前元素 note.body 的值,即,我能否通过目标元素的 在文档层次结构中的位置?

我们的想法是让脚本即使在输入 XML 中的元素名称发生变化(但不是文档的 结构 )后仍能继续工作。

如果您想按位置定位感兴趣的元素,请使用通用XML DOM 属性:

PowerShell Core:

# Extract the text from the *last child* of the *document element*.
# This is the positional equivalent of your $xmlData.note.body call.
# Of course, you can use specific indices such as [2] as well.
$xmlData.DocumentElement.ChildNodes[-1].InnerText

对于您的示例文档,输出是 Don't forget me this weekend!,正如预期的那样。


Windows PowerShell 中(所有解决方法也适用于 PowerShell Core):

一个 bug 阻止使用 [-1] 来引用 last 在这种情况下是集合的元素。

解决方法 1:

$childNodes = $xmlData.DocumentElement.ChildNodes  
$childNodes[$childNodes.Count-1].InnerText

解决方法 2

您提出了以下备选方案,它更简单,但效率较低(可能无关紧要):

使用member-access enumeration从前面的所有个子节点中提取.InnerText值——returns一个常规的PowerShell数组——并应用[-1]:

$xmlData.DocumentElement.ChildNodes.InnerText[-1]

解决方法 3,由 Tomalak:

提出
$xmlData.DocumentElement.ChildNodes |
  Select-Object -Last 1 -ExpandProperty InnerText

Select-Object -Last 1 确实成功提取了最后一个子元素,-ExpandProperty InnerText 然后 returns .InnerText 属性 值。

请注意,由于在管道中使用了 cmdlet,此解决方案通常在变通方案中表现最差,不过,这在实践中可能并不重要,除非您在循环中调用此代码高迭代次数。