首页 > 解决方案 > Powershell xml解析弄乱了编码

问题描述

我有这个非常简单的脚本:

$rssUrl = "https://elpais.com/rss/elpais/portada.xml"
$FeedXml = [xml](Invoke-WebRequest $rssUrl)

此时如果我把$FeedXml.Save()提要中的所有重音和特殊字符都称为乱码,就好像编码错误一样。

例如:

Un periodista que viaj?? a Mil??n para
should be:
Un periodista que viajó a Milán para

(Invoke-WebRequest $rssUrl).Content会产生正确的输出。

我目前已经这样做了:

$FeedXml = New-Object xml
$resolver = New-Object -TypeName System.Xml.XmlUrlResolver
$resolver.Credentials = [System.Net.CredentialCache]::DefaultCredentials

$reader = New-Object -TypeName System.Xml.XmlReaderSettings
$reader.XmlResolver = $resolver
$reader = [System.Xml.XmlReader]::Create($rssUrl, $reader)

$FeedXml.Load($reader)

在这种情况下$FeedXml.Save()会产生预期的输出。

我完全无法理解为什么第一个代码,它应该是“正确的方式”它不起作用?

标签: xmlpowershellpowershell-core

解决方案


所以看起来问题在于,当 PowerShell 将结果转换为Invoke-WebRequest $rssUrlxml 文档时,它用于[System.Text.Encoding]::ASCII将原始字节流转换为字符串,在您的情况下,根据 http 请求中的标头,这实际上是一个 utf8 字节流。

PS> $rssUrl = "https://elpais.com/rss/elpais/portada.xml"

PS> $response = Invoke-WebRequest $rssUrl

PS> $response.GetType().FullName
Microsoft.PowerShell.Commands.BasicHtmlWebResponseObject

PS> $response.Headers["Content-Type"]
text/xml; charset=utf-8

这是 BasicHtmlWebResponseObject 的来源:https ://github.com/PowerShell/PowerShell/blob/master/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/BasicHtmlWebResponseObject.Common.cs

你可以看到它继承自 WebResponseObject,ToString 方法在这里:https ://github.com/PowerShell/PowerShell/blob/658837323599ab1c7a81fe66fcd43f7420e4402b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common /WebResponseObject.Common.cs#L88

/// <summary>
/// Returns the string representation of this web response.
/// </summary>
/// <returns>The string representation of this web response.</returns>
public sealed override string ToString()
{
    char[] stringContent = System.Text.Encoding.ASCII.GetChars(Content);
    //                     ^^^^^^^^^^^^^^^^^^^^^^^^^^
    for (int counter = 0; counter < stringContent.Length; counter++)
    {
        if (!IsPrintable(stringContent[counter]))
        {
            stringContent[counter] = '.';
        }
    }
    return new string(stringContent);
}

另一方面,(Invoke-WebRequest $rssUrl).Content是一个已被正确解码的字符串,System.Text.Encoding.UTF8因此它保留了重音字符。

简而言之,使用(Invoke-WebRequest $rssUrl).Contentwhich 已经是一个字符串可能会更好,而不是使用Invoke-WebRequest $rssUrl.


推荐阅读