XmlWriter, aby zapisać do ciągu zamiast do pliku

118

Mam usługę WCF, która musi zwrócić ciąg XML. Ale wygląda na to, że piszący chce tylko utworzyć plik, a nie ciąg. Próbowałem:

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

To generuje błąd informujący, że nextXMLstring nie ma ścieżki do pliku. Chce czegoś takiego:

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

Jak mogę zbudować mój XML, a następnie zwrócić go jako ciąg?

Dzięki!!

Płomień
źródło

Odpowiedzi:

217

Musisz utworzyć StringWriter i przekazać go do XmlWriter.

Przeciążenie ciągu XmlWriter.Create dotyczy nazwy pliku.

Na przykład

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


  }
  return sw.ToString();
}
Richard
źródło
2
@Will: Cofnięto twoją zmianę. XmlTextWriter.Close () opróżni strumień do strumienia, więc postaraj się, aby stało się to przed wyodrębnieniem ciągu. (Mała różnica w tym przypadku, ale wolę robić to konsekwentnie, ponieważ semantyka flush klas * Writer i Stream nie zawsze jest jasno udokumentowana).
Richard
1
Tylko komentarz dla osób używających tego. Jeśli zdarzy ci się pominąć using () i zamiast tego normalnie zadeklarować XmlWriter, upewnij się, że wywołałeś xw.Flush przed wywołaniem sw.ToString (), w przeciwnym razie możesz nie uzyskać całej zawartości! (Oczywiście lepiej jest użyć nawiasów klamrowych ...)
Ravendarksky
Należy pamiętać, że poniższy kod ostrzega CA2202 podczas analizy kodu, metoda beacuse Dispose () zostanie wywołana dwukrotnie na obiekcie StringWriter
Łukasz Kosiak
113

Jak powiedział Richard, StringWriterjest droga naprzód. Jest jednak jeden problem: domyślnie StringWriterbędzie się reklamować jako będący w UTF-16. Zwykle XML jest w UTF-8. Możesz to naprawić, tworząc podklasę StringWriter;

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

Wpłynie to na oświadczenie sporządzone przez XmlWriter. Oczywiście, jeśli następnie napiszesz ciąg w innym miejscu w formie binarnej, upewnij się, że używasz kodowania, które pasuje do dowolnego kodowania, które naprawisz dla StringWriter. (Powyższy kod zawsze zakłada UTF-8; trywialne jest stworzenie bardziej ogólnej wersji, która akceptuje kodowanie w konstruktorze.)

Wtedy użyłbyś:

using (TextWriter writer = new Utf8StringWriter())
{
    using (XmlWriter xmlWriter = XmlWriter.Create(writer))
    {
        ...
    }
    return writer.ToString();
}
Jon Skeet
źródło
Jon, jesteś pewien, że writerto nie jest usuwane więcej niż raz?
rasx
2
@rasx: Może - ale to nie ma znaczenia.
Jon Skeet
30

Wiem, że to jest stare i odpowiedziałem, ale oto inny sposób, aby to zrobić. Szczególnie jeśli nie chcesz, aby BOM UTF8 znajdował się na początku ciągu i chcesz, aby tekst był wcięty:

using (var ms = new MemoryStream())
using (var x = new XmlTextWriter(ms, new UTF8Encoding(false)) 
                   { Formatting = Formatting.Indented })
{
     // ...
     return Encoding.UTF8.GetString(ms.ToArray());
}
brianary
źródło
3
Encoding.UTF8.GetString(ms.ToArray())to uproszczenie po powrocie.
SliverNinja - MSFT
1
ms.ToArray()nie zwraca żadnych pozycji, gdy próbowałem tego. Musiał dodać x.Close()lub przenieść instrukcję return tuż poza wewnętrzną instrukcję using.
Rich C
Czy utf8.GetString (ms.GetBuffer (), 0, (int) ms.Length); praca?
brianary
1
@Rich C - Podejrzewam, że to dlatego, że Twój strumień nie został opróżniony. XmlTextWriter zostałby usunięty poza jego instrukcją using, która spowodowałaby opróżnienie.
yourbuddypal
13

Zastosowanie StringBuilder:

var sb = new StringBuilder();
    using (XmlWriter xmlWriter = XmlWriter.Create(sb))
    {
        ...
    }
return sb.ToString();
Ria
źródło
1

Chłopaki nie zapominają o wywołaniu xmlWriter.Close () i xmlWriter.Dispose (), bo inaczej twój string nie zakończy tworzenia. Będzie to po prostu pusty ciąg

saunupe1911
źródło
Nie martw się, instrukcja using zajmie się usunięciem obiektu.
To jest pytanie z 2009 roku. Dlatego udzielenie odpowiedzi teraz byłoby przydatne dla przyszłych użytkowników, którzy mogą mieć podobne problemy. W związku z tym odpowiedzi na stare pytania, takie jak to, należy udzielić tylko wtedy, gdy mogą one jasno zidentyfikować problem i wyjaśnić / zapewnić rozwiązanie. Zazwyczaj próba angażowania OP w rozmowę jest bezowocna, ponieważ prawdopodobnie przeszli dalej.
MikeC
Przeglądałem wszystkie te przykłady i zastanawiałem się, dlaczego otrzymuję pusty ciąg. xmlWriter.Close()było rozwiązaniem.
Rafał Ryszkowski
-1

Cóż, myślę, że najprostszym i najszybszym rozwiązaniem byłoby po prostu:

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
źródło