118 votes

XDocument.ToString() laisse tomber la balise d'encodage XML

Existe-t-il un moyen d'obtenir l'encodage xml dans la fonction toString() ?

Exemple :

xml.Save("myfile.xml");

conduit à

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

Mais

tb_output.Text = xml.toString();

conduit à une sortie comme celle-ci

<Cooperations>
  <Cooperation>
    <CooperationId>xxx</CooperationId>
    <CooperationName>Allianz Konzern</CooperationName>
    <LogicalCustomers>
    ...

104voto

Jon Skeet Points 692016

Soit vous écrivez explicitement la déclaration, soit vous utilisez une balise StringWriter et appeler 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);
    }
}

Vous pourriez facilement l'ajouter comme méthode d'extension :

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

Cela a l'avantage qu'il n'y aura pas d'explosion s'il y a n'est pas une déclaration :)

Alors vous pouvez utiliser :

string x = doc.ToStringWithDeclaration();

Notez que cela utilisera l'encodage utf-16, parce que c'est l'encodage implicite dans le fichier StringWriter . Vous pouvez cependant influencer cela vous-même en créant une sous-classe de StringWriter par exemple pour toujours utiliser UTF-8 .

14 votes

Il y a un petit problème dans la mesure où l'encodage de la déclaration XDocument est ignoré et remplacé par l'encodage du StringWriter lors de l'enregistrement, ce qui peut ou non correspondre à ce que vous souhaitez.

2 votes

Ensuite, vous combinez la méthode d'extension avec : Utf8StringWriter de stackoverflow.com/a/1564727/75963 ;)

12 votes

J'ai trouvé plus simple d'utiliser la méthode d'extension ci-dessus mais de retourner ce qui suit... return doc.Declaration + doc.ToString() ; Si la déclaration est nulle, cela donne juste une chaîne vide.

56voto

Ryan Brunner Points 8983

La propriété Declaration contiendra la déclaration XML. Pour obtenir le contenu plus la déclaration, vous pouvez faire ce qui suit :

tb_output.Text = xml.Declaration.ToString() + xml.ToString()

7 votes

Il semble que si vous n'utilisez pas new XDeclaration("1.0", "utf-8", "yes") dans votre xdocument, cela crée une erreur car xml.Declaration est null. Mais xml.save semble détecter automatiquement le bon encodage.

0 votes

Ou, tb_output.Text = @"<?xml version=""1.0"" encoding=""utf-8"" ?>" + xml;

4 votes

Ou ... = $"{xdoc.Declaration}{Environment.NewLine}{xdoc}";

13voto

Farooq Kaiser Points 229

Utilisez ça :

output.Text = String.Concat(xml.Declaration.ToString() , xml.ToString())

2 votes

Sans créer une nouvelle XDeclaration("1.0", "utf-8", "yes") et l'ajouter dans un XDocument ou un autre objet, xml.Declaration.ToString() lancera une exception nulle.

1 votes

C'est plus sûr comme ci-dessous parce que Concat ne se soucie pas des chaînes nulles : output.Text = String.Concat(xml.Declaration , xml)

3voto

Ziggler Points 105

J'ai aimé ça.

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

Veuillez voir ci-dessous ce que j'obtiens dans distributorInfo

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Distributors>
  <Distributor Id="12345678" />
  <Distributor Id="22222222" />
  <Distributor Id="11111111" />
</Distributors>

2voto

B2K Points 919

Quelques-unes de ces réponses répondent à la demande du posteur, mais semblent trop compliquées. Voici une méthode d'extension simple qui évite le besoin d'un rédacteur séparé, gère une déclaration manquante et prend en charge le paramètre standard 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);
}

Pour utiliser l'extension, il suffit de remplacer xml.ToString() con xml.ToXmlString()

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X