首页 > 解决方案 > 使用 powershell 解析 XML 会给出“需要命名空间管理器或 XsltContext”错误

问题描述

我正在尝试使用 powershell 解析以下 xml。下面是我的代码,结果给出

使用“1”参数调用“SelectSingleNode”的异常:“需要命名空间管理器或 XsltContext。此查询具有前缀、变量或用户定义的函数。

如何使用 powershell 脚本解析这个 XML?

代码:

$webConfig = "Rubyconf.config"
$XmlObj = New-Object XML
$XmlObj.Load($webConfig)
$ScheduleMaintenance = 'Settings/a:KeyValueOfstringstring'
$Xmlnode = $XmlObj.SelectSingleNode($ScheduleMaintenance)
Write-Output $Xmlnode

我正在尝试将“MaximumCheckForScheduleAttempts”值设置为 10。有人可以帮我解决这个问题吗?

XML 文件

<RubySettings xmlns="http://schemasxxxxxx" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
    <Settings xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
        <a:KeyValueOfstringstring>
            <a:Key>LiveMaximumNumberParallelModelExecutions</a:Key>
            <a:Value>7</a:Value>
        </a:KeyValueOfstringstring>        
        <a:KeyValueOfstringstring>
            <a:Key>ModelCompilationTimeout</a:Key>
            <a:Value>00:02:00.0000000</a:Value>
        </a:KeyValueOfstringstring>
        <a:KeyValueOfstringstring>
            <a:Key>MaximumCheckForScheduleAttempts</a:Key>
            <a:Value>5</a:Value>
        </a:KeyValueOfstringstring>
        <a:KeyValueOfstringstring>
            <a:Key>ExternalCalloutPermitted</a:Key>
            <a:Value>true</a:Value>
        </a:KeyValueOfstringstring>
        <a:KeyValueOfstringstring>
            <a:Key>ExternalCalloutTimeout</a:Key>
            <a:Value>00:00:00.2000000</a:Value>
        </a:KeyValueOfstringstring>
    </Settings>
<lastChanged>2019-12-02T15:36:48.513Z</lastChanged>
</DpoSettings>

标签: xmlpowershell

解决方案


看起来你遇到了一些问题。

  • 第一个是您的示例 xml 中的一个简单错字 - 您的 close</DpoSettings>与您的 opening 不匹配<RubySettings>

  • 第二个问题是在 xml 文档中定义的名称空间前缀(例如,来自您的元素的a前缀)不会被导入到您的代码中。换句话说,除非您做一些额外的工作来重新定义代码中的前缀,否则您的 in your在 XPath 查询中没有任何意义。xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays"<Settings>a:a:KeyValueOfstringstringa:

  • 第三,您的 XPath 查询Settings/a:KeyValueOfstringstring有点不稳定

无效的 xml

这是一个简单的修复 - 如果我们假设结束元素应该​​是</RubySettings>我们可以克服这个,然后我们可以重现您报告的错误。

<RubySettings xmlns="http://schemasxxxxxx" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
...
</DpoSettings>

变成

<RubySettings xmlns="http://schemasxxxxxx" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
...
</RubySettings>

命名空间前缀

要解决第二个问题(以及您的错误消息),您需要做的是创建一个XmlNamespaceManager来定义您自己的命名空间前缀,这些前缀可能(或可能不匹配)原始 xml 文档中的前缀,然后在您的 XPath 查询:

$webConfig = "Rubyconf.config"
$XmlObj = New-Object XML
$XmlObj.Load($webConfig)

# create namespace prefixes
$nametable = new-object System.Xml.NameTable;
$nsmgr = new-object System.Xml.XmlNamespaceManager($nametable);
$nsmgr.AddNamespace("x", "http://schemasxxxxxx");
$nsmgr.AddNamespace("a", "http://schemas.microsoft.com/2003/10/Serialization/Arrays");

# now we can use x: and a:
$ScheduleMaintenance = 'x:RubySettings/x:Settings/a:KeyValueOfstringstring'

# note the $nsmgr parameter which maps "a:" in the xpath query to the actual namespace
# "http://schemas.microsoft.com/2003/10/Serialization/Arrays" in the xml document
$Xmlnode = $XmlObj.SelectSingleNode($ScheduleMaintenance, $nsmgr)

Write-Output $Xmlnode

# Key                                      Value
# ---                                      -----
# LiveMaximumNumberParallelModelExecutions 7

请注意,前缀名称a与原始 xml 文档中的名称匹配,但我们可以很容易地说出类似的内容:

...
$nametable = new-object System.Xml.NameTable;
$nsmgr = new-object System.Xml.XmlNamespaceManager($nametable);
$nsmgr.AddNamespace("default", "http://schemasxxxxxx");
$nsmgr.AddNamespace("arrays", "http://schemas.microsoft.com/2003/10/Serialization/Arrays");

$ScheduleMaintenance = 'default:RubySettings/default:Settings/arrays:KeyValueOfstringstring'
...

并且只要 XPath 字符串中的前缀与 XmlNamespaceManager 中的前缀匹配,一切都会正常工作。

现在我们已经完成了所有这些工作,我们可以细化 XPath 查询以选择我们真正感兴趣的节点。

XPath 查询

注意 - 上面的代码还修复了 XPath 问题的一部分 - 即您需要RubySettings在 XPath 中包含根才能找到Settings节点,并使用适当的前缀。

那是:

$ScheduleMaintenance = 'x:RubySettings/x:Settings/a:KeyValueOfstringstring'

此时,您可以使用 XPath 做一些巧妙的事情来找到Key带有 text 子元素的单个节点MaximumCheckForScheduleAttempts

$ScheduleMaintenance = "x:RubySettings/x:Settings/a:KeyValueOfstringstring/a:Key[text()='MaximumCheckForScheduleAttempts']/.."

where-object在所有a:KeyValueOfstringstring节点上使用 PowerShell 可能更容易:

$ScheduleMaintenance = "x:RubySettings/x:Settings/a:KeyValueOfstringstring"
$Xmlnodes = $XmlObj.SelectNodes($ScheduleMaintenance, $nsmgr)
$Xmlnode = $xmlnodes | where-object { $_.Key -eq "MaximumCheckForScheduleAttempts" }

注意 - 我们使用SelectNodes而不是SelectSingleNode然后使用 PowerShell 来过滤结果。

更新值

最后,您可以更新节点的值:

$Xmlnode.Value = "10" # value has to be a string

然后保存xml文档

$XmlObj.Save($newFilename)

希望这可以帮助。


推荐阅读