我正在使用Powershell脚本将字符串转换为XML然后导出到文件(以这种方式保持缩进):
[xml]$xmloutput = $xml
$sw = New-Object System.IO.StringWriter
$writer = New-Object System.Xml.XmlTextWriter($sw)
$writer.Formatting = [System.Xml.Formatting]::Indented
$xmloutput.WriteContentTo($writer)
$sw.ToString() | Set-Content -Encoding 'ASCII' $filepath
由于供应商限制,目标必须是ASCII格式。我看到的问题是ASCII只是将特殊字符更改为问号(例如:Ö变成?)。
如果我使用UTF8编码,输出看起来完全正常。我甚至尝试保存到UTF8然后转换为ASCII,做同样的事情(导出一个问号):
[System.Io.File]::ReadAllText($filepath) | Out-File -FilePath $filepath -Encoding ASCII
如果我在转换为XML之前尝试替换字符串中的字符(使用ASCII代码Ö
),它只会转换&符号并保留其余字符,使其无效。
有没有办法让Powershell正确地将这些字符保存到文件中?
编辑:我想在输出文件中看到特殊字符,但如果不符合ASCII格式,我希望看到它的ASCII代码(在本例中为Ö
)< / p>
我也不想只看到O,我需要真正的角色。
答案 0 :(得分:4)
XML文档中的所有字符都是Unicode。但是,XML文档的表示具有文档编码。不是该字符集成员的字符被写为字符实体引用,通常以数字形式和十六进制表示法。该数字是Unicode代码点。
您的合作伙伴的要求似乎是使用ASCII作为文档编码。
XmlDocument
有点难以使用,但带有文档编码设置的XmlWriter
可以使用:
$myString = 'hellÖ'
[xml]$myXml = [System.Management.Automation.PSSerializer]::Serialize($myString)
$settings = New-Object System.Xml.XmlWriterSettings
$settings.Encoding = [System.Text.Encoding]::ASCII
$settings.Indent = $true
$writer = [System.Xml.XmlWriter]::Create("./test.xml", $settings)
$myXml.Save($writer)
$writer.Dispose()
这会发出一个ASCII编码的文本文件,其中包含XML declation,声明文档编码为ASCII,并使用十六进制数字字符实体引用,用于无法用ASCII表示的XML内容字符:
<?xml version="1.0" encoding="us-ascii"?>
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04">
<S>hellÖ</S>
</Objs>
正如您在C1 Controls和Latin-1 Supplement块中看到的here,U + 00D6(&amp;#D6;),是带有DIAERESIS的L拉丁文大写字母O
答案 1 :(得分:2)
这不是特定于PowerShell的,它通常是一个字符编码问题。
基本上,该字符不是ASCII,而是ISO 8859-1。
但是,通过将XmlTextWriter
直接写入文件可以简化此过程,因为您可以使用它来控制编码。试试这个:
$myString = 'hellÖ'
[xml]$myXml = [System.Management.Automation.PSSerializer]::Serialize($myString)
$myEncoding = [System.Text.Encoding]::GetEncoding('iso-8859-1')
$writer = New-Object System.Xml.XmlTextWriter($filepath, $myEncoding)
$writer.Formatting = [System.Xml.Formatting]::Indented
$myXml.WriteContentTo($writer)
$writer.Flush()
$writer.Close()
$writer.Dispose()
这将使用ISO 8859-1编码编写文件,但不会编码为XML实体。
因此,如果您的应用程序仅需要真正的ASCII,没有扩展集,那么这将无效。如果它真的只需要单字节编码并且这种编码中的字符集足够,那就没关系。
第1步:忽略我写的内容,改为使用Tom Blodget's answer。
您可以做的是在ASCII编码器上设置custom fallback callback,这样每当遇到无法用ASCII表示的字符时,它就会调用您的函数来获取替换。您的函数将有助于返回角色的实体版本。
技术上......这可能会适得其反。由于您必须从编码器返回&符号&
,因此XmlWriter可能会看到并“帮助”将其替换为&
,这会破坏您的编码。
可能直接从PowerShell使用此回调,但会有点麻烦。使用一些C#和Add-Type
会更容易。
或者您可以执行此方法的游击版本:编写XML字符串,然后手动替换任何非ASCII字符。
这里我使用的是正则表达式引擎的替换方法版本,该方法采用匹配评估功能。正则表达式匹配任何不在'BasicLatin'Unicode Named Block中的字符。
$myString = 'hellÖ'
[xml]$myXml = [System.Management.Automation.PSSerializer]::Serialize($myString)
$sw = New-Object System.IO.StringWriter
$writer = New-Object System.Xml.XmlTextWriter($sw)
$writer.Formatting = [System.Xml.Formatting]::Indented
$myXml.WriteContentTo($writer)
$output = [RegEx]::Replace($sw.ToString(), '\P{IsBasicLatin}', { param($match) '&#{0};' -f [int][char]$match.Value })
$output | Set-Content -Encoding 'ASCII' -LiteralPath $filepath
据我所知,这将完全符合您的要求。