PowerShellv3とWindowsPowerShellISEを使用しています。私はうまく機能する次の関数を持っています:
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に明示的にキャストしないと、関数の2番目のパラメーターに間違ったデータ型が渡されるため、.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
}
より具体的には、ここで起こっていることは、$ fullyQualifiedModePathを強く入力するコーディング習慣がGetの結果(オブジェクトのリスト)を文字列に変換しようとしていることです。
[文字列] $ foo
何が戻ってきても、変数$ fooを文字列のみに制約します。この場合、型の制約は、リターンを微妙に台無しにしてObject []にしているものです。
また、コードを見ると、手作業でコーディングされたXMLを大量に展開するのではなく、Select-Xml(V2以降に組み込まれている)を使用することを個人的にお勧めします。 Select-Xmlで-Namespace @ {x = "..."}を使用して名前空間クエリを実行できます。