it-swarm.com.ru

Как поместить атрибут кодирования в xml, отличный от utf-16, с помощью XmlWriter?

У меня есть функция создания некоторого 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();
}

Я установил кодировку, но после создания XmlWriter у нее есть кодировка utf-16. Я знаю, что это потому, что строки (и, я полагаю, StringBuilder) закодированы в utf-16, и вы не можете это изменить.
Так как я могу легко создать этот xml с атрибутом кодировки, установленным в «windows-1250»? он даже не должен кодироваться в этой кодировке, он просто должен иметь указанный атрибут.

Правка: он должен быть в .Net 2.0, поэтому любые новые элементы каркаса не могут быть использованы.

36
agnieszka

Вам нужно использовать StringWriter с соответствующей кодировкой. К сожалению, StringWriter не позволяет вам указать кодировку напрямую, поэтому вам нужен такой класс:

public sealed class StringWriterWithEncoding : StringWriter
{
    private readonly Encoding encoding;

    public StringWriterWithEncoding (Encoding encoding)
    {
        this.encoding = encoding;
    }

    public override Encoding Encoding
    {
        get { return encoding; }
    }
}

( Этот вопрос похож, но не совсем повторяется.)

Правка: Чтобы ответить на комментарий: передайте StringWriterWithEncoding в XmlWriter.Create вместо StringBuilder, затем вызовите ToString () для него в конце.

71
Jon Skeet

Просто несколько дополнительных объяснений, почему это так.

Строки - это последовательности символов, а не байты. Строки сами по себе не являются «кодированными», потому что они используют символы, которые хранятся в виде кодовых точек Unicode. Кодирование не имеет смысла на строковом уровне.

Кодирование - это отображение последовательности кодовых точек (символов) в последовательность байтов (для хранения в системах, основанных на байтах, таких как файловые системы или память). Инфраструктура не позволяет указывать кодировки, если нет веских причин, например, чтобы 16-битные кодовые точки помещались в хранилище на основе байтов.

Поэтому, когда вы пытаетесь записать свой XML в StringBuilder, вы фактически строите последовательность символов XML и записываете их как последовательность символов, поэтому кодирование не выполняется. Поэтому нет поля Кодировка.

Если вы хотите использовать кодировку, XmlWriter должен выполнить запись в поток.

О решении, которое вы нашли с MemoryStream, не обидно, а просто взмахом руками и движением горячего воздуха. Вы кодируете свои кодовые точки с помощью «windows-1252», а затем снова анализируете их до кодовых точек. Единственное изменение, которое может произойти, - это то, что символы, не определенные в windows-1252, преобразуются в '?' персонаж в процессе.

Для меня правильным решением может быть следующее. В зависимости от того, для чего используется ваша функция, вы можете передать поток в качестве параметра своей функции, чтобы вызывающий абонент решал, должен ли он быть записан в память или в файл. Так было бы написано так:


        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();
            }
        }
5
Laurent LA RIZZA
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());

Отсюда

5
EddiG

Я на самом деле решил проблему с 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;
        }
3
agnieszka

Я решил свою проблему путем вывода строки в переменную и замены любых ссылок на utf-16 на utf-8 (моему приложению требовалась кодировка UTF8). Поскольку вы используете функцию, вы можете сделать что-то подобное. В основном я использую VB.net, но я думаю, что C # будет выглядеть примерно так.

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