XmlWriter для записи в строку, а не в файл

118

У меня есть служба WCF, которая должна возвращать строку XML. Но похоже, что писатель хочет создать только файл, а не строку. Я попытался:

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

Это генерирует ошибку о том, что nextXMLstring не имеет пути к файлу. Ему нужно что-то вроде:

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

Как я могу создать свой XML, а затем вернуть его в виде строки?

Спасибо!!

полыхать
источник

Ответы:

217

Вам нужно создать StringWriter и передать его XmlWriter.

Перегрузка строки XmlWriter.Create предназначена для имени файла.

Например

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


  }
  return sw.ToString();
}
Ричард
источник
2
@Will: Откатил ваше изменение. XmlTextWriter.Close () будет сброшен в поток, поэтому нужно, чтобы это произошло до извлечения строки. (Небольшая разница в этом случае, но предпочитаю делать это последовательно, потому что семантика сброса классов * Writer и Stream не всегда четко документирована.)
Ричард
1
Просто комментарий для людей, использующих это. Если вы опустите using () и вместо этого объявите свой XmlWriter в обычном режиме, обязательно вызовите xw.Flush перед вызовом sw.ToString (), иначе вы можете не получить весь контент! (Очевидно, лучше использовать скобки ...)
Равендаркский
Имейте в виду, что следующий код выдает предупреждение CA2202 во время анализа кода, потому что метод Dispose () будет вызываться дважды для объекта StringWriter
Лукаш Косяк
113

Как сказал Ричард, StringWriterэто путь вперед. Однако есть одна загвоздка: по умолчанию он StringWriterбудет рекламировать себя как находящийся в UTF-16. Обычно XML находится в UTF-8. Вы можете исправить это, создав подкласс StringWriter;

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

Это повлияет на декларацию, написанную пользователем XmlWriter. Конечно, если вы затем запишете строку в другом месте в двоичной форме, убедитесь, что вы используете кодировку, которая соответствует той кодировке, которую вы исправили для файла StringWriter. (Приведенный выше код всегда предполагает UTF-8; тривиально создать более общую версию, которая принимает кодировку в конструкторе.)

Затем вы должны использовать:

using (TextWriter writer = new Utf8StringWriter())
{
    using (XmlWriter xmlWriter = XmlWriter.Create(writer))
    {
        ...
    }
    return writer.ToString();
}
Джон Скит
источник
Джон, ты уверен, что writerэто не удаляется более одного раза?
rasx
2
@rasx: Может быть, но это не имеет значения.
Джон Скит,
30

Я знаю, что это старый ответ, но вот еще один способ сделать это. В частности, если вам не нужна спецификация UTF8 в начале строки и вы хотите, чтобы текст был с отступом:

using (var ms = new MemoryStream())
using (var x = new XmlTextWriter(ms, new UTF8Encoding(false)) 
                   { Formatting = Formatting.Indented })
{
     // ...
     return Encoding.UTF8.GetString(ms.ToArray());
}
brianary
источник
3
Encoding.UTF8.GetString(ms.ToArray())упрощение по возвращении.
SliverNinja - MSFT
1
ms.ToArray()когда я пробовал это, не возвращает никаких элементов. Пришлось добавить x.Close()или переместить оператор return сразу за пределы внутреннего оператора using.
Rich C
Имеет ли utf8.GetString (ms.GetBuffer (), 0, (int) ms.Length); работай?
brianary
1
@Rich C - я подозреваю, что это потому, что ваш поток не был сброшен. XmlTextWriter был бы удален за пределами своего оператора using, что привело бы к его очистке.
yourbuddypal
15

Использование StringBuilder:

var sb = new StringBuilder();
    using (XmlWriter xmlWriter = XmlWriter.Create(sb))
    {
        ...
    }
return sb.ToString();
Ria
источник
1

Ребята, не забудьте вызвать xmlWriter.Close () и xmlWriter.Dispose (), иначе ваша строка не завершит создание. Это будет просто пустая строка

saunupe1911
источник
Не волнуйтесь, оператор using обработает удаление объекта.
Это вопрос из 2009 года. Таким образом, ответ сейчас будет полезен для будущих пользователей, у которых могут быть похожие проблемы. Следовательно, ответы на старые вопросы, подобные этому, следует давать только в том случае, если они могут четко определить проблему и объяснить / предложить решение. Обычно бесполезно пытаться вовлечь ОП в разговор, поскольку они, скорее всего, ушли.
MikeC
Я просматривал все эти примеры и удивлялся, почему я получаю пустую строку. xmlWriter.Close()было решение.
Rafał Ryszkowski
-1

Что ж, я думаю, что самым простым и быстрым решением здесь было бы просто:

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
источник