c# encoding xmlwriter

c# - ¿Cómo poner un atributo de codificación en xml otro que utf-16 con XmlWriter?



stringwriter encoding utf 8 c# (5)

Tengo una función que crea algo de 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(); }

Configuré una codificación pero después de crear XmlWriter, 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 para que no se puedan usar los nuevos elementos del framework.


De hecho, resolví el problema con 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; }


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

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 codificación. Por lo tanto, no hay campo de Codificación.

Si desea usar una codificación, 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 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. 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í


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 codificación 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 así.

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


Necesita usar un StringWriter con la codificación adecuada. Desafortunadamente StringWriter no le permite especificar la codificación 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.