Подтвердить что ты не робот

Как поместить атрибут кодирования в 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"? он даже не должен быть закодирован в этой кодировке, он просто должен иметь указанный атрибут.

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

4b9b3361

Ответ 1

Вам нужно использовать 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; }
    }
}

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

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

Ответ 2

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

Строки - это последовательности символов, а не байты. Строки сами по себе не "закодированы", потому что они используют символы, которые хранятся как кодовые страницы Unicode. Кодирование НЕ СДЕЛАТЬ SENSE на уровне String.

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

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

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

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

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


        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();
            }
        }

Ответ 3

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());

Отсюда

Ответ 4

Я действительно решил проблему с 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;
        }

Ответ 5

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

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