Paire de substitution de caractères dans un document XML
Un substitut ou paire de substitution est une paire de valeurs d'encodage Unicode 16 bits qui représentent à elles deux un seul caractère. Ce qu'il faut garder à l'esprit est que chacune de ces paires correspond en fait à un caractère 32 bits. On ne peut alors plus supposer qu'une valeur d'encodage Unicode 16 bits puisse être mappée exactement à un autre caractère.
Utilisation de paires de substitution
La première valeur de la paire de substitution est le caractère de substitution étendu ; elle contient une valeur de code 16 bits comprise entre U+D800 et U+DBFF. La seconde valeur de la paire, le caractère de substitution faible, contient des valeurs comprises entre U+DC00 et U+DFFF. L'utilisation de paires de substitution permet au système d'encodage Unicode 16 bits d'utiliser un million et plus de caractères supplémentaires (220) par rapport au nombre de caractères définis par les normes Unicode.
Vous pouvez utiliser les caractères de substitution dans n'importe quelle chaîne passée à une méthode XmlTextWriter. Cependant, le caractère de substitution doit être valide dans le document XML en cours d'écriture. Par exemple, la recommandation du World Wide Web Consortium (W3C) n'autorise pas les caractères de substitution dans les noms d'éléments ou d'attributs. Si la chaîne contient une paire de substitution non valide, une exception est levée.
En outre, vous pouvez utiliser la méthode WriteSurrogateCharEntity pour écrire l'entité caractère correspondant à une paire de substitution. Cette entité caractère est écrite au format hexadécimal et est générée à l'aide de la formule :
(highChar -0xD800) * 0x400 + (lowChar -0xDC00) + 0x10000
Si la chaîne contient une paire de substitution non valide, une exception est levée. L'exemple suivant illustre l'utilisation de la méthode WriteSurrogateCharEntity avec une paire de substitution comme entrée.
// The following line writes 𐀀.
WriteSurrogateCharEntity ('\uDC00', '\uD800');
L'exemple suivant génère un fichier de paire de substitution, le charge dans l'objet XmlReader et enregistre ce fichier sous un nouveau nom. Le fichier d'origine et le nouveau fichier sont rechargés dans l'application de la structure DOM (Document Object Model) XML pour comparaison.
char lowChar, highChar;
char [] charArray = new char[10];
FileStream targetFile = new FileStream("SurrogatePair.xml",
FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite);
lowChar = Convert.ToChar(0xDC00);
highChar = Convert.ToChar(0xD800);
XmlTextWriter tw = new XmlTextWriter(targetFile, null);
tw.Formatting = Formatting.Indented;
tw.WriteStartElement("root");
tw.WriteStartAttribute("test", null);
tw.WriteSurrogateCharEntity(lowChar, highChar);
lowChar = Convert.ToChar(0xDC01);
highChar = Convert.ToChar(0xD801);
tw.WriteSurrogateCharEntity(lowChar, highChar);
lowChar = Convert.ToChar(0xDFFF);
highChar = Convert.ToChar(0xDBFF);
tw.WriteSurrogateCharEntity(lowChar, highChar);
// Add 10 random surrogate pairs.
// As Unicode, the high bytes are in lower
// memory; for example, word 6A21 as 21 6A.
// The high or low is in the logical sense.
Random random = new Random();
for (int i = 0; i < 10; ++i) {
lowChar = Convert.ToChar(random.Next(0xDC00, 0xE000));
highChar = Convert.ToChar(random.Next(0xD800, 0xDC00));
charArray[i] = highChar;
charArray[++i] = lowChar;
}
tw.WriteChars(charArray, 0, charArray.Length);
for (int i = 0; i < 10; ++i) {
lowChar = Convert.ToChar(random.Next(0xDC00, 0xE000));
highChar = Convert.ToChar(random.Next(0xD800, 0xDC00));
tw.WriteSurrogateCharEntity(lowChar, highChar);
}
tw.WriteEndAttribute();
tw.WriteEndElement();
tw.Flush();
tw.Close();
XmlTextReader r = new XmlTextReader("SurrogatePair.xml");
r.Read();
r.MoveToFirstAttribute();
targetFile = new FileStream("SurrogatePairFromReader.xml",
FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite);
tw = new XmlTextWriter(targetFile, null);
tw.Formatting = Formatting.Indented;
tw.WriteStartElement("root");
tw.WriteStartAttribute("test", null);
tw.WriteString(r.Value);
tw.WriteEndAttribute();
tw.WriteEndElement();
tw.Flush();
tw.Close();
// Load both result files into the DOM and compare.
XmlDocument doc1 = new XmlDocument();
XmlDocument doc2 = new XmlDocument();
doc1.Load("SurrogatePair.xml");
doc2.Load("SurrogatePairFromReader.xml");
if (doc1.InnerXml != doc2.InnerXml) {
Console.WriteLine("Surrogate Pair test case failed");
}
Lors de l'écriture à l'aide de la méthode WriteChars qui écrit une mémoire tampon de données à la fois, il est possible qu'une paire de substitution contenue dans l'entrée soit fractionnée entre deux mémoires tampon. Dans la mesure où les valeurs de substitution sont correctement définies, si la méthode WriteChars rencontre une valeur Unicode de la plage supérieure ou inférieure, elle l'identifie comme une des deux moitiés de la paire de substitution. Dans le cas où la méthode WriteChars est amenée à écrire dans la mémoire tampon la première moitié d'une paire de substitution divisée, une exception est levée. Utilisez la méthode IsHighSurrogate pour vérifier si le tampon se termine par un caractère de substitution étendu. Si le dernier caractère dans le tampon n'est pas un caractère de substitution étendu, vous pouvez passer le tampon à la méthode WriteChars.
Voir aussi
Concepts
Création de XML correctement construit avec XmlTextWriter