PowerShell更改返回对象的类型

时间:2013-07-06 00:06:43

标签: function powershell powershell-v3.0 return-type powershell-ise

我正在使用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行。任何建议表示赞赏。感谢。

2 个答案:

答案 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 =“...”}进行命名空间查询。