c # Rileva codifica XML da array di byte?
-
06-09-2019 - |
Domanda
Beh io ho un array di byte, e so che la sua un oggetto serilized XML nella matrice di byte C'è un modo per ottenere la codifica da esso?
Im non andando a deserilize ma Im salvandolo in un campo XML su un server SQL ... quindi ho bisogno di convertirlo in una stringa?
Soluzione
Si potrebbe guardare i primi byte 40-ish 1 . Essi dovrebbe contenere la dichiarazione di documento (ammesso che ha di una dichiarazione di documento), che dovrebbe contenere sia la codifica o si può presumere che sia UTF-8 o UTF-16, che dovrebbe dovrebbe essere evidente da come avete capito la parte <?xml
. (Basta controllare per entrambi i modelli.)
Realisticamente, si aspetta che tu abbia mai ottenere qualcosa di diverso da UTF-8 o UTF-16? In caso contrario, si potrebbe verificare per i modelli che si ottiene a inizio sia di quelli e un'eccezione se non segue neanche modello. In alternativa, se si vuole fare un altro tentativo, si può sempre cercare di decodificare il documento come UTF-8, ricodificarlo e vedere se si ottengono gli stessi byte indietro. Non è l'ideale, ma potrebbe funzionare.
Sono sicuro che ci sono modi più rigorosi di fare questo, ma sono suscettibili di essere pignoli:)
1 Molto probabilmente meno di questo. Immagino 20 caratteri dovrebbero essere abbastanza, che è di 40 byte in UTF-16.
Altri suggerimenti
Una soluzione simile a questa domanda potrebbe risolvere questo utilizzando uno streaming di byte. Allora non dovrete perdere tempo a livello di byte. In questo modo:
Encoding encoding;
using (var stream = new MemoryStream(bytes))
{
using (var xmlreader = new XmlTextReader(stream))
{
xmlreader.MoveToContent();
encoding = xmlreader.Encoding;
}
}
I primi 2 o 3 byte può essere un Byte Order Mark (BOM), che può dirvi se il flusso è UTF-8, Unicode-LittleEndian o Unicode-BigEndian.
UTF-8 BOM è 0xEF 0xBB 0xBF Unicode bigEndian è 0xFE 0xFF Unicode LittleEndiaon è 0xFF 0xFE
Se nessuno di questi sono presenti, allora si può usare ASCII per verificare <?xml
(nota più bastoni moderna generazione XML al livello che nessuno spazio bianco può precedere la dichiarazione XML).
ASCII viene utilizzato fino a quando ?>
in modo da poter trovare la presenza di encoding = e di trovare il suo valore.
Se la codifica non è presente o <?xml
declare non è presente, allora si può supporre UTF-8.
Il specifiche W3C XML ha una sezione su come determinare la codifica di una stringa di byte.
Primo controllo per un Byte Order Mark Unicode
Una distinta base è solo un altro personaggio; è il:
Il carattere U + FEFF , con ogni altro carattere nel file, è codificato utilizzando lo schema di codifica appropriata:
-
00 00 FE FF
: UCS-4, big-endian macchina (1234 ordine) -
FF FE 00 00
: UCS-4, little-endian macchina (4321 ordine) -
00 00 FF FE
: UCS-4, insolito ordine ottetto (2143) -
FE FF 00 00
: UCS-4, insolito ordine ottetto (3412) -
FE FF ## ##
: UTF-16, big-endian -
FF FE ## ##
: UTF-16, little-endian -
EF BB BF
: UTF-8
dove ## ##
può essere nulla - tranne che per entrambi che sono pari a zero
Quindi, per prima cosa controllare i byte inital per uno di tali firme. Se si trova uno di loro, ritorno che code-page identificativo
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)
oppure cercare Xml
Se il documento XML non ha alcuna Byte Order Mark carattere, quindi si passa alla ricerca per i primi cinque caratteri che ogni documento XML deve avere:
<?xml
E 'utile sapere che
-
<
è # x0000003C -
?
è # x0000003F
Con che abbiamo abbastanza di guardare ai primi quattro byte:
-
00 00 00 3C
: UCS-4, big-endian macchina (1234 ordine) -
3C 00 00 00
: UCS-4, little-endian macchina (4321 ordine) -
00 00 3C 00
: UCS-4, insolito ordine ottetto (2143) -
00 3C 00 00
: UCS-4, insolito ordine ottetto (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
: un certo sapore di EBCDIC
Quindi possiamo poi aggiungere di più per il nostro codice:
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.
}