PowerShell меняет тип возвращаемого объекта
Я использую 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 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 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() выдается следующая ошибка, поскольку в функцию передается неправильный тип данных 2-й параметр.
Cannot find an overload for "SelectSingleNode" and the argument count: "2".
Поэтому по какой-то причине PowerShell не поддерживает тип данных возвращаемой переменной. Я бы очень хотел, чтобы эта работа работала от функции, так что мне не нужно копировать эти 3 строки по всему месту. Любые предложения приветствуются. Спасибо.
Ответы
Ответ 1
Что происходит, PowerShell преобразует ваш объект управления пространством имен в массив строк.
Я думаю, что это связано с природой PowerShell "разворачивания" коллекций при отправке объектов по конвейеру. Я думаю, что PowerShell сделает это для любого типа, реализующего IEnumerable (имеет метод GetEnumerator).
В качестве работы вы можете использовать трюк с запятой, чтобы предотвратить это поведение и отправить объект как целую коллекцию.
function Get-XmlNamespaceManager([xml]$XmlDocument, [string]$NamespaceURI = "")
{
...
$xmlNsManager.AddNamespace("ns", $NamespaceURI)
return ,$xmlNsManager
}
Ответ 2
Более конкретно, что здесь происходит, так это то, что ваша привычка кодирования для строгого ввода $fullQualifiedModePath пытается превратить результат Get (который представляет собой список объектов) в строку.
[string] $foo
будет ограничивать переменную $foo только строкой, независимо от того, что вернулось. В этом случае ваше ограничение типа - это то, что тонко прикручивает возврат и делает его Object []
Кроме того, глядя на ваш код, я лично рекомендую вам использовать Select-Xml (встроенный в V2 и более поздние версии), а не делать много ручного разметки XML. Вы можете делать запросы пространства имен в Select-Xml с -Namespace @{x = "..." }.