7
votes

Xmlreader se casse sur la naissance UTF-8

J'ai le code d'analyse XML suivant dans mon application:

var responseXml = new UTF8Encoding(false).GetString(bytes);


1 commentaires

4 Réponses :


6
votes

La chaîne XML ne doit pas (!) contenir la nomenclature, la nomenclature n'est autorisée que dans les données d'octets (par exemple, qui est codée avec UTF-8. En effet, la représentation des chaînes n'est pas codée, mais déjà une séquence de caractères unicode.

Il semble donc que vous chargez la chaîne incorrecte, ce qui est dans le code que vous n'avez pas fourni. P>

EDIT: strong> p>

Merci d'avoir publié le code de sérialisation. P>

Vous ne devez pas écrire les données sur un StringWRITEAM, mais plutôt à un StringWriter que vous pouvez ensuite convertir en une corde avec une totring. Comme cela évite de traverser une représentation d'octets, il n'est pas seulement plus rapide, mais évite également de tels problèmes. P>

quelque chose comme ceci: p>

private static string SerializeResponse(Response response)
{
    var output = new StringWriter();
    var writer = XmlWriter.Create(output);
    new XmlSerializer(typeof(Response)).Serialize(writer, response);
    return output.ToString();
}


5 commentaires

J'ai fait exactement ce changement, et cela fonctionne parfaitement. Merci!


Il n'y a pas de restriction pour que la nomination soit présente dans XML selon ceci: w3.org / TR / REC-XML / # Charcoding


Cela fonctionne ... Cependant, lorsque vous passez à un StringWriter , l'attribut coding dans le Déclaration semble toujours apparaître comme UTF-16. Pour, disons, utf-8, vous devez retour de retour.tostring (). Remplacez ("UTF-16", "UTF-8"); .


De plus, je me rends compte que c'était un exemple rapide, mais vous devriez pas juste neuf un xmlSerializer comme dans le code exemple. La mémoire XMLSerializer fuit - voir par exemple ici . Un travail commun est de rendre le sérialiseur statique à la classe étant sérialisé.


@David, la représentation de la mémoire des chaînes est UTF-16, c'est pourquoi Write "UTF-16" à la sortie est réellement correcte pour la représentation en mémoire. Cela dit, faire un remplacement sur la chaîne résultante est une très mauvaise idée non seulement parce que c'est lent, mais aussi parce que vous pouvez remplacer d'autres cordes qui ont "UTF-16" écrit en eux et ne peuvent avoir rien à voir avec le XML codage utilisé. En ce qui concerne la fuite, ce code ne fuit pas car il utilise la surcharge du constructeur TAT utilise des assemblages mis en cache (pas celui avec le xmlrooTatTtribut spécifique).



0
votes

La naissance ne devrait pas être dans la ficelle en premier lieu.
Les boms sont utilisés pour détecter le codage d'un tableau d'octets brut; Ils n'ont aucune affaire dans une chaîne réelle.

À quoi vient la chaîne?
Vous le lisez probablement avec le mauvais encodage.


3 commentaires

Je me suis assuré que j'avais au moins utiliser le bon codage :) J'ai ajouté le code de sérialisation à ma question.


C'est une réponse intéressante ... J'ai une affaire où je tire à partir d'une API distante (que je ne contrôle pas) et que je charge simplement les données via req.getresponse (). GetResponstream () et que ruisseau directement dans un xmlreader. Y a-t-il un meilleur moyen de le faire (ce qui évite ce problème)?


@Tomlianza: Cela dépend. Quels octets l'envoi est-il?



0
votes

Les chaînes en C # sont codées comme UTF-16, de sorte que la chône serait fausse. En règle générale, encodez toujours des matrices d'octets XML et décoder des tableaux d'octets.


14 commentaires

Ce n'est pas vraiment vrai. Bien que le format de la mémoire soit généralement similaire à UTF-16, les chaînes sont une séquence de caractères "abstraite" avec un nombre spécifique de caractères. Notez qu'il y a eu des discussions dans l'équipe CLR pour changer de chaîne pour avoir une autre représentation en mémoire afin de les rendre plus efficaces. Quoi qu'il en soit, puisqu'il s'agit d'une vue abstraite et non d'une séquence d'octets, un bom ne doit pas exister dans la chaîne.


J'ai ajouté le code de sérialisation. J'utilise déjà UTF-8 explicitement.


@Stephen, je pense que la chose avec des représentations de chaînes alternatives en mémoire était dans la chaîne suivante 9 Vidéo: canal9.msdn.com/shows/ing +deep/...


@LUCERO: le La documentation de la classe String indique clairement qu'il utilise Encodage UTF-16. Vous pouvez obtenir la séquence de caractères unicode via stringinfo.gettextexemementenumerator ; Les valeurs Char dans une chaîne peuvent contenir des paires de substitution.


@Stephen, le docs disent: "Une chaîne est une collection séquentielle de caractères Unicode utilisés pour représenter le texte." et plus tard "chaque caractère Unicode dans une chaîne est défini par une valeur scalaire unicode, également appelée point de code Unicode ou la valeur ordinale (numérique) du caractère Unicode. Chaque point de code est codé à l'aide de l'encodage UTF-16 et de la valeur numérique de chaque élément du codage est représenté par un objet de caractère. "Le point étant que la chaîne n'est pas une représentation sérialisée, mais une séquence de caractères Unicode composée de points de code UTF16. C'est une abstraction de séquence de caractères.


(suite) La nomenclature est utilisée pour détecter la sérialisation binaire (octet) d'une chaîne UNICODE. Comme il s'agit d'une abstraction de chalamières utilisant des points de code, vous ne rencontrez jamais une représentation d'octets, ce qui signifie également qu'un nom n'est ni utilisé ni supporté pour la représentation de chaîne interne. Notez que les bombes sont principalement utilisées pour détecter UTF16 Little Endian et Big Endianness en séquences d'octets, et l'utilisation de l'UTF8 est moins importante en dehors du monde de Microsoft et uniquement des serveurs de "étiquettes" une séquence d'octets comme UTF8 opposée à ASCII ou à ANSI.


@LUCERO: Comme vous l'avez cité, la classe String utilise l'encodage UTF-16. S'il était destiné à être une abstraction de caractères, il s'agit d'une abstraction très très fuyante, car elle itérit sur les rendements de la chaîne UTF-16 octets.


@Stephen, c'est la partie que vous avez mal à laquelle vous avez mal: cela ne donne pas d'octets, mais (16 bits) caractères endians-invariant. C'est une différence très importante.


@LUCERO: bonne prise avec l'endianness! Mais j'interprète toujours les documents comme déclarant l'encodage UTF-16 (juste avec une endansion non spécifiée).


@Stephen, l'endianness n'est significative que lors du chargement d'entités entières supérieures à un octet, par exemple dans un registre de processeur. Fondamentalement, il définit si l'octet le plus ou le moins significatif vient d'abord pour quelque chose de plus grand qu'un octet. Donc, depuis que nous traitons déjà avec des entités de 16 bits, l'endansnité n'a pas de sens ici et par conséquence, une naissance n'a aucune fonction ici. Voir aussi Unicode.org/faq/utf_bom.html#bom - "Que dois-je faire avec U + FeFF au milieu d'un fichier? " (Notez que la discussion dans la FAQ concerne Streams de données , pas des séquences ponctuelles de code comme nous l'avons en mémoire).


@LUCERO: Je conviens que la naissance ne doit pas être dans la chaîne. Cependant, l'endansion n'a pas de sens avec UTF-16; Il y a des codages LE et BE UTF-16, et lorsqu'ils sont écrits dans un flux d'octets, ces nécessitent BOM.


@Stephen, désolé, mais vous êtes complètement faux ici. Le et être prédéfini dans leur endianness lorsqu'il est écrit dans un ruisseau d'octets, et donc n'utilisez donc pas la naissance. Dès que vous gérez des codes 16 bits qui ont déjà été chargés d'une représentation d'octets, l'endansion n'a pas de sens. Voir la FAQ BeforementationDed, "Unicode a-t-il un codage 16 bits" et "Qu'est-ce qu'un UTF?" et "quelles sont certaines des différences entre les UTFS?".


@LUCERO: Je vous réfère au spécific XML , qui indique clairement que Un document XML dans un codage UTF-16 nécessite un nom.


@Stephen: Oui, un document XML (qui est lu à partir d'un flux d'octets) nécessite une nomenclature lorsque UTF-16 est le codage. Mais ne confondez pas l'UTF-16 ordinaire avec UTF-16BE ou UTF-16LE - ceux ne doivent pas avoir un bom (et sont rarement utilisés pour les fichiers XML)! Voir aussi ietf.org/rfc/rfc3023.txt Page 14.



9
votes

Dans mon gestionnaire de demande, je suis sérialisé un objet de réponse et le renvoyer en tant que chaîne. Le processus de sérialisation ajoute une nomenclature UTF-8 à l'avant de la chaîne, ce qui provoque la rupture du même code lors de l'analyse de la réponse.

Vous voulez donc empêcher la chômée d'être ajoutée dans le cadre de votre processus de sérialisation. Malheureusement, vous ne fournissez pas quelle est votre logique de sérialisation.

Ce que vous devriez faire est de fournir un utf8encoding exemple créé via le utf8encoding (bool) constructeur pour désactiver la génération de la naissance et passez cette instance coding sur les méthodes utilisées qui génèrent votre chaîne intermédiaire.


2 commentaires

Merci! Je rencontrerais ce peu de sagesse au cours de mes recherches, mais je ne pouvais trouver aucune orientation explicite sur l'inclusion ou l'exclusion de la naissance.


M'a beaucoup aidé aujourd'hui, bonne solution!