为什么XDocument.Descendants()在PowerShell ISE中返回IEnumerator?

时间:2009-02-06 17:16:14

标签: xml powershell linq-to-xml powershell-v2.0 powershell-ise

我正在编写一个PowerShell脚本来操作一些Windows Installer XML(WiX)。我正在使用.NET 3.5中的新XML API来实现这一点,因为我发现它比DOM更容易使用API​​。以下脚本片段断然拒绝工作:

[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

脚本应该输出每个< String>标记在一个单独的行上。一旦这个bug得到解决,我就会让它做一些更有趣的事情; - )

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>

$ strings不是$ null(我已经明确地测试了它),如果我写了host-wxl,我可以看到文件已被加载。将$字符串管理到Get-Member会返回一个错误,指出“没有为get-member指定任何对象”,write-host $字符串不执行任何操作。我也尝试过$ wxl.Descendants(“WixLocalization”),结果相同。像$ wxl.Root和$ wxl.Nodes这样的东西按预期工作。使用PowerShell ISE进行调试,我看到$ strings已设置为IEnumerator,而不是预期的IEnumerable&lt; XElement&gt;。使用单个MoveNext测试IEnumerator,然后使用Current测试“Current =”,大概是$ null。

奇怪的是,相同的技术在之前的脚本中有效。完全相同的代码,但具有不同的变量名和字符串文字。刚刚尝试调试该脚本(以验证行为),它似乎现在也显示相同的行为。

2 个答案:

答案 0 :(得分:5)

这个问题引起了我的兴趣,所以我做了一些搜索。经过PowerShell中的大量搜索和搜索网络后,我找到了解决方案。

感谢Jamie Thomson提供的实际代码。 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
}

答案 1 :(得分:1)

我知道你说你不喜欢不使用DOM,但是有什么理由说这不适合你吗?

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

输出:

PS&GT; $ test.WixLocalization.String

Id #text
- -----
0广告发布资源
1分配注册表空间

此时的预告不应该太难。