¿Cómo poner un atributo de encoding en xml otro que utf-16 con XmlWriter?

Tengo una función que crea algo de XmlDocument:

public string CreateOutputXmlString(ICollection 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(); } 

Configuré una encoding pero después de crear XmlWriter, tiene encoding 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 encoding establecido en “windows-1250”? ni siquiera tiene que estar codificado en esta encoding, solo tiene que tener el atributo especificado.

editar: tiene que estar en .Net 2.0 para que no se puedan usar los nuevos elementos del framework.

Necesita usar un StringWriter con la encoding adecuada. Desafortunadamente StringWriter no le permite especificar la encoding directamente, por lo que necesita una clase como esta:

 public sealed class StringWriterWithEncoding : StringWriter { private readonly Encoding encoding; public StringWriterWithEncoding (Encoding encoding) { this.encoding = encoding; } public override Encoding Encoding { get { return encoding; } } } 

( Esta pregunta es similar pero no es exactamente un duplicado).

EDITAR: Para responder el comentario: pase el StringWriterWithEncoding a XmlWriter.Create en lugar de StringBuilder, luego llame a ToString () al final.

Solo algunas explicaciones adicionales sobre por qué esto es así.

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

Una encoding 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.

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

Si desea utilizar una encoding, el XmlWriter debe escribir en un Stream.

Acerca de la solución que encontraste con MemoryStream, sin intención de ofender, pero solo está aleteando alrededor de los arms y moviendo el air 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. Entonces 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(); } } 
 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()); 

De aquí

De hecho, resolví el problema con MemoryStream:

 public static string CreateOutputXmlString(ICollection 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; } 

Resolví el mío al enviar la cadena a una variable y luego reemplazar cualquier referencia a utf-16 con utf-8 (mi aplicación necesitaba encoding UTF8). 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");