Perché XDocument.Descendants () ritornano IEnumerator in PowerShell ISE?
-
22-08-2019 - |
Domanda
Sto scrivendo uno script PowerShell per manipolare alcuni Windows Installer XML (WiX). Sto utilizzando le nuove API XML in .NET 3.5 per fare questo, come io trovo un'API più facile da lavorare rispetto al DOM. Il seguente frammento di script è categoricamente rifiuta di lavorare:
[System.Reflection.Assembly]::LoadWithPartialName("System.Xml.Linq") | Out-Null
# Basic idea: Iterate through en.wxl's l10ns, get string for each l10n, search all wxs files for that value.
pushd "C:\temp\installer_l10n"
$wxlFileName = "${pwd}\en.wxl"
$wxl = [System.Xml.Linq.XDocument]::Load($wxlFileName)
$strings = $wxl.Descendants("String")
$strings
$strings | foreach {
$_
}
popd
Lo script dovrebbe uscita ogni
Il documento XML è un file di localizzazione standard di WiX:
<?xml version="1.0" encoding="utf-8" ?>
<WixLocalization Culture="en-US" xmlns="http://schemas.microsoft.com/wix/2006/localization">
<String Id="0">Advertising published resource</String>
<String Id="1">Allocating registry space</String>
...
</WixLocalization>
$ stringhe non è $ null (ho provato in modo esplicito), e se scrivo-host $ WxL, posso vedere che il documento è stato caricato. Tubazioni $ stringhe in Get-Member restituisce un errore che indica che "Nessun oggetto è stato specificato per get-member" e Write-Host $ stringhe non fa nulla. Ho anche provato $ wxl.Descendants ( "WixLocalization") con gli stessi risultati. Cose come $ wxl.Root e $ wxl.Nodes funzionano come previsto. Debug con PowerShell ISE, vedo che $ stringhe è stato impostato su IEnumerator, piuttosto che l'IEnumerable previsto
La cosa strana è che la stessa tecnica ha lavorato in uno script precedente. Lo stesso codice esatto, ma con diversi nomi di variabili e le stringhe letterali. E dopo aver appena provato il debug di script che troppo (per verificare il comportamento), a quanto pare è ora anche la visualizzazione lo stesso comportamento.
Soluzione
Questo problema mi ha incuriosito, così ho fatto qualche ricerca in giro. Dopo un sacco di fare in giro in PowerShell e la ricerca sul web ho trovato la soluzione.
Il credito va a Jamie Thomson per il codice vero e proprio. http://dougfinke.com/blog/ index.php / 2007/08/07 / usando-xmllinq-in-PowerShell /
Il pezzo mancante è quello di gestire lo spazio dei nomi nel file XML. Ecco il codice che dovrebbe funzionare per voi:
[System.Reflection.Assembly]::LoadWithPartialName("System.Xml.Linq") | Out-Null
# Basic idea: Iterate through en.wxl's l10ns, get string for each l10n, search all wxs files for that value.
$wxlFileName = "${pwd}\en.wxl"
$wxl = [System.Xml.Linq.XDocument]::Load($wxlFileName)
$ns = [System.Xml.Linq.XNamespace]”http://schemas.microsoft.com/wix/2006/localization”
$strings = $wxl.Descendants($ns + "String")
foreach ($string in $strings) {
$string
}
Altri suggerimenti
So che hai detto che non preferito lavorare con il DOM, ma c'è alcuna ragione per cui questo non funziona per voi?
[xml]$test = gc .\test.wml
$test
$test.WixLocalization
$test.WixLocalization.String
Questa Uscite:
PS> $ test.WixLocalization.String
Id #text
- -----
0 Advertising risorsa pubblicata
1 Allocare lo spazio di registro
Foreach'ing oltre che non dovrebbe essere troppo difficile a quel punto.