Function PowerShell更改返回对象';s型

Function PowerShell更改返回对象';s型,function,powershell,powershell-3.0,return-type,powershell-ise,Function,Powershell,Powershell 3.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 defa

我正在使用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
}
现在,我将创建一些类似的函数,因此我想将前3行拆分为一个新函数,这样我就不必到处复制粘贴它们,所以我完成了以下操作:

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仍将其转换为对象数组

如果我没有将Get-XmlNamespaceManager函数返回的值显式强制转换为System.Xml.XmlNamespaceManager,则会从.SelectSingleNode()函数中引发以下错误,因为将错误的数据类型传递到函数的第二个参数中

Cannot find an overload for "SelectSingleNode" and the argument count: "2".

因此,出于某种原因,PowerShell没有维护返回变量的数据类型。我真的很想让它从一个函数中工作,这样我就不必复制粘贴这3行了。如有任何建议,我们将不胜感激。谢谢。

现在的情况是,PowerShell正在将命名空间管理器对象转换为字符串数组

我认为这与PowerShell在沿管道发送对象时“展开”集合的性质有关。我认为PowerShell将为实现IEnumerable的任何类型(具有GetEnumerator方法)执行此操作

作为一种解决方法,您可以使用逗号技巧来防止这种行为,并将对象作为整个集合发送

function Get-XmlNamespaceManager([xml]$XmlDocument, [string]$NamespaceURI = "")
{
    ...
    $xmlNsManager.AddNamespace("ns", $NamespaceURI)
    return ,$xmlNsManager
}

更具体地说,这里发生的情况是,您强键入$FullyQualifiedModelPath的编码习惯试图将Get(对象列表)的结果转换为字符串

[字符串]$foo

将约束变量$foo仅为字符串,无论返回什么。在本例中,您的类型约束微妙地扭曲了返回并使其成为对象[]


另外,看看您的代码,我个人建议您使用selectxml(内置于V2和更高版本中),而不是进行大量手工编码的Xml展开。您可以使用-namespace@{x=“…”}在Select Xml中执行名称空间查询。

那么,您对内置的
Select Xml
cmdlet有什么看法?与它一起使用名称空间非常简单,只需向它传递一个前缀到名称空间映射的哈希表,例如,
$xml | Select xml-XPath'//dns:foo'-namespace@{dns='1〕http://schema.foo.org“}
谢谢Keith,实际上我还没有听说过Select-Xml cmdlet。我宁愿忽略Xml名称空间,因为我不关心它,但不幸的是,正如我在博客()中所讨论的,SelectSingleNode()需要它。使用Select Xml可以解决这个问题吗?
Select Xml
只是调用
SelectSingleNode
SelectNodes
(XmlDocument的)因此它仍然容易受到XML名称空间的影响,这就是@Keith使用
-namespace
参数的原因。顺便说一下,有一种方法可以完全忽略XML名称空间,您只需要以不同的方式编写Xpath。演示了如何执行。他对
$fullyQualifiedModePath
行没有意见。这是一个
[System.Xml.XmlNamespaceManager]$xmlNsManager=
是的,XmlNamespaceManager实现了IEnumerable,因此PowerShell将其视为一个项目序列。使用逗号运算符是解决此特定问题的方法,但是在这种情况下使用
return
(函数的最后一行,因此不需要提前返回)。感谢您的解释。Keith,我传统上是一名C#和.Net程序员,最近才进入PowerShell,所以我仍然有使用return的习惯;另外,我喜欢它使函数返回的内容变得明确/明显。@deadlydog另一个问题是,任何返回值未设置为变量或管道为null的内容都将从函数返回,例如,如果调用XmlDocument。方法,它将返回一个XmlNode对象,该对象将与命名空间管理器对象一起发送,除非您阻止它。@AndyArismendi+1。这就是为什么我通常避免返回,除非我需要在函数的早期退出。即使这样,我也倾向于不使用
return
表单。它对函数返回的内容给出错误的感觉。@AndyArismendi您也可以强制转换为void以抑制方法或Cmdlet的输出,即
[void]$xmlNsManager.AddNamespace(“ns”,$NamespaceURI)