XmlWriter pour écrire dans une chaîne au lieu de dans un fichier

118

J'ai un service WCF qui doit renvoyer une chaîne de XML. Mais il semble que le rédacteur souhaite uniquement créer un fichier, pas une chaîne. J'ai essayé:

string nextXMLstring = "";
using (XmlWriter writer = XmlWriter.Create(nextXMLstring))

Cela génère une erreur indiquant que nextXMLstring n'a pas de chemin de fichier. Il veut quelque chose comme:

using (XmlWriter writer = XmlWriter.Create("nextXMLstring.xml"))

Comment puis-je construire mon XML puis le renvoyer sous forme de chaîne?

Merci!!

Flamber
la source

Réponses:

217

Vous devez créer un StringWriter et le transmettre à XmlWriter.

La surcharge de chaîne de XmlWriter.Create est pour un nom de fichier.

Par exemple

using (var sw = new StringWriter()) {
  using (var xw = XmlWriter.Create(sw)) {
    // Build Xml with xw.


  }
  return sw.ToString();
}
Richard
la source
2
@ Will: Annulé votre changement. XmlTextWriter.Close () se videra dans le flux, nous voulons donc que cela se produise avant d'extraire la chaîne. (Peu de différence dans ce cas, mais préférez le faire de manière cohérente car la sémantique de flush des classes * Writer et Stream n'est pas toujours clairement documentée.)
Richard
1
Juste un commentaire pour les personnes qui l'utilisent. Si vous omettez d'utiliser () et déclarez à la place votre XmlWriter normalement, assurez-vous d'appeler xw.Flush avant d'appeler sw.ToString (), sinon vous risquez de ne pas obtenir tout le contenu! (De toute évidence, il vaut mieux utiliser les parenthèses ...)
Ravendarksky
Gardez à l'esprit que le code suivant donne un avertissement à CA2202 lors de l'analyse de code, car la méthode Dispose () sera appelée deux fois sur l'objet StringWriter
Łukasz Kosiak
113

Comme l'a dit Richard, StringWriterc'est la voie à suivre. Il y a cependant un hic: par défaut, il StringWriters'affichera comme étant en UTF-16. Le XML est généralement en UTF-8. Vous pouvez résoudre ce problème en sous-classant StringWriter;

public class Utf8StringWriter : StringWriter
{
    public override Encoding Encoding
    {
         get { return Encoding.UTF8; }
    }
}

Cela affectera la déclaration rédigée par XmlWriter. Bien sûr, si vous écrivez ensuite la chaîne ailleurs sous forme binaire, assurez-vous d'utiliser un codage qui correspond à celui que vous fixez pour le StringWriter. (Le code ci-dessus suppose toujours UTF-8; il est trivial de créer une version plus générale qui accepte un encodage dans le constructeur.)

Vous utiliseriez alors:

using (TextWriter writer = new Utf8StringWriter())
{
    using (XmlWriter xmlWriter = XmlWriter.Create(writer))
    {
        ...
    }
    return writer.ToString();
}
Jon Skeet
la source
Jon, es-tu sûr que ce writern'est pas éliminé plus d'une fois?
rasx
2
@rasx: C'est peut-être le cas - mais cela n'a pas d'importance.
Jon Skeet
30

Je sais que c'est vieux et répondu, mais voici une autre façon de le faire. En particulier si vous ne voulez pas la nomenclature UTF8 au début de votre chaîne et que vous voulez que le texte soit mis en retrait:

using (var ms = new MemoryStream())
using (var x = new XmlTextWriter(ms, new UTF8Encoding(false)) 
                   { Formatting = Formatting.Indented })
{
     // ...
     return Encoding.UTF8.GetString(ms.ToArray());
}
Brianary
la source
3
Encoding.UTF8.GetString(ms.ToArray())est une simplification à votre retour.
SliverNinja - MSFT
1
ms.ToArray()ne renvoie aucun élément lorsque j'ai essayé cela. J'ai dû ajouter x.Close()ou déplacer l'instruction return juste à l'extérieur de l'instruction using interne.
Rich C
Est-ce que utf8.GetString (ms.GetBuffer (), 0, (int) ms.Length); travail?
brianary
1
@ Rich C - Je soupçonne que c'est parce que votre flux n'a pas été vidé. Le XmlTextWriter aurait été supprimé en dehors de son instruction using, ce qui entraînerait son vidage.
yourbuddypal
15

Utilisez StringBuilder:

var sb = new StringBuilder();
    using (XmlWriter xmlWriter = XmlWriter.Create(sb))
    {
        ...
    }
return sb.ToString();
Ria
la source
1

Les gars n'oublient pas d'appeler xmlWriter.Close () et xmlWriter.Dispose () sinon votre chaîne ne finira pas de créer. Ce sera juste une chaîne vide

saunupe1911
la source
Ne vous inquiétez pas, l'utilisation de l'instruction gérera l'élimination de l'objet.
Il s'agit d'une question de 2009. Donc, la valeur de fournir une réponse maintenant serait pour les futurs utilisateurs qui pourraient avoir des problèmes similaires. Par conséquent, les réponses aux anciennes questions comme celle-ci ne devraient être fournies que si elles peuvent identifier clairement le problème et expliquer / fournir une solution. Il est généralement infructueux d'essayer d'engager le PO dans une conversation car il est susceptible d'avoir évolué.
MikeC
Je passais en revue tous ces exemples et je me demandais pourquoi j'obtenais une chaîne vide. xmlWriter.Close()était la solution.
Rafał Ryszkowski
-1

Eh bien, je pense que la solution la plus simple et la plus rapide ici serait simplement de:

StringBuilder sb = new StringBuilder();

using (var writer = XmlWriter.Create(sb, settings))
{
    ... // Whatever code you have/need :)

    sb = sb.Replace("encoding=\"utf-16\"", "encoding=\"utf-8\""); //Or whatever uft you want/use.
    //Before you finally save it:
    File.WriteAllText("path\\dataName.xml", sb.ToString());
}
Deniz
la source