XDocument.ToString () удаляет тег кодирования XML

103

Есть ли способ получить кодировку xml в функции toString ()?

Пример:

xml.Save("myfile.xml");

приводит к

<?xml version="1.0" encoding="utf-8"?>
<Cooperations>
  <Cooperation>
    <CooperationId>xxx</CooperationId>
    <CooperationName>Allianz Konzern</CooperationName>
    <LogicalCustomers>

Но

tb_output.Text = xml.toString();

приводит к такому выводу

<Cooperations>
  <Cooperation>
    <CooperationId>xxx</CooperationId>
    <CooperationName>Allianz Konzern</CooperationName>
    <LogicalCustomers>
    ...
Хенрик П. Хессель
источник

Ответы:

98

Либо явно напишите объявление, либо используйте StringWriterи вызовите Save():

using System;
using System.IO;
using System.Text;
using System.Xml.Linq;

class Test
{
    static void Main()
    {
        string xml = @"<?xml version='1.0' encoding='utf-8'?>
<Cooperations>
  <Cooperation />
</Cooperations>";

        XDocument doc = XDocument.Parse(xml);
        StringBuilder builder = new StringBuilder();
        using (TextWriter writer = new StringWriter(builder))
        {
            doc.Save(writer);
        }
        Console.WriteLine(builder);
    }
}

Вы можете легко добавить это как метод расширения:

public static string ToStringWithDeclaration(this XDocument doc)
{
    if (doc == null)
    {
        throw new ArgumentNullException("doc");
    }
    StringBuilder builder = new StringBuilder();
    using (TextWriter writer = new StringWriter(builder))
    {
        doc.Save(writer);
    }
    return builder.ToString();
}

Это имеет то преимущество, что он не взорвется, если нет декларации :)

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

string x = doc.ToStringWithDeclaration();

Обратите внимание, что в качестве кодировки будет использоваться utf-16, потому что это неявная кодировка в StringWriter. Вы можете повлиять на это самостоятельно, создав подкласс StringWriter, например, чтобы всегда использовать UTF-8 .

Джон Скит
источник
14
У этого есть небольшая проблема в том, что кодировка в объявлении XDocument игнорируется и заменяется кодировкой StringWriter при выполнении сохранения, что может быть или не быть тем, что вы хотите,
Сэм Холдер,
2
Затем вы комбинируете метод расширения с: Utf8StringWriter из stackoverflow.com/a/1564727/75963 ;)
Ник Йозевски
12
Было проще использовать метод расширения, указанный выше, но вернуть следующий ... return doc.Declaration + doc.ToString (); Если объявление равно нулю, результатом будет пустая строка.
Стив Г.
Странно, но я не могу заставить его работать сейчас ( скрипт .net ) - он всегда использует кодировку «utf-16». Я заглянул внутрь XDocument.Save(TextWriter)реализации, и она просто игнорирует кодировку объявления, в отличие от реализаций XDocument.Save(String)или XDocument.Save(Stream). Интересно, почему ...
Илья Лузянин
@IlyaLuzyanin: Да, он будет использовать "utf-16" в качестве кодировки, когда вы передаете a StringWriter, если вы не используете ту, которая переопределяет Encodingсвойство. У меня есть еще один ответ на этот счет. Я думал, вы говорили, что он полностью отбрасывает "кодировку" ...
Джон Скит,
46

Свойство Декларации будет содержать объявление XML. Чтобы получить объявление content plus, вы можете сделать следующее:

tb_output.Text = xml.Declaration.ToString() + xml.ToString()
Райан Бруннер
источник
7
кажется, что если вы не используете новый XDeclaration («1.0», «utf-8», «yes») в своем xdocument, это создает ошибку, потому что xml.Declaration имеет значение null. Но xml.save, похоже, автоматически определяет правильную кодировку.
Хенрик П. Хессель
или,tb_output.Text = @"<?xml version=""1.0"" encoding=""utf-8"" ?>" + xml;
Билл Хог
4
или... = $"{xdoc.Declaration}{Environment.NewLine}{xdoc}";
WernerCD
9

использовать это:

output.Text = String.Concat(xml.Declaration.ToString() , xml.ToString())
Фарук Кайзер
источник
2
Без создания нового XDeclaration («1.0», «utf-8», «yes») и добавления в XDocument или другой объект xml.Declaration.ToString () вызовет нулевое исключение.
Ziggler
1
это безопаснее, как показано ниже, потому что Concat не заботится о нулевых строках: output.Text = String.Concat (xml.Declaration, xml)
dmihailescu
3

Мне это понравилось

        string distributorInfo = string.Empty;

        XDocument distributors = new XDocument();

     //below is important else distributors.Declaration.ToString() throws null exception
        distributors.Declaration = new XDeclaration("1.0", "utf-8", "yes"); 

        XElement rootElement = new XElement("Distributors");
        XElement distributor = null;
        XAttribute id = null;

        distributor = new XElement("Distributor");
        id = new XAttribute("Id", "12345678");
        distributor.Add(id);
        rootElement.Add(distributor);

        distributor = new XElement("Distributor");
        id = new XAttribute("Id", "22222222");

        distributor.Add(id);

        rootElement.Add(distributor);         

        distributors.Add(rootElement);

        distributorInfo = String.Concat(distributors.Declaration.ToString(), distributors.ToString());

Пожалуйста, смотрите ниже, что я получаю от DistributorInfo

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Distributors>
  <Distributor Id="12345678" />
  <Distributor Id="22222222" />
  <Distributor Id="11111111" />
</Distributors>
Зигглер
источник
1
хороший пример. некоторые примечания: 1) используйте новый XDeclaration ("1.0", "utf-8") вместо нового XDeclaration ("1.0", "utf-8", "yes"), 2) вставьте новую строку в последнюю строку: распространители. Декларация.ToString () + Environment.NewLine + дистрибьюторы.ToString ()
Алексей Обухов
2

Подобно другим ответам +1, но немного подробнее об объявлении и немного более точной конкатенации.

<xml />объявление должно быть на отдельной строке в форматированном XML, поэтому я уверен, что мы добавили новую строку. ПРИМЕЧАНИЕ: при использовании Environment.Newlineтак будет создана новая строка для конкретной платформы

// Parse xml declaration menthod
XDocument document1 =
  XDocument.Parse(@"<?xml version=""1.0"" encoding=""iso-8859-1""?><rss version=""2.0""></rss>");
string result1 =
  document1.Declaration.ToString() +
  Environment.NewLine +
  document1.ToString() ;

// Declare xml declaration method
XDocument document2 = 
  XDocument.Parse(@"<rss version=""2.0""></rss>");
document2.Declaration =
  new XDeclaration("1.0", "iso-8859-1", null);
string result2 =
  document2.Declaration.ToString() +
  Environment.NewLine +
  document2.ToString() ;

Оба результата дают:

<?xml version="1.0" encoding="iso-8859-1"?>
<rss version="2.0"></rss>
Sonjz
источник
1

Некоторые из этих ответов решают вопрос автора, но кажутся слишком сложными. Вот простой метод расширения, который позволяет избежать необходимости в отдельном писателе, обрабатывает отсутствующее объявление и поддерживает стандартный параметр ToString SaveOptions.

public static string ToXmlString(this XDocument xdoc, SaveOptions options = SaveOptions.None)
{
    var newLine =  (options & SaveOptions.DisableFormatting) == SaveOptions.DisableFormatting ? "" : Environment.NewLine;
    return xdoc.Declaration == null ? xdoc.ToString(options) : xdoc.Declaration + newLine + xdoc.ToString(options);
}

Чтобы использовать расширение, просто замените xml.ToString()наxml.ToXmlString()

B2K
источник
0

Вы также можете использовать XmlWriter и вызвать

Writer.WriteDocType() 

метод.

Гас Пол
источник
0
string uploadCode = "UploadCode";
string LabName = "LabName";
XElement root = new XElement("TestLabs");
foreach (var item in returnList)
{  
       root.Add(new XElement("TestLab",
                new XElement(uploadCode, item.UploadCode),
                new XElement(LabName, item.LabName)
                            )
               );
}

XDocument returnXML = new XDocument(new XDeclaration("1.0", "UTF-8","yes"),
             root);

string returnVal;
using (var sw = new MemoryStream())
{
       using (var strw = new StreamWriter(sw, System.Text.UTF8Encoding.UTF8))
       {
              returnXML.Save(strw);
              returnVal = System.Text.UTF8Encoding.UTF8.GetString(sw.ToArray());
       }
}

// ReturnVal has the string with XML data with XML declaration tag
Дэвид
источник