我正在尝试使用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
我正在尝试将"最大检查计划尝试"值设置为 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>
看起来你遇到了一些问题。
-
第一个是示例 xml 中的简单拼写错误 - 您的结束
</DpoSettings>
与您的开头<RubySettings>
不匹配。 -
第二个问题是 xml 文档中定义的命名空间前缀(例如,
<Settings>
元素xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays"
中的a
前缀(不会导入到代码中。换句话说,a:KeyValueOfstringstring
中的a:
在 XPath 查询中没有任何意义,除非您做一些额外的工作来重新定义代码中的a:
前缀。 -
第三,您的 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 问题的一部分 - 即您需要在 XPath 中包含根RubySettings
才能找到Settings
节点,并使用适当的前缀。
那是:
$ScheduleMaintenance = 'x:RubySettings/x:Settings/a:KeyValueOfstringstring'
此时,您可以使用 XPath 执行一些巧妙的操作,以查找具有带有文本MaximumCheckForScheduleAttempts
的子Key
元素的单个节点:
$ScheduleMaintenance = "x:RubySettings/x:Settings/a:KeyValueOfstringstring/a:Key[text()='MaximumCheckForScheduleAttempts']/.."
但是在所有a:KeyValueOfstringstring
节点上使用PowerShell的where-object
可能更容易:
$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)
希望这有帮助。