【问题标题】:PowerShell XML select node with namespace具有命名空间的 PowerShell XML 选择节点
【发布时间】:2019-01-24 17:38:03
【问题描述】:

我正在尝试从 XML 文件中选择节点,但遇到的问题似乎是由命名空间引起的。

下面的代码不返回任何内容。但是如果我从 XML 文件中删除命名空间,我会得到预期的结果。

MWE

$StandaloneXML = "test.xml"
# Load XML content
$NewStandaloneXML = New-Object -TypeName "System.XML.XMLDocument"
$NewStandaloneXML.Load($StandaloneXML)
# Get namespace
$Namespace = New-Object -TypeName "Xml.XmlNamespaceManager" -ArgumentList $NewStandaloneXML.NameTable
$Namespace.AddNamespace("jboss", $NewStandaloneXML.DocumentElement.NamespaceURI)
$NewStandaloneXML.SelectNodes("jboss:server/interfaces/interface", $Namespace)

XML

<?xml version="1.0" ?>
<server xmlns="urn:jboss:domain:4.2">
  <interfaces>
      <interface name="management">
          <inet-address value="${jboss.bind.address.management:127.0.0.1}"/>
      </interface>
      <interface name="public">
          <inet-address value="${jboss.bind.address:127.0.0.1}"/>
      </interface>
  </interfaces>
</server>

预期输出

名称 inet 地址 ---- ------------ 管理网络地址 公共网络地址

【问题讨论】:

  • 您必须将命名空间前缀添加到它适用的所有元素:jboss:server/interfaces/interface -> /jboss:server/jboss:interfaces/jboss:interface
  • @AnsgarWiechers 谢谢,那行得通。为什么需要它?没有继承吗?我正在努力寻找有关该主题的全面文档。
  • XML 节点从其父节点继承默认命名空间(并且只有默认命名空间)。然而,XPath 路径元素却没有。您可以通过本地名称 (*[local-name()="nodename"]) 选择节点,但 ns:nodename 的可读性远不止于此,您不觉得吗?另外,related.

标签: xml powershell xpath namespaces xml-namespaces


【解决方案1】:

正如@AnsgarWiechers 所说,每个节点都必须以其命名空间为前缀,因为没有继承。

MWE

$StandaloneXML = "test.xml"
# Load XML content
$NewStandaloneXML = New-Object -TypeName "System.XML.XMLDocument"
$NewStandaloneXML.Load($StandaloneXML)
# Get namespace
$Namespace = New-Object -TypeName "Xml.XmlNamespaceManager" -ArgumentList $NewStandaloneXML.NameTable
$Namespace.AddNamespace("jboss", $NewStandaloneXML.DocumentElement.NamespaceURI)
$NewStandaloneXML.SelectNodes("jboss:server/jboss:interfaces/jboss:interface", $Namespace)

为了方便起见,我构建了一个小函数来自动为提供的XPath 中的每个节点添加前缀。

function Select-XMLNode {
  [CmdletBinding()]
  Param (
    [Parameter (
      Position    = 1,
      Mandatory   = $true,
      HelpMessage = "XML content"
    )]
    [ValidateNotNullOrEmpty()]
    [System.XML.XMLDocument]
    $XML,
    [Parameter (
      Position    = 2,
      Mandatory   = $true,
      HelpMessage = "XPath corresponding to the node"
    )]
    [ValidateNotNullOrEmpty()]
    [String]
    $XPath,
    [Parameter (
      Position    = 3,
      Mandatory   = $false,
      HelpMessage = "Namespace"
    )]
    [ValidateNotNullOrEmpty()]
    [String]
    $Namespace = $XML.DocumentElement.NamespaceURI
  )
  Begin {
    # Variables
    $Delimiter          = "/"
    $Alias              = "x"
    $SpecialCharacters  = [RegEx]::New('^[/.@]*')
    if ($XPath -match $SpecialCharacters) {
      $Prefix = $Matches[0]
      $XPath  = $XPath -replace $SpecialCharacters, ''
    }
  }
  Process {
    # Get namespace
    $NamespaceManager = New-Object -TypeName "Xml.XmlNamespaceManager" -ArgumentList $XML.NameTable
    $NamespaceManager.AddNamespace($Alias, $Namespace)
    # Split XPath to identify nodes
    $Nodes = $XPath.Split($Delimiter)
    $PrefixedNodes = New-Object -TypeName "System.Collections.ArrayList"
    # Prefix nodes with namespace (alias)
    foreach($Node in $Nodes) {
      if ($Node) {
        [Void]$PrefixedNodes.Add("${Alias}:${Node}")
      }
    }
    # Join prefixed-nodes to create new XPath with namespace
    $XPathWithNamespace = $PrefixedNodes -join $Delimiter
    # Check XPath prefix
    if ($Prefix) {
      $XPathWithNamespace = $Prefix + "" + $XPathWithNamespace
    }
    # Select and return nodes
    $SelectedNodes = $XML.SelectNodes($XPathWithNamespace, $NamespaceManager)
    return $SelectedNodes
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-30
    • 2010-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-27
    相关资源
    最近更新 更多