Pourquoi est-XDocument.Descendants () retour IEnumerator dans PowerShell ISE?
-
22-08-2019 - |
Question
J'écris un script PowerShell pour manipuler certains Windows Installer XML (WiX). J'utilise les nouvelles API XML dans .NET 3.5 pour ce faire, que je trouve une API plus facile à utiliser que les DOM. Le fragment de script suivant est platement refuse de travailler:
[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
Le script devrait sortie chaque balise
Le document XML est un fichier de localisation norme 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>
chaînes de $ ne sont pas $ null (je l'ai testé explicitement), et si j'écris hôte WXL de $, je peux voir que le document a été chargé. Piping chaînes de $ dans Get-Member retourne une erreur indiquant que « Aucun objet n'a été spécifié pour obtenir-membre » et write-host des chaînes de $ ne fait rien. J'ai aussi essayé $ wxl.Descendants ( « WixLocalization ») avec les mêmes résultats. Des choses comme $ wxl.Root et wxl.Nodes $ fonctionnent comme prévu. Débogage avec PowerShell ISE, je vois que les chaînes $ a été mis à IEnumerator, plutôt que le IEnumerable attendu
La chose étrange est que la même technique a travaillé dans un script précédent. Le même code, mais avec des noms de variables et les littéraux de chaîne. Et juste après avoir essayé de débogage trop (pour vérifier le comportement) ce script, il semble qu'il est l'affichage maintenant le même comportement.
La solution
Ce problème m'a intriguée, donc je fait quelques recherches autour. Après beaucoup de déconner dans PowerShell et recherche sur le Web, j'ai trouvé votre solution.
Le crédit va à Jamie Thomson pour le code réel. http://dougfinke.com/blog/ index.php / 2007/08/07 / utilisant-xmllinq en Powershell /
La pièce manquante est de gérer l'espace de noms dans le fichier XML. Voici le code qui devrait fonctionner pour vous:
[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
}
Autres conseils
Je sais que vous avez dit que vous ne préférions travailler avec les DOM, mais est-il une raison pour laquelle cela ne fonctionne pas pour vous?
[xml]$test = gc .\test.wml
$test
$test.WixLocalization
$test.WixLocalization.String
Sorties:
PS> $ test.WixLocalization.String
Id #text
- -----
0 Publicité ressource publiée
1 espace de registre Allouer
Foreach'ing sur cela ne devrait pas être trop difficile à ce moment-là.