1

Я пишу сценарий PowerShell для управления некоторыми установщиками Windows Installer XML (WiX). Я использую новые XML-API в .NET 3.5 для этого, поскольку я считаю, что это более простой API для работы с DOM. Следующий фрагмент сценария категорически отказывается работать:Почему XDocument.Descendants() возвращает IEnumerator в PowerShell ISE?

[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 

Сценарий должен выход каждого < Строка > тег на отдельной строке. Я собираюсь заставить его сделать что-то более интересное, когда эта ошибка была решена ;-)

документ XML является стандартной локализации 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> 

$ строк не $ нулевой (I» ve явно протестировал его), и если я пишу-хост $ wxl, я вижу, что документ был загружен. Строка $ strings в Get-Member возвращает ошибку, в которой указано, что «No object не был указан для get-member», а строки $ str для записи-хозяина ничего не делают. Я также пробовал $ wxl.Descendants («WixLocalization») с теми же результатами. Такие вещи, как $ wxl.Root и $ wxl.Nodes работают должным образом. Отладка с помощью PowerShell ISE, я вижу, что $ strings был установлен в IEnumerator, а не ожидаемый IEnumerable <XElement>. Тестирование IEnumerator с помощью одного MoveNext, а затем Current указывает, что «Current =», предположительно, $ null.

Странно, что тот же метод работал в предыдущем сценарии. Точный же код, но с разными именами переменных и строковыми литералами. И просто попробовав отладку этого скрипта (чтобы проверить поведение), похоже, что теперь он также демонстрирует то же поведение.

ответ

5

Эта проблема заинтриговала меня, поэтому я немного искал. После того, как в PowerShell появилось много проблем и поиск в Интернете, я нашел ваше решение.

Кредит принадлежит Джейми Томсону за фактический код. http://dougfinke.com/blog/index.php/2007/08/07/using-xmllinq-in-powershell/

Отсутствует деталь для обработки пространства имен в файле XML. Вот код, который должен сработать для вас:

[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 
} 
+0

Спасибо! Я, должно быть, прочитал это сообщение в блоге 100 раз, пока он искал эту статью, и каждый раз пропустил комментарии Джейми Томсона! Кажется, что в PowerShell существует переменная LINQ to XML, поскольку этого не происходит в C#. – alastairs

1

Я знаю, что вы сказали, что предпочитаете не работать с DOM, но есть ли причина, почему это не работает для вас?

[xml]$test = gc .\test.wml                       
$test                            
$test.WixLocalization                        
$test.WixLocalization.String 

Это выходы:

PS> $ test.WixLocalization.String

Id #text
- -----
0 Реклама опубликовал ресурс
1 Выделяя пространство реестра

Предпринимать над этим не должно быть слишком сложно в таком случае.

+0

Благодарим за отзыв. Поскольку это проблема на работе, я попробую, когда вернусь в офис в понедельник. – alastairs

+0

Это действительно работало, хотя я принял другой ответ, поскольку использовал код LINQ, который у меня уже был. – alastairs

Смежные вопросы