web-dev-qa-db-fra.com

Comment mettre un attribut de codage à xml autre que utf-16 avec XmlWriter?

J'ai une fonction créant du XmlDocument:

public string CreateOutputXmlString(ICollection<Field> fields)
{
    XmlWriterSettings settings = new XmlWriterSettings();
    settings.Indent = true;
    settings.Encoding = Encoding.GetEncoding("windows-1250");

    StringBuilder builder = new StringBuilder();
    XmlWriter writer = XmlWriter.Create(builder, settings);

    writer.WriteStartDocument();
    writer.WriteStartElement("data");
    foreach (Field field in fields)
    {
        writer.WriteStartElement("item");
        writer.WriteAttributeString("name", field.Id);
        writer.WriteAttributeString("value", field.Value);
        writer.WriteEndElement();
    }
    writer.WriteEndElement();
    writer.Flush();
    writer.Close();

    return builder.ToString();
}

J'ai défini un encodage mais après avoir créé XmlWriter, il utilise l'encodage utf-16. Je sais que c'est parce que les chaînes (et StringBuilder, je suppose) sont codées en utf-16 et que vous ne pouvez pas le changer.
Alors, comment puis-je facilement créer ce fichier xml avec l'attribut encoding défini sur "windows-1250"? il n'a même pas besoin d'être encodé dans cet encodage, il doit simplement avoir l'attribut spécifié.

edit: il doit être en .Net 2.0 pour que tous les nouveaux éléments du framework ne puissent pas être utilisés.

36
agnieszka

Vous devez utiliser un StringWriter avec le codage approprié. Malheureusement, StringWriter ne vous laisse pas spécifier directement l'encodage, vous avez donc besoin d'une classe comme celle-ci:

public sealed class StringWriterWithEncoding : StringWriter
{
    private readonly Encoding encoding;

    public StringWriterWithEncoding (Encoding encoding)
    {
        this.encoding = encoding;
    }

    public override Encoding Encoding
    {
        get { return encoding; }
    }
}

( Cette question est similaire mais n’est pas tout à fait un doublon.)

EDIT: Pour répondre au commentaire: transmettez StringWriterWithEncoding à XmlWriter.Create au lieu du StringBuilder, puis appelez ToString () à la fin.

71
Jon Skeet

Juste quelques explications supplémentaires pour expliquer pourquoi il en est ainsi.

Les chaînes sont des séquences de caractères, pas d'octets. Les chaînes, en elles-mêmes, ne sont pas "codées", car elles utilisent des caractères, stockés sous forme de points de code Unicode. L'encodage ne donne pas de sens au niveau de la chaîne.

Un codage est un mappage d'une séquence de points de code (caractères) à une séquence d'octets (pour le stockage sur des systèmes à octets tels que les systèmes de fichiers ou la mémoire). La structure ne vous permet pas de spécifier des codages, sauf s'il existe une raison impérieuse de vouloir rendre les points de code 16 bits adaptés à la mémoire en octets.

Ainsi, lorsque vous essayez d'écrire votre code XML dans un StringBuilder, vous créez en réalité une séquence de caractères XML et vous les écrivez sous forme de séquence de caractères. Aucun codage n'est donc effectué. Par conséquent, pas de champ de codage.

Si vous souhaitez utiliser un codage, XmlWriter doit écrire dans un flux.

À propos de la solution que vous avez trouvée avec MemoryStream, aucune infraction n'est prévue, mais il s'agit simplement de bouger des bras et de déplacer de l'air chaud. Vous codez vos points de code avec "windows-1252", puis vous les analysez pour en faire des points de code. Le seul changement qui peut se produire est que les caractères non définis dans Windows-1252 sont convertis en un '?' personnage dans le processus.

Pour moi, la bonne solution pourrait être la suivante. En fonction de l'utilisation de votre fonction, vous pouvez transmettre un flux en tant que paramètre à votre fonction, de sorte que l'appelant décide s'il doit être écrit en mémoire ou dans un fichier. Donc, ce serait écrit comme ceci:


        public static void WriteFieldsAsXmlDocument(ICollection fields, Stream outStream)
        {
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Indent = true;
            settings.Encoding = Encoding.GetEncoding("windows-1250");

            using(XmlWriter writer = XmlWriter.Create(outStream, settings)) {
                writer.WriteStartDocument();
                writer.WriteStartElement("data");
                foreach (Field field in fields)
                {
                    writer.WriteStartElement("item");
                    writer.WriteAttributeString("name", field.Id);
                    writer.WriteAttributeString("value", field.Value);
                    writer.WriteEndElement();
                }
                writer.WriteEndElement();
            }
        }
5
Laurent LA RIZZA
MemoryStream memoryStream = new MemoryStream();
XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();
xmlWriterSettings.Encoding = Encoding.UTF8;

XmlWriter xmlWriter = XmlWriter.Create(memoryStream, xmlWriterSettings);
xmlWriter.WriteStartDocument();
xmlWriter.WriteStartElement("root", "http://www.timvw.be/ns");
xmlWriter.WriteEndElement();
xmlWriter.WriteEndDocument();
xmlWriter.Flush();
xmlWriter.Close();

string xmlString = Encoding.UTF8.GetString(memoryStream.ToArray());

D'ici

5
EddiG

J'ai en fait résolu le problème avec MemoryStream:

public static string CreateOutputXmlString(ICollection<Field> fields)
        {
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Indent = true;
            settings.Encoding = Encoding.GetEncoding("windows-1250");

            MemoryStream memStream = new MemoryStream();
            XmlWriter writer = XmlWriter.Create(memStream, settings);

            writer.WriteStartDocument();
            writer.WriteStartElement("data");
            foreach (Field field in fields)
            {
                writer.WriteStartElement("item");
                writer.WriteAttributeString("name", field.Id);
                writer.WriteAttributeString("value", field.Value);
                writer.WriteEndElement();
            }
            writer.WriteEndElement();
            writer.Flush();
            writer.Close();

            writer.Flush();
            writer.Close();

            string xml = Encoding.GetEncoding("windows-1250").GetString(memStream.ToArray());

            memStream.Close();
            memStream.Dispose();

            return xml;
        }
3
agnieszka

J'ai résolu le mien en affichant la chaîne dans une variable, puis en remplaçant les références à utf-16 par utf-8 (mon application avait besoin du codage UTF8). Puisque vous utilisez une fonction, vous pouvez faire quelque chose de similaire. J'utilise principalement VB.net, mais je pense que le C # ressemblerait à quelque chose comme ça.

return builder.ToString().Replace("utf-16", "utf-8");
0
SEFL