2009-01-09 7 views
33

J'ai fonction la création de certains XmlDocument:Comment mettre un attribut de codage à xml autre que utf-16 avec XmlWriter?

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(); 
} 

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

éditer: il doit être dans .Net 2.0 de sorte que tous les nouveaux éléments d'infrastructure ne peuvent pas être utilisés.

+0

Je sais qu'il ne peut pas être la bonne façon, mais j'utilisé blahblah.Replace (« utf-16 », « utf-8 ») quand je voulais retourner ma chaîne xml et cela a fonctionné pour moi: D –

Répondre

65

Vous devez utiliser un StringWriter avec l'encodage approprié. Malheureusement StringWriter ne vous permet pas de spécifier l'encodage directement, donc il faut une classe comme ceci: (. This question est similaire, mais pas tout à fait en double)

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

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

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

EDIT: Pour répondre à ce commentaire: laissez-passer StringWriterWithEncoding à XmlWriter.Create au lieu de StringBuilder, puis appelez ToString() à la fin.

+0

Eh bien c'est un strinWriter, j'ai déjà vu ce post (dans un autre sujet) mais je ne sais pas vraiment ce que je pourrais en faire. – agnieszka

+0

pourriez-vous s'il vous plaît expliquer comment pourrais-je l'utiliser? – agnieszka

+0

Voir mes modifications à la fin. Changez simplement votre StringBuilder en StringWriterWithEncoding (en passant le codage que vous voulez) et vous avez terminé. –

3

En fait, je 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; 
     } 
+1

Si vous utilisez un MemoryStream, vous devez au moins le décoder avec le même encodage que précédemment (c'est-à-dire Windows-1250, * pas * ASCII). Je préfère ma version, personnellement :) –

5

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

Les chaînes sont des séquences de caractères, pas d'octets. Les chaînes, en soi, ne sont pas "codées", car elles utilisent des caractères, qui sont stockés en tant que points de code Unicode. L'encodage NE FAIT PAS DE SENS au niveau de la corde.

Un codage est un mappage entre une séquence de points de code (caractères) et une séquence d'octets (pour le stockage sur des systèmes basés sur des octets tels que les systèmes de fichiers ou la mémoire). Le framework ne vous permet pas de spécifier des encodages, à moins qu'il y ait une raison impérieuse, de faire en sorte que les points de code 16 bits tiennent sur le stockage basé octet. Lorsque vous essayez d'écrire votre code XML dans StringBuilder, vous construisez une séquence de caractères XML et vous l'écrivez comme une séquence de caractères, donc aucun encodage n'est effectué. Par conséquent, aucun champ de codage.

Si vous souhaitez utiliser un encodage, XmlWriter doit écrire dans un flux. À propos de la solution que vous avez trouvée avec le MemoryStream, sans vouloir offenser, mais il s'agit simplement de tourner autour des bras et de déplacer l'air chaud. Vous codez vos points de code avec 'windows-1252', puis vous l'analysez de nouveau aux points de code. Le seul changement qui peut arriver est que les caractères non définis dans windows-1252 soient convertis en '?' caractère dans le processus.

Pour moi, la bonne solution pourrait être la suivante. Selon la fonction utilisée, vous pouvez transmettre un Stream 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, il 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(); 
      } 
     } 
4
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()); 

From here

0

Je le mien résolu en plaçant la chaîne à une variable puis en remplaçant toutes les références à utf-16 avec utf-8 (mon application nécessaire UTF8 codage). Puisque vous utilisez une fonction, vous pouvez faire quelque chose de similaire. J'utilise principalement VB.net, mais je pense que le C# ressemblerait à ceci.

return builder.ToString().Replace("utf-16", "utf-8"); 
Questions connexes