XmlWriter para escribir en una cadena en lugar de en un archivo

118

Tengo un servicio WCF que necesita devolver una cadena de XML. Pero parece que el escritor solo quiere crear un archivo, no una cadena. Lo intenté:

string nextXMLstring = "";
using (XmlWriter writer = XmlWriter.Create(nextXMLstring))

Esto genera un error que indica que nextXMLstring no tiene una ruta de archivo. Quiere algo como:

using (XmlWriter writer = XmlWriter.Create("nextXMLstring.xml"))

¿Cómo puedo construir mi XML y luego devolverlo como una cadena?

¡¡Gracias!!

Resplandor
fuente

Respuestas:

217

Necesita crear un StringWriter y pasarlo al XmlWriter.

La sobrecarga de cadenas de XmlWriter.Create es para un nombre de archivo.

P.ej

using (var sw = new StringWriter()) {
  using (var xw = XmlWriter.Create(sw)) {
    // Build Xml with xw.


  }
  return sw.ToString();
}
Ricardo
fuente
2
@Will: Retiró su cambio. XmlTextWriter.Close () se descargará en la secuencia, así que desea que eso suceda antes de extraer la cadena. (Poca diferencia en este caso, pero prefiero hacer esto de manera consistente porque la semántica flush de las clases * Writer y Stream no siempre está claramente documentada).
Richard
1
Solo un comentario para las personas que usan esto. Si omite using () y en su lugar declara su XmlWriter normalmente, asegúrese de llamar a xw.Flush antes de llamar a sw.ToString () o de lo contrario, ¡es posible que no obtenga todo el contenido! (Obviamente, es mejor usar los corchetes de uso ...)
Ravendarksky
Tenga en cuenta que el siguiente código da una advertencia de CA2202 durante el análisis de código, porque el método Dispose () se llamará dos veces en el objeto StringWriter
Łukasz Kosiak
113

Como dijo Richard, StringWriteres el camino a seguir. Sin embargo, hay un inconveniente: de forma predeterminada, StringWriterse anunciará como en UTF-16. Por lo general, XML está en UTF-8. Puede arreglar esto subclasificando StringWriter;

public class Utf8StringWriter : StringWriter
{
    public override Encoding Encoding
    {
         get { return Encoding.UTF8; }
    }
}

Esto afectará la declaración escrita por XmlWriter. Por supuesto, si luego escribe la cadena en otro lugar en forma binaria, asegúrese de usar una codificación que coincida con la codificación que corrija para StringWriter. (El código anterior siempre asume UTF-8; es trivial hacer una versión más general que acepte una codificación en el constructor).

Luego usarías:

using (TextWriter writer = new Utf8StringWriter())
{
    using (XmlWriter xmlWriter = XmlWriter.Create(writer))
    {
        ...
    }
    return writer.ToString();
}
Jon Skeet
fuente
Jon, ¿estás seguro de que writerno se va a deshacer más de una vez?
rasx
2
@rasx: Podría ser, pero eso no importará.
Jon Skeet
30

Sé que esto es antiguo y está resuelto, pero aquí hay otra forma de hacerlo. Particularmente si no desea la lista de materiales UTF8 al comienzo de su cadena y desea que el texto tenga sangría:

using (var ms = new MemoryStream())
using (var x = new XmlTextWriter(ms, new UTF8Encoding(false)) 
                   { Formatting = Formatting.Indented })
{
     // ...
     return Encoding.UTF8.GetString(ms.ToArray());
}
Brianary
fuente
3
Encoding.UTF8.GetString(ms.ToArray())es una simplificación a su regreso.
SliverNinja - MSFT
1
ms.ToArray()no devuelve ningún artículo cuando probé esto. Tuve que agregar x.Close()o mover la declaración de retorno justo fuera de la declaración de uso interna.
Rich C
¿Utf8.GetString (ms.GetBuffer (), 0, (int) ms.Length); ¿trabajo?
brianary
1
@Rich C: sospecho que esto se debe a que su transmisión no se descargó. El XmlTextWriter se habría eliminado fuera de su declaración using, lo que provocaría que se vacíe.
yourbuddypal
13

Utilizar StringBuilder:

var sb = new StringBuilder();
    using (XmlWriter xmlWriter = XmlWriter.Create(sb))
    {
        ...
    }
return sb.ToString();
Ria
fuente
1

Los chicos no se olviden de llamar a xmlWriter.Close () y xmlWriter.Dispose () o de lo contrario su cadena no terminará de crearse. Será solo una cadena vacía

saunupe1911
fuente
No se preocupe, el uso de declaración manejará la eliminación del objeto.
Esta es una pregunta de 2009. Por lo tanto, el valor de proporcionar una respuesta ahora sería para los futuros usuarios que pudieran tener problemas similares. En consecuencia, las respuestas a preguntas antiguas como esta solo deben proporcionarse si pueden identificar claramente el problema y explicar / proporcionar una solución. Por lo general, es inútil intentar entablar una conversación con el OP, ya que es probable que hayan seguido adelante.
MikeC
Estaba revisando todos estos ejemplos y me preguntaba por qué obtengo una cadena vacía. xmlWriter.Close()fue la solución.
Rafał Ryszkowski
-1

Bueno, creo que la solución más simple y rápida aquí sería simplemente:

StringBuilder sb = new StringBuilder();

using (var writer = XmlWriter.Create(sb, settings))
{
    ... // Whatever code you have/need :)

    sb = sb.Replace("encoding=\"utf-16\"", "encoding=\"utf-8\""); //Or whatever uft you want/use.
    //Before you finally save it:
    File.WriteAllText("path\\dataName.xml", sb.ToString());
}
Deniz
fuente