XmlWriter para gravar em uma string em vez de em um arquivo

118

Tenho um serviço WCF que precisa retornar uma string XML. Mas parece que o escritor quer apenas construir um arquivo, não uma string. Eu tentei:

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

Isso gera um erro dizendo que nextXMLstring não tem um caminho de arquivo. Ele quer algo como:

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

Como posso construir meu XML e depois retorná-lo como uma string ??

Obrigado!!

Chama
fonte

Respostas:

217

Você precisa criar um StringWriter e passá-lo para o XmlWriter.

A sobrecarga de string do XmlWriter.Create é para um nome de arquivo.

Por exemplo

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


  }
  return sw.ToString();
}
Richard
fonte
2
@Will: Reverteu sua mudança. XmlTextWriter.Close () irá liberar para o fluxo, portanto, deseja que isso aconteça antes de extrair a string. (Pouca diferença neste caso, mas prefira fazer isso de forma consistente porque a semântica de limpeza das classes * Writer e Stream nem sempre está claramente documentada.)
Richard
1
Apenas um comentário para as pessoas que usam isso. Se acontecer de você omitir using () e, em vez disso, declarar seu XmlWriter normalmente, certifique-se de chamar xw.Flush antes de chamar sw.ToString () ou então você não obterá todo o conteúdo! (Obviamente melhor usar os colchetes ...)
Ravendarksky
Lembre-se de que o código a seguir fornece um aviso CA2202 durante a análise do código, porque o método Dispose () será chamado duas vezes no objeto StringWriter
Łukasz Kosiak
113

Como disse Richard, StringWriteré o caminho a seguir. Porém, há um obstáculo: por padrão, StringWriterse anunciará como sendo UTF-16. Normalmente, o XML está em UTF-8. Você pode corrigir isso criando uma subclasse de StringWriter;

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

Isso afetará a declaração escrita por XmlWriter. Obviamente, se você escrever a string em outro lugar na forma binária, certifique-se de usar uma codificação que corresponda a qualquer codificação corrigida para o StringWriter. (O código acima sempre assume UTF-8; é trivial fazer uma versão mais geral que aceite uma codificação no construtor.)

Você então usaria:

using (TextWriter writer = new Utf8StringWriter())
{
    using (XmlWriter xmlWriter = XmlWriter.Create(writer))
    {
        ...
    }
    return writer.ToString();
}
Jon Skeet
fonte
Jon, tem certeza que writernão está sendo descartado mais de uma vez?
rasx
2
@rasx: Pode ser - mas isso não importa.
Jon Skeet
30

Eu sei que isso é antigo e respondido, mas aqui está outra maneira de fazer isso. Especialmente se você não quiser o BOM UTF8 no início de sua string e quiser que o texto seja recuado:

using (var ms = new MemoryStream())
using (var x = new XmlTextWriter(ms, new UTF8Encoding(false)) 
                   { Formatting = Formatting.Indented })
{
     // ...
     return Encoding.UTF8.GetString(ms.ToArray());
}
brianary
fonte
3
Encoding.UTF8.GetString(ms.ToArray())é uma simplificação no seu retorno.
SliverNinja - MSFT
1
ms.ToArray()não retorna nenhum item quando eu tentei isso. Tive que adicionar x.Close()ou mover a instrução return fora da instrução using interna.
Rich C
Utf8.GetString (ms.GetBuffer (), 0, (int) ms.Length); trabalhos?
brianary,
1
@Rich C - Suspeito que seja porque seu stream não foi liberado. O XmlTextWriter teria sido descartado fora de sua instrução using, o que faria com que fosse liberado.
yourbuddypal de
13

Use StringBuilder:

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

Pessoal, não esqueçam de chamar xmlWriter.Close () e xmlWriter.Dispose () ou então sua string não vai terminar de criar. Será apenas uma string vazia

saunupe1911
fonte
Não se preocupe, o uso de instrução tratará do descarte do objeto.
Esta é uma pergunta de 2009. Portanto, o valor em fornecer uma resposta agora seria para usuários futuros que possam ter problemas semelhantes. Conseqüentemente, respostas a perguntas antigas como esta só devem ser fornecidas se puderem identificar claramente o problema e explicar / fornecer uma solução. Geralmente, é inútil tentar envolver o OP em uma conversa, pois é provável que ele tenha mudado.
MikeC
Eu estava passando por todos esses exemplos e me pergunto por que recebo uma string vazia. xmlWriter.Close()foi a solução.
Rafał Ryszkowski
-1

Bem, acho que a solução mais simples e rápida aqui seria apenas:

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
fonte