XDocument.ToString () usuwa znacznik kodowania XML

103

Czy istnieje sposób uzyskania kodowania XML w funkcji toString ()?

Przykład:

xml.Save("myfile.xml");

prowadzi do

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

Ale

tb_output.Text = xml.toString();

prowadzi do takiego wyniku

<Cooperations>
  <Cooperation>
    <CooperationId>xxx</CooperationId>
    <CooperationName>Allianz Konzern</CooperationName>
    <LogicalCustomers>
    ...
Henrik P. Hessel
źródło

Odpowiedzi:

98

Albo jawnie napisz deklarację, albo użyj a StringWriteri wywołaj 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);
    }
}

Możesz łatwo dodać to jako metodę rozszerzenia:

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

Ma to tę zaletę, że nie wybuchnie, jeśli nie ma deklaracji :)

Następnie możesz użyć:

string x = doc.ToStringWithDeclaration();

Zauważ, że użyje to utf-16 jako kodowania, ponieważ jest to niejawne kodowanie w StringWriter. Możesz jednak wpłynąć na to samodzielnie, tworząc podklasę StringWriter, np. Aby zawsze używać UTF-8 .

Jon Skeet
źródło
14
Ma to mały problem polegający na tym, że kodowanie w deklaracji XDocument jest ignorowane i zastępowane przez kodowanie StringWriter podczas zapisywania, co może być tym, czego chcesz, ale nie musi
Sam Holder
2
Następnie łączysz metodę rozszerzenia z: Utf8StringWriter ze stackoverflow.com/a/1564727/75963 ;)
Nick Josevski
12
Zauważyłem, że łatwiej jest użyć powyższej metody rozszerzającej, ale zwróć następujące ... return doc.Declaration + doc.ToString (); Jeśli deklaracja ma wartość null, skutkuje po prostu pustym ciągiem.
Steve G.
Dziwne, ale nie mogę go teraz uruchomić ( skrzypce .net ) - zawsze używa kodowania "utf-16". Zajrzałem do wnętrza XDocument.Save(TextWriter)implementacji i po prostu ignoruje kodowanie deklaracji, w przeciwieństwie do implementacji XDocument.Save(String)lub XDocument.Save(Stream). Zastanawiam się, dlaczego ...
Ilya Luzyanin
@IlyaLuzyanin: Tak, użyje "utf-16" jako kodowania, kiedy przekażesz a StringWriter, chyba że użyjesz takiego, który nadpisuje Encodingwłaściwość. Mam inną odpowiedź na ten temat. Myślałem, że mówisz, że całkowicie porzuciłeś "kodowanie" ...
Jon Skeet
46

Właściwość Declaration będzie zawierać deklarację XML. Aby uzyskać treść plus deklarację, możesz wykonać następujące czynności:

tb_output.Text = xml.Declaration.ToString() + xml.ToString()
Ryan Brunner
źródło
7
wygląda na to, że jeśli nie używasz nowej XDeclaration ("1.0", "utf-8", "tak") w swoim xdocument, spowoduje to błąd, ponieważ xml.Declaration ma wartość null. Ale xml.save wydaje się automatycznie wykrywać właściwe kodowanie.
Henrik P. Hessel
lubtb_output.Text = @"<?xml version=""1.0"" encoding=""utf-8"" ?>" + xml;
Bill Hoag
4
lub... = $"{xdoc.Declaration}{Environment.NewLine}{xdoc}";
WernerCD,
9

Użyj tego:

output.Text = String.Concat(xml.Declaration.ToString() , xml.ToString())
Farooq Kaiser
źródło
2
Bez tworzenia nowej deklaracji XDeclaration ("1.0", "utf-8", "tak") i dodawania do XDocument lub innego obiektu, xml.Declaration.ToString () wyrzuci wyjątek zerowy.
Ziggler
1
jest bezpieczniejsze jak poniżej, ponieważ Concat nie dba o ciągi zerowe: output.Text = String.Concat (xml.Declaration, xml)
dmihailescu
3

Podobało mi się to

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

Zobacz poniżej, co otrzymuję w DistributorInfo

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Distributors>
  <Distributor Id="12345678" />
  <Distributor Id="22222222" />
  <Distributor Id="11111111" />
</Distributors>
Ziggler
źródło
1
dobry przykład. kilka uwag: 1) użyj nowej XDeclaration ("1.0", "utf-8") zamiast nowej XDeclaration ("1.0", "utf-8", "tak"), 2) wstaw nową linię w ostatniej linii: dystrybutorzy. Declaration.ToString () + Environment.NewLine + distributors.ToString ()
Alexey Obukhov
2

Podobnie jak inne odpowiedzi +1, ale trochę więcej szczegółów na temat deklaracji i nieco dokładniejsza konkatenacja.

<xml />deklaracja powinna znajdować się w osobnym wierszu w sformatowanym pliku XML, więc upewniam się, że dodano nową linię. UWAGA: użycie Environment.Newlinetak spowoduje utworzenie nowej linii specyficznej dla platformy

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

Oba wyniki dają:

<?xml version="1.0" encoding="iso-8859-1"?>
<rss version="2.0"></rss>
sonjz
źródło
1

Kilka z tych odpowiedzi rozwiązuje prośbę nadawcy, ale wydaje się, że jest to zbyt skomplikowane. Oto prosta metoda rozszerzenia, która pozwala uniknąć konieczności stosowania oddzielnego modułu zapisującego, obsługuje brakującą deklarację i obsługuje standardowy parametr 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);
}

Aby użyć rozszerzenia, po prostu wymień xml.ToString() goxml.ToXmlString()

B2K
źródło
0

Możesz również użyć XmlWriter i wywołać metodę

Writer.WriteDocType() 

metoda.

Gus Paul
źródło
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
David
źródło