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

发布于 2024-07-13 10:57:10 字数 1521 浏览 6 评论 0原文

我正在编写一个 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

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

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,可以看到文档已经加载了。 通过管道将 $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。

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

I'm writing a PowerShell script to manipulate some Windows Installer XML (WiX). I'm using the new XML APIs in .NET 3.5 to do this, as I find it an easier API to work with than the DOM. The following script fragment is flatly refusing to work:

[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

The script should output each <String> tag on a separate line. I'm going to get it to do something more interesting once this bug's been solved ;-)

The XML document is a standard WiX localisation file:

<?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 is not $null (I've explicitly tested it), and if I write-host $wxl, I can see that the document has been loaded. Piping $strings into Get-Member returns an error stating that "No object has been specified to get-member" and write-host $strings does nothing. I've also tried $wxl.Descendants("WixLocalization") with the same results. Things like $wxl.Root and $wxl.Nodes work as expected. Debugging with PowerShell ISE, I see that $strings has been set to IEnumerator, rather than the expected IEnumerable<XElement>. Testing the IEnumerator with a single MoveNext and then a Current indicates that "Current = ", presumably $null.

The weird thing is that the same technique worked in a previous script. The exact same code, but with different variable names and string literals. And having just tried debugging that script too (to verify the behaviour), it seems it's now also displaying the same behaviour.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

我是男神闪亮亮 2024-07-20 10:57:10

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

This problem intrigued me, so I did some searching around. After a lot of messing around in PowerShell and searching the web I found your solution.

Credit goes to Jamie Thomson for the actual code.
http://dougfinke.com/blog/index.php/2007/08/07/using-xmllinq-in-powershell/

The missing piece is to handle the namespace in the XML file. Here is the code that should work for you:

[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
}
街角迷惘 2024-07-20 10:57:10

我知道您说过您不喜欢使用 DOM,但是有什么理由说明这对您不起作用吗?

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

这输出:

PS> $test.WixLocalization.String

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

此时进行查找应该不会太困难。

I know you said you prefered not to work with the DOM, but is there any reason why this doesn't work for you?

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

This outputs:

PS> $test.WixLocalization.String

Id #text
-- -----
0 Advertising published resource
1 Allocating registry space

Foreach'ing over that shouldn't be too difficult at that point.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文