XDocument: сохранение XML в файл без спецификации

Я создаю файл utf-8 XML, используя XDocument.

XDocument xml_document = new XDocument(
                    new XDeclaration("1.0", "utf-8", null),
                    new XElement(ROOT_NAME,                    
                    new XAttribute("note", note)
                )
            );
...
xml_document.Save(@file_path);

Файл создается правильно и успешно проверяется с помощью файла xsd.

Когда я пытаюсь загрузить XML-файл в онлайн-службу, служба сообщает, что мой файл - wrong at line 1; Я обнаружил, что проблема вызвана спецификацией первых байтов файла.

Вы знаете, почему к файлу добавляется спецификация и как я могу сохранить файл без нее?

Как указано в отметке порядка байтов в статье Википедии:

Хотя стандарт Unicode допускает спецификацию в UTF-8, он не требует и не рекомендует. Порядок байтов не имеет значения в UTF-8, поэтому спецификация служит только для идентификации текстового потока или файла как UTF-8 или для того, чтобы он был преобразован из другого формата, имеющего спецификацию

Это XDocument проблема, или мне следует связаться с парнями поставщика онлайн-услуг, чтобы попросить обновить парсер?


person systempuntoout    schedule 09.02.2011    source источник


Ответы (4)


Используйте XmlTextWriter и передайте его методу XDocument Save (), чтобы иметь больший контроль над типом используемой кодировки:

var doc = new XDocument(
    new XDeclaration("1.0", "utf-8", null),
    new XElement("root", new XAttribute("note", "boogers"))
);
using (var writer = new XmlTextWriter(".\\boogers.xml", new UTF8Encoding(false)))
{
    doc.Save(writer);
}

Конструктор класса UTF8Encoding имеет перегрузку, которая указывает, следует ли использовать BOM (Byte Order Mark) с логическим значением в вашем случае false.

Результат этого кода был проверен с помощью Notepad ++ для проверки кодировки файла.

person Quick Joe Smith    schedule 09.02.2011
comment
Когда вы открываете его с помощью Notepad ++, он все еще находится в utf-8 даже при использовании new UTF8Encoding(false)? - person systempuntoout; 09.02.2011
comment
Я думал, вам нужен UTF-8, только без спецификации? - person Quick Joe Smith; 09.02.2011
comment
да, это правильно. Я просто спрашивал, может ли new UTF8Encoding(false) иметь какое-то другое значение. - person systempuntoout; 09.02.2011
comment
Нет, логическое значение, переданное конструктору UTF8Encoding, просто контролирует, включает ли он спецификацию. true, чтобы включить, false, чтобы опустить. - person Quick Joe Smith; 09.02.2011
comment
Рассмотрите возможность добавления writer.Formatting = Formatting.Indented; - person Kevin Panko; 24.02.2014
comment
Кевин, это будет полностью зависеть от того, предназначен ли файл для просмотра людьми, иначе это просто потраченные байты. В вопросе не было достаточно подробностей, чтобы предположить, что это так. - person Quick Joe Smith; 25.02.2014
comment
Предупреждение. Решение Дерксара лучше. Начиная с .NET Framework 2.0, мы рекомендуем создавать экземпляры XmlWriter с помощью метода XmlWriter.Create и класса XmlWriterSettings, чтобы воспользоваться преимуществами новых функций. Источник: Конструктор XmlTextWriter (String, Encoding) (System.Xml) - person Stéphane Gourichon; 13.05.2016

Прежде всего: поставщик услуг ДОЛЖЕН обрабатывать его в соответствии со спецификацией XML, в которой указано, что спецификация может присутствовать в случае представления UTF-8.

Вы можете принудительно сохранить свой XML без спецификации следующим образом:

XmlWriterSettings settings = new XmlWriterSettings();
settings.Encoding = new UTF8Encoding(false); // The false means, do not emit the BOM.
using (XmlWriter w = XmlWriter.Create("my.xml", settings))
{
    doc.Save(w);
}

(Погуглил отсюда: http://social.msdn.microsoft.com/Forums/en/xmlandnetfx/thread/ccc08c65-01d7-43c6-adf3-1fc70fdb026a)

person Dercsár    schedule 09.02.2011
comment
Спецификация может присутствовать в случае представления UTF-8, вы можете указать мне на этот конкретный документ? - person systempuntoout; 09.02.2011
comment
Вот и все: w3.org/TR/2006/REC-xml -20060816 / # charencoding Первый абзац: все процессоры XML ДОЛЖНЫ иметь возможность читать объекты в кодировке UTF-8 и UTF-16. Кодировка UTF-8 включает (но не требует) спецификации (см. Комментарий Джо ниже), поэтому процессоры XML должны иметь возможность обрабатывать файлы UTF-8 с помощью спецификации. - person Dercsár; 09.02.2011
comment
Хотя стандарт Unicode допускает использование спецификации в UTF-8, он не требует и не рекомендует этого. Порядок байтов не имеет значения в UTF-8 - en.wikipedia.org/wiki/Byte_order_mark - person Quick Joe Smith; 09.02.2011
comment
Предупреждение: выполнение этого вместо doc.Save(filename) имеет побочный эффект: все записывается в одной строке. Если вы хотите, чтобы ваш файл оставался доступным для чтения, подумайте о добавлении settings.Indent = true; в код этого ответа. - person Stéphane Gourichon; 19.05.2016

Наиболее целесообразный способ избавиться от символа спецификации при использовании XDocument - просто сохранить документ, затем выполнить прямое чтение файла как файл, а затем записать его обратно. Подпрограммы File удаляют символ за вас:

        XDocument xTasks = new XDocument();
        XElement xRoot = new XElement("tasklist",
            new XAttribute("timestamp",lastUpdated),
            new XElement("lasttask",lastTask)
        );
        ...
        xTasks.Add(xRoot);
        xTasks.Save("tasks.xml");

        // read it straight in, write it straight back out. Done.
        string[] lines = File.ReadAllLines("tasks.xml");
        File.WriteAllLines("tasks.xml",lines);

(это глупо, но это работает ради целесообразности - по крайней мере, у вас будет хорошо сформированный файл для загрузки в ваш онлайн-провайдер);)

person Justin Rivers    schedule 04.11.2011
comment
Просто используйте XmlWriter.Create с XmlWriterSettings.Indent = true;. Здесь вы можете отформатировать свой вывод так, как считаете нужным. - person SvenL; 21.06.2018

Документами UTF-8

String XMLDec = xDoc.Declaration.ToString();
StringBuilder sb = new StringBuilder(XMLDec);
sb.Append(xDoc.ToString());
Encoding encoding = new UTF8Encoding(false); // false = without BOM
File.WriteAllText(outPath, sb.ToString(), encoding); 
person ketzer    schedule 02.12.2020
comment
Как уже ответили несколько раз. - person Gert Arnold; 02.12.2020