C # اكتشاف ترميز XML من صفيف البايت؟
-
06-09-2019 - |
سؤال
حسنا، لدي صفيف بايت، وأنا أعلم أن كائن ساري XML في صفيف البايت هو هناك أي طريقة للحصول على الترميز منه؟
أنا لن أحلامها ولكني حفظها في حقل XML على خادم SQL ... لذلك أحتاج إلى تحويله إلى سلسلة؟
المحلول
يمكنك أن تنظر إلى البايت الأربعين الأولين1. وبعد هم ينبغي تحتوي على إعلان المستند (على افتراض ذلك لديها إعلان مستند) الذي يجب أن يحتوي إما على الترميز أو يمكنك افتراض أنه UTF-8 أو UTF-16، والذي ينبغي أن يكون واضحا من كيفية فهمك <?xml
جزء. (فقط تحقق من كلا الأنماط.)
واقعية، هل تتوقع أن تحصل على أي شيء آخر غير UTF-8 أو UTF-16؟ إذا لم يكن الأمر كذلك، فيمكنك التحقق من الأنماط التي تحصل عليها في بداية كل من تلك ورمي استثناء إذا لم يتبع النمط. بدلا من ذلك، إذا كنت ترغب في إجراء محاولة أخرى، فيمكنك دائما محاولة فك تشفير المستند باسم UTF-8، وإعادة تشفيرها ومعرفة ما إذا كنت تحصل على نفس البايتات. انها ليست مثالية، ولكن قد تعمل فقط.
أنا متأكد من أن هناك طرق أكثر صرامة للقيام بذلك، لكن من المحتمل أن تكون أخيرا :)
1 ربما أقل من هذا. يجب أن يكون الرقم 20 حرفا كافيا، وهو 40 بايت في UTF-16.
نصائح أخرى
حل مشابه ل هذا السؤال يمكن حل هذا باستخدام دفق على صفيف البايت. ثم لن تضطر إلى كمان على مستوى البايت. مثله:
Encoding encoding;
using (var stream = new MemoryStream(bytes))
{
using (var xmlreader = new XmlTextReader(stream))
{
xmlreader.MoveToContent();
encoding = xmlreader.Encoding;
}
}
قد يكون أول 2 أو 3 بايت علامة ترتيب البايت (BOM) والتي يمكن أن تخبرك ما إذا كان الدفق هو UTF-8 أو Unicode-Linkode-Linkode أو Unicode-Bigendian.
UTF-8 Bom هو 0xEF 0xbb 0xbf Unicode-Bigendian هو 0xff 0xff Unicode-Linterendiaon هو 0xff 0xfe
إذا لم يكن أي من هذه حاضرين، فيمكنك استخدام ASCII لاختبار <?xml
(لاحظ أن معظم جيل XML الحديث يتمسك بالمعيار الذي لا يمكن لأي مسافة بيضاء مسبق تعلن XML).
يستخدم ASCII حتى ?>
حتى تتمكن من العثور على وجود الترميز = وابحث عن قيمتها. إذا الترميز غير موجود أو <?xml
يعلن غير موجود، يمكنك افتراض UTF-8.
ال مواصفات W3C XML لديها قسم حول كيفية تحديد ترميز سلسلة البايت.
تحقق أولا من علامة ترتيب البايت Unicode
بوم هو مجرد شخصية أخرى؛ انها ال:
الشخصية U + FEFF., ، إلى جانب كل حرف آخر في الملف، يتم ترميزه باستخدام نظام الترميز المناسب:
00 00 FE FF
: UCS-4، آلة كبيرة الانديان (1234 طلب)FF FE 00 00
: UCS-4، آلة Little-Endian (4321 Order)00 00 FF FE
: UCS-4، أمر ثابت غير عادي (2143)FE FF 00 00
: UCS-4، أمر غير عادي أوتمت (3412)FE FF ## ##
: UTF-16، Big-endianFF FE ## ##
: UTF-16، Little-EndianEF BB BF
: UTF-8.
أين ## ##
يمكن أن يكون أي شيء - باستثناء كلا الصفر
تحقق أولا أولا من البايتات الداخلية لأي من تلك التوقيعات. إذا وجدت أحدهم، فأعد ذلك معرف صفحة الرمز
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، آلة Little-Endian (4321 Order)00 00 3C 00
: UCS-4، أمر ثابت غير عادي (2143)00 3C 00 00
: UCS-4، أمر غير عادي أوتمت (3412)00 3C 00 3F
: UTF-16، Big-endian3C 00 3F 00
: UTF-16، Little-Endian3C 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.
}