powershell functions




PowerShell cambia el tipo de objeto de retorno (2)

Estoy usando PowerShell v3 y el ISE de Windows PowerShell. Tengo la siguiente función que funciona bien:

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
}

Ahora, voy a crear algunas funciones similares, por lo que quiero dividir las primeras 3 líneas en una nueva función para que no tenga que copiarlas y pegarlas en todas partes, así que he hecho esto:

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
}

El problema es que cuando "return $ xmlNsManager" ejecuta el siguiente error se produce:

Cannot convert the "System.Object[]" value of type "System.Object[]" to type "System.Xml.XmlNamespaceManager".

Entonces, aunque he convertido explícitamente mis variables $ xmlNsManager para que sean del tipo System.Xml.XmlNamespaceManager, cuando se devuelve de la función Get-XmlNamespaceManager, PowerShell lo está convirtiendo en una matriz de objetos.

Si no emito explícitamente el valor devuelto por la función Get-XmlNamespaceManager a System.Xml.XmlNamespaceManager, entonces se produce el siguiente error desde la función .SelectSingleNode () porque el tipo de datos incorrecto se pasa al segundo parámetro de la función.

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

Por alguna razón, PowerShell no mantiene el tipo de datos de la variable de retorno. Realmente me gustaría que esto funcione desde una función para no tener que copiar y pegar esas 3 líneas por todas partes. Cualquier sugerencia es apreciada. Gracias.


Lo que sucede es que PowerShell está convirtiendo su objeto de administrador de espacio de nombres en una matriz de cadenas.

Creo que tiene que ver con la naturaleza de PowerShell de las colecciones "desenrolladas" cuando se envían objetos por la tubería. Creo que PowerShell hará esto para cualquier tipo de implementación de IEnumerable (tiene un método GetEnumerator).

Como solución, puede utilizar el truco de coma para evitar este comportamiento y enviar el objeto como una colección completa.

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

Más específicamente, lo que está sucediendo aquí es que su hábito de codificación de escribir con fuerza $ fullQualifiedModePath está tratando de convertir el resultado de Get (que es una lista de objetos) en una cadena.

[string] $ foo

restringirá la variable $ foo para que sea solo una cadena, sin importar lo que haya regresado. En este caso, su restricción de tipo es lo que sutilmente arruina la devolución y la convierte en Objeto []

Además, mirando su código, personalmente recomendaría que utilice Select-Xml (integrado en V2 y versiones posteriores), en lugar de hacer muchos desenrollamientos XML codificados a mano. Puede hacer consultas de espacio de nombres en Select-Xml con -Namespace @ {x = "..."}.





powershell-ise