我有一个字节数组,我知道它在字节数组中的xml serized对象是否有任何方法可以从中获取编码?
我不打算对它进行deserilize,但是我将它保存在sql server上的xml字段中......所以我需要将它转换为字符串?
答案 0 :(得分:14)
类似于this question的解决方案可以通过在字节数组上使用Stream来解决这个问题。那么你就不必在字节级别进行操作。像这样:
Encoding encoding;
using (var stream = new MemoryStream(bytes))
{
using (var xmlreader = new XmlTextReader(stream))
{
xmlreader.MoveToContent();
encoding = xmlreader.Encoding;
}
}
答案 1 :(得分:7)
您可以查看前40个字节 1 。他们应包含文档声明(假设它具有文档声明),该声明应包含编码或,您可以认为它是UTF-8或UTF-16,从您对<?xml
部分的理解应该是显而易见的。 (只需检查两种模式。)
实际上,您是否期望获得UTF-8或UTF-16以外的其他任何东西?如果没有,您可以检查在这两个模式开始时获得的模式,如果不遵循任何模式,则抛出异常。或者,如果您想再次尝试,可以尝试将文档解码为UTF-8,重新编码并查看是否返回相同的字节。它并不理想,但它可能会起作用。
我确信有更严格的方法可以做到这一点,但它们可能很挑剔:)
1 可能还不到这个。我认为20个字符应该足够了,这是UTF-16中的40个字节。
答案 2 :(得分:7)
前2个或3个字节可以是字节顺序标记(BOM),它可以告诉您流是UTF-8,Unicode-LittleEndian还是Unicode-BigEndian。
UTF-8 BOM为0xEF 0xBB 0xBF Unicode-Bigendian是0xFE 0xFF Unicode-LittleEndiaon是0xFF 0xFE
如果这些都不存在,那么您可以使用ASCII来测试<?xml
(请注意,大多数现代XML生成都遵循标准,即xml声明之前不会出现空格。)
ASCII用完直到?>
,因此您可以找到encoding =的存在并找到它的值。
如果编码不存在或<?xml
声明不存在,那么您可以假设为UTF-8。
答案 3 :(得分:6)
关于如何确定字节串编码的W3C XML specification has a section。
BOM只是另一个角色;这是:
字符 U + FEFF 以及文件中的每个其他字符都使用适当的编码方案进行编码:
00 00 FE FF
: UCS-4,大端机器(1234订购) FF FE 00 00
: UCS-4,小端机器(4321订单) 00 00 FF FE
: UCS-4,异常八位字节顺序(2143) FE FF 00 00
: UCS-4,异常八位字节顺序(3412) FE FF ## ##
: UTF-16,big-endian FF FE ## ##
: UTF-16,little-endian EF BB BF
: UTF-8 其中## ##
可以是任何内容 - 除了两者都是零
因此,首先检查任何这些签名的初始字节。如果您找到其中一个,请返回code-page identifier
UInt32 GuessEncoding(byte[] XmlString)
{
if BytesEqual(XmlString, [00, 00, $fe, $ff]) return 12001; //"utf-32BE" - Unicode UTF-32, big endian byte order
if BytesEqual(XmlString, [$ff, $fe, 00, 00]) return 1200; //"utf-32" - Unicode UTF-32, little endian byte order
if BytesEqual(XmlString, [$fe, $ff, 00, 00]) throw new Exception("Nobody supports 2143 UCS-4");
if BytesEqual(XmlString, [$fe, $ff, 00, 00]) throw new Exception("Nobody supports 3412 UCS-4");
if BytesEqual(XmlString, [$fe, $ff])
{
if (XmlString[2] <> 0) && (XmlString[3] <> 0)
return 1201; //"unicodeFFFE" - Unicode UTF-16, big endian byte order
}
if BytesEqual(XmlString, [$ff, $fe])
{
if (XmlString[2] <> 0) && (XmlString[3] <> 0)
return 1200; //"utf-16" - Unicode UTF-16, little endian byte order
}
if BytesEqual(XmlString, [$ef, $bb, $bf]) return 65001; //"utf-8" - Unicode (UTF-8)
如果XML文档没有字节顺序标记字符,那么您将继续查找每个XML文档必须具有的前五个字符:
<?xml
了解
是有帮助的<
是#x0000003C ?
是#x0000003F 有了这个,我们就足够了解前四个字节:
00 00 00 3C
: UCS-4,大端机器(1234订购) 3C 00 00 00
: UCS-4,小端机器(4321订单) 00 00 3C 00
: UCS-4,异常八位字节顺序(2143) 00 3C 00 00
: UCS-4,异常八位字节顺序(3412) 00 3C 00 3F
: UTF-16,big-endian 3C 00 3F 00
: UTF-16,little-endian 3C 3F 78 6D
: UTF-8 4C 6F A7 94
:某些EBCDIC 因此我们可以在代码中添加更多内容:
if BytesEqual(XmlString, [00, 00, 00, $3C]) return 12001; //"utf-32BE" - Unicode UTF-32, big endian byte order
if BytesEqual(XmlString, [$3C, 00, 00, 00]) return 1200; //"utf-32" - Unicode UTF-32, little endian byte order
if BytesEqual(XmlString, [00, 00, $3C, 00]) throw new Exception("Nobody supports 2143 UCS-4");
if BytesEqual(XmlString, [00, $3C, 00, 00]) throw new Exception("Nobody supports 3412 UCS-4");
if BytesEqual(XmlString, [00, $3C, 00, $3F]) return return 1201; //"unicodeFFFE" - Unicode UTF-16, big endian byte order
if BytesEqual(XmlString, [$3C, 00, $3F, 00]) return 1200; //"utf-16" - Unicode UTF-16, little endian byte order
if BytesEqual(XmlString, [$3C, $3F, $78, $6D]) return 65001; //"utf-8" - Unicode (UTF-8)
if BytesEqual(XmlString, [$4C, $6F, $A7, $94])
{
//Some variant of EBCDIC, e.g.:
//20273 IBM273 IBM EBCDIC Germany
//20277 IBM277 IBM EBCDIC Denmark-Norway
//20278 IBM278 IBM EBCDIC Finland-Sweden
//20280 IBM280 IBM EBCDIC Italy
//20284 IBM284 IBM EBCDIC Latin America-Spain
//20285 IBM285 IBM EBCDIC United Kingdom
//20290 IBM290 IBM EBCDIC Japanese Katakana Extended
//20297 IBM297 IBM EBCDIC France
//20420 IBM420 IBM EBCDIC Arabic
//20423 IBM423 IBM EBCDIC Greek
//20424 IBM424 IBM EBCDIC Hebrew
//20833 x-EBCDIC-KoreanExtended IBM EBCDIC Korean Extended
//20838 IBM-Thai IBM EBCDIC Thai
//20866 koi8-r Russian (KOI8-R); Cyrillic (KOI8-R)
//20871 IBM871 IBM EBCDIC Icelandic
//20880 IBM880 IBM EBCDIC Cyrillic Russian
//20905 IBM905 IBM EBCDIC Turkish
//20924 IBM00924 IBM EBCDIC Latin 1/Open System (1047 + Euro symbol)
throw new Exception("We don't support EBCDIC. Sorry");
}
//Otherwise assume UTF-8, and fail to decode it anyway
return 65001; //"utf-8" - Unicode (UTF-8)
//Any code is in the public domain. No attribution required.
}