我有一个在其文本内容中包含汉字的XmlDocument
,我需要使用 ISO-8859-1 编码将其写入流。 当我这样做时,没有一个汉字字符被正确编码,而是被替换为"??"。
下面是演示如何从XmlDocument
编写 XML 的示例代码:
MemoryStream mStream = new MemoryStream();
Encoding enc = Encoding.GetEncoding("ISO-8859-1");
XmlTextWriter writer = new XmlTextWriter(mStream,enc);
doc.WriteTo(writer);
writer.Flush();
mStream.Flush();
mStream.Position = 0;
StreamReader sReader = new StreamReader(mStream, enc);
String formattedXML = sReader.ReadToEnd();
在这种特定情况下,可以做些什么来正确编码汉字?
如注释中所述,显示?
字符是因为编码ISO-8859-1
不支持汉字字符,因此它将?
替换为回退字符。 编码回退在Encoding
的文档备注中讨论:
请注意,编码类允许错误(不支持的字符)执行以下操作:
- 静默地更改为"?"字符。
- 使用"最合适"字符。
- 通过使用带有 U+FFFD Unicode 替换字符的
EncoderFallback
和DecoderFallback
类更改为特定于应用程序的行为。
这就是您所看到的行为。
但是,即使ISO-8859-1
不支持汉字字符,您也可以通过切换到XmlWriter.Create(Stream, XmlWriterSettings)
返回的较新XmlWriter
并在XmlWriterSettings.Encoding
上设置编码来获得更好的结果,如下所示:
MemoryStream mStream = new MemoryStream();
var enc = Encoding.GetEncoding("ISO-8859-1");
var settings = new XmlWriterSettings
{
Encoding = enc,
CloseOutput = false,
// Remove to enable the XML declaration if you want it. XmlTextWriter doesn't include it automatically.
OmitXmlDeclaration = true,
};
using (var writer = XmlWriter.Create(mStream, settings))
{
doc.WriteTo(writer);
}
mStream.Position = 0;
var sReader = new StreamReader(mStream, enc);
var formattedXML = sReader.ReadToEnd();
通过设置Encoding
属性XmlWriterSettings
,只要当前编码不支持某个字符,XML 编写器就会被通知,并自动将其替换为 XML 字符实体引用,而不是一些硬编码的回退。
例如,假设您有如下所示的 XML:
<Root>
<string>畑 はたけ hatake "field of crops"</string>
</Root>
然后,您的代码将输出以下内容,将所有汉字映射到单个回退字符:
<Root><string>? ??? hatake "field of crops"</string></Root>
而新版本将输出:
<Root><string>畑 はたけ hatake "field of crops"</string></Root>
请注意,汉字字符已替换为字符实体,例如畑
? 所有兼容的 XML 解析器都将识别并重建这些字符,因此,尽管您的首选编码不支持汉字,但不会丢失任何信息。
最后,作为旁注,XmlTextWriter
的文档指出:
从 .NET Framework 2.0 开始,我们建议您改用 System.Xml.XmlWriter 类。
因此,用XmlWriter
替换它通常是一个好主意。
示例 .Net 小提琴演示了这两个编写器的用法,并断言XmlWriter
生成的 XML 在语义上等效于原始 XML,尽管字符进行了转义。