2009-01-09 12 views
33

Tengo una función de creación de algunos XmlDocument:¿Cómo poner un atributo de codificación en xml otro que utf-16 con 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(); 
} 

que establecer una codificación, pero después de crear XmlWriter sí tiene codificación UTF-16. Sé que es porque las cadenas (y StringBuilder, supongo) están codificadas en utf-16 y no se puede cambiar.
Entonces, ¿cómo puedo crear fácilmente este xml con el atributo de codificación establecido en "windows-1250"? ni siquiera tiene que estar codificado en esta codificación, solo tiene que tener el atributo especificado.

editar: tiene que estar en .Net 2.0 por lo que no se pueden utilizar los nuevos elementos del marco.

+0

Sé que no puede ser el camino correcto pero he usado blahblah.Replace ("UTF-16", "UTF-8") cuando quería volver a mi cadena XML y funcionó para mí: D –

Respuesta

65

Necesita utilizar un StringWriter con la codificación adecuada. Desafortunadamente StringWriter no le permite especificar la codificación directa, por lo que necesita una clase como esta: (. This question es similar pero no es un duplicado)

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

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

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

EDIT: Para responder a los comentarios: pase StringWriterWithEncoding a XmlWriter.Create en lugar de StringBuilder, luego llame a ToString() al final.

+0

bueno, es una regla, he visto esta publicación antes (en otro tema) pero realmente no sé qué uso podría darle. – agnieszka

+0

¿podría explicar cómo podría usarlo? – agnieszka

+0

Ver mi edición al final. Simplemente cambie su StringBuilder a StringWriterWithEncoding (pasando la codificación que desee) y listo. –

3

De hecho, me resolvió el problema 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 va a utilizar un MemoryStream, al menos debe decodificarlo con la misma codificación que está utilizando anteriormente (es decir, Windows-1250, * not * ASCII). Prefiero mi versión, personalmente :) –

5

Sólo algunas explicaciones adicionales de por qué esto es así.

Las cadenas son secuencias de caracteres, no de bytes. Las cadenas, per se, no están "codificadas", porque están usando caracteres, que se almacenan como puntos de código Unicode. La codificación NO TIENE SENTIDO a nivel de secuencia.

Una codificación es una asignación de una secuencia de puntos de código (caracteres) a una secuencia de bytes (para el almacenamiento en sistemas basados ​​en bytes, como sistemas de archivos o memoria). El marco no le permite especificar codificaciones, a menos que haya una razón convincente para, como hacer que los puntos de código de 16 se ajusten al almacenamiento basado en bytes.

Así que cuando intenta escribir su XML en un StringBuilder, en realidad está construyendo una secuencia XML de caracteres y escribiéndola como una secuencia de caracteres, por lo que no se realiza ninguna codificación. Por lo tanto, no hay campo de Codificación.

Si desea utilizar una codificación, el XmlWriter tiene que escribir en una secuencia.

Acerca de la solución que encontraste con el MemoryStream, sin intención de ofender, pero solo está aleteando alrededor de los brazos y moviendo el aire caliente. Está codificando sus puntos de código con 'windows-1252', y luego analizándolo de nuevo a puntos de código. El único cambio que puede ocurrir es que los caracteres no definidos en windows-1252 se conviertan en '?' personaje en el proceso.

Para mí, la solución correcta podría ser la siguiente. Dependiendo de para qué se utiliza su función, puede pasar una secuencia como parámetro a su función, de modo que la persona que llama decida si debe escribirse en la memoria o en un archivo.Por lo tanto, se escribiría así:


     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

Solucioné la mina mediante la salida de la cadena a una variable volviendo a poner todas las referencias a UTF-16 con UTF-8 (mi aplicación necesita UTF8 codificación). Como estás usando una función, podrías hacer algo similar. Yo uso VB.net principalmente, pero creo que el C# se vería más o menos así.

return builder.ToString().Replace("utf-16", "utf-8"); 
Cuestiones relacionadas