使用 Powershell 解析 XML 以在被子节点屏蔽时获取 .Name 属性 的值

Parse XML with Powershell to get value of .Name property when masked by child node

在 Powershell 中,当 XML 元素有一个名为 'Name' 的子节点时,我如何获取其 .Name 属性 的值,该子节点掩盖了 属性.

# Assign XML that contains an element called 'Name' deliberately
# to mask the .Name property on the parent element.
$xml = [xml]@"
<People>
    <Person>
        <Name>Jo Bloggs</Name>
   </Person>
</People>
"@

Write-Host $xml.People.FirstChild.Name
# > Jo Bloggs
#Expect to get the .Name property of the <Person> element but instead
# we get the 'Name' child node text.

# Use XML that doesn't mask the .Name property
$xml = [xml]@"
<People>
    <Person>
        <FullName>Jo Bloggs</FullName>
   </Person>
</People>
"@

Write-Host $xml.People.FirstChild.Name
# > Person
# We now get what we originally expected, the value of the .Name
# property of the Person element itself.

当然,我可以调用 Person 元素的 .LocalName 属性 并得到预期的结果,但这不是通用解决方案,就好像 Person 元素有一个 LocalName 子元素一样,那也是蒙面

更新 2021-08-26:此后我发现了这个与我的问题非常相似的 SO 问题,并提供了一些详细的答案。

我认为在这种情况下没有办法告诉 PowerShell 优先考虑隐藏属性,但我很高兴被证明是错误的。

您可以遍历 XPathNavigator 并评估 XPath 字符串。这个

# or:  [System.Xml.XPath.XPathDocument]::new("C:\Path\to\the\file.xml")
$doc = [System.Xml.XPath.XPathDocument]::new([System.IO.StringReader]::new(@"
<People>
    <Person>
        <Name>Jo Bloggs</Name>
   </Person>
</People>
"@))

$xpath = $doc.CreateNavigator()
$xpath.Evaluate("name(/People/*[1])")

将打印 Person.

根据这个问答

and

下面的行将获得内在的 .Name 属性 而不是装饰的 Powershell 属性.

$xml.People.FirstChild.get_Name()

更完整的解决方案演示为:

# Assign XML that contains an element called 'Name' deliberately
# to have Powershell decorate and thererfore Shadow the intrinsic 
# .Name property on the parent element.
$xml = [xml]@"
<People>
    <Person>
        <Name>Jo Bloggs</Name>
   </Person>
</People>
"@

# Solution to avoid issues with collision between decorated
# properties which shadow intrinsic element properties is to
# use the .get_<property-name>() method.
#
# In this case, .get_Name() should always return the intrinsic
# element property, and never the Powershell decorated property.
Write-Host $xml.People.FirstChild.get_Name()

# > Person
# This works