我正在使用PowerShell v3和Windows PowerShell ISE。我有以下功能可以正常工作:
function Get-XmlNode([xml]$XmlDocument, [string]$NodePath, [string]$NamespaceURI = "", [string]$NodeSeparatorCharacter = '.')
{
# If a Namespace URI was not given, use the Xml document's default namespace.
if ([string]::IsNullOrEmpty($NamespaceURI)) { $NamespaceURI = $XmlDocument.DocumentElement.NamespaceURI }
# In order for SelectSingleNode() to actually work, we need to use the fully qualified node path along with an Xml Namespace Manager, so set them up.
[System.Xml.XmlNamespaceManager]$xmlNsManager = New-Object System.Xml.XmlNamespaceManager($XmlDocument.NameTable)
$xmlNsManager.AddNamespace("ns", $NamespaceURI)
[string]$fullyQualifiedNodePath = Get-FullyQualifiedXmlNodePath -NodePath $NodePath -NodeSeparatorCharacter $NodeSeparatorCharacter
# Try and get the node, then return it. Returns $null if the node was not found.
$node = $XmlDocument.SelectSingleNode($fullyQualifiedNodePath, $xmlNsManager)
return $node
}
现在,我将创建一些类似的函数,所以我想将前三行分解为一个新函数,这样我就不必将它们复制粘贴到任何地方,所以我这样做了:
function Get-XmlNamespaceManager([xml]$XmlDocument, [string]$NamespaceURI = "")
{
# If a Namespace URI was not given, use the Xml document's default namespace.
if ([string]::IsNullOrEmpty($NamespaceURI)) { $NamespaceURI = $XmlDocument.DocumentElement.NamespaceURI }
# In order for SelectSingleNode() to actually work, we need to use the fully qualified node path along with an Xml Namespace Manager, so set them up.
[System.Xml.XmlNamespaceManager]$xmlNsManager = New-Object System.Xml.XmlNamespaceManager($XmlDocument.NameTable)
$xmlNsManager.AddNamespace("ns", $NamespaceURI)
return $xmlNsManager
}
function Get-XmlNode([xml]$XmlDocument, [string]$NodePath, [string]$NamespaceURI = "", [string]$NodeSeparatorCharacter = '.')
{
[System.Xml.XmlNamespaceManager]$xmlNsManager = Get-XmlNamespaceManager -XmlDocument $XmlDocument -NamespaceURI $NamespaceURI
[string]$fullyQualifiedNodePath = Get-FullyQualifiedXmlNodePath -NodePath $NodePath -NodeSeparatorCharacter $NodeSeparatorCharacter
# Try and get the node, then return it. Returns $null if the node was not found.
$node = $XmlDocument.SelectSingleNode($fullyQualifiedNodePath, $xmlNsManager)
return $node
}
问题是当“return $ xmlNsManager”执行时抛出以下错误:
Cannot convert the "System.Object[]" value of type "System.Object[]" to type "System.Xml.XmlNamespaceManager".
所以即使我已经显式地将我的$ xmlNsManager变量强制转换为System.Xml.XmlNamespaceManager类型,当它从Get-XmlNamespaceManager函数返回时,PowerShell会将其转换为Object数组。
如果我没有显式地将从Get-XmlNamespaceManager函数返回的值强制转换为System.Xml.XmlNamespaceManager,则会从.SelectSingleNode()函数抛出以下错误,因为错误的数据类型正在传递给函数的第二个参数。
Cannot find an overload for "SelectSingleNode" and the argument count: "2".
因此,PowerShell没有维护返回变量的数据类型。我真的希望通过一个函数来实现这个功能,这样我就不必在这个地方复制粘贴这3行。任何建议表示赞赏。感谢。
答案 0 :(得分:26)
正在发生的事情是PowerShell正在将您的名称空间管理器对象转换为字符串数组。
我认为这与PowerShell在向管道中发送对象时“展开”集合的性质有关。我认为PowerShell将为任何实现IEnumerable的类型执行此操作(具有GetEnumerator方法)。
作为一种解决方法,您可以使用逗号技巧来防止此行为并将对象作为整个集合发送。
function Get-XmlNamespaceManager([xml]$XmlDocument, [string]$NamespaceURI = "")
{
...
$xmlNsManager.AddNamespace("ns", $NamespaceURI)
return ,$xmlNsManager
}
答案 1 :(得分:1)
更具体地说,这里发生的是强烈输入$ fullQualifiedModePath的编码习惯是试图将Get(对象列表)的结果转换为字符串。
[string] $ foo
无论回来什么,都会将变量$ foo限制为只是一个字符串。在这种情况下,您的类型约束是巧妙地搞砸了返回并使其成为Object []
另外,看看你的代码,我个人建议你使用Select-Xml(内置于V2及更高版本),而不是进行大量的手工编码XML展开。您可以在Select-Xml中使用-Namespace @ {x =“...”}进行命名空间查询。