【问题标题】:Why is XDocument.Descendants() returning IEnumerator in PowerShell ISE?为什么 XDocument.Descendants() 在 PowerShell ISE 中返回 IEnumerator?
【发布时间】:2010-10-05 23:49:08
【问题描述】:

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

[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>

$strings 不是 $null(我已经明确测试过),如果我写主机 $wxl,我可以看到文档已经加载。将 $strings 导入 Get-Member 会返回一个错误,指出“没有为 get-member 指定对象”并且 write-host $strings 什么也不做。我也试过 $wxl.Descendants("WixLocalization") 得到相同的结果。 $wxl.Root 和 $wxl.Nodes 之类的东西按预期工作。使用 PowerShell ISE 进行调试时,我看到 $strings 已设置为 IEnumerator,而不是预期的 IEnumerable。使用单个 MoveNext 和 Current 测试 IEnumerator 指示“Current =”,大概是 $null。

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

【问题讨论】:

    标签: xml powershell linq-to-xml powershell-2.0 powershell-ise


    【解决方案1】:

    这个问题引起了我的兴趣,所以我做了一些搜索。在 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
    }
    

    【讨论】:

    • 谢谢!在谷歌搜索时,我一定已经阅读了该博客文章 100 次,并且每次都错过了 Jamie Thomson 的 cmets!似乎是 PowerShell 中 LINQ to XML 的变幻莫测,因为这在 C# 中不会发生。
    【解决方案2】:

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

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

    这个输出:

    PS> $test.WixLocalization.String

    ID #文本
    -- -----
    0 广告发布资源
    1 分配注册表空间

    在那个时候,解决这个问题应该不会太难。

    【讨论】:

    • 感谢您的回复。由于这是工作上的问题,我会在星期一回到办公室时尝试一下。
    • 这确实有效,尽管我接受了另一个答案,因为它使用了我已经拥有的 LINQ 代码。
    猜你喜欢
    • 2011-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-10
    • 2020-11-28
    • 2012-06-07
    相关资源
    最近更新 更多