2010-01-27 15 views
1

Est-il possible d'avoir un seul flux et d'avoir plus d'un XmlWriter écrit dans ce flux et se retrouvent avec du XML bien formé?Un seul flux, plusieurs XmlWriters

J'ai une hiérarchie d'objets dans laquelle chaque objet est entièrement responsable de la sérialisation. Ma dernière tentative a été de créer un flux au niveau le plus élevé, puis de transmettre cette référence de flux vers le bas et de permettre à chaque objet de créer son propre XmlWriter pour se sérialiser dans le flux. Cependant, cela finit par créer des nœuds dans des nœuds parents incomplets (l'élément start n'est pas entièrement formé dans le parent avant que le contenu enfant ne soit écrit, même avec un vidage).

Il existe plusieurs domaines d'application, donc la transmission de la référence XmlWriter ne fonctionnera pas. Chaque objet renvoyait une chaîne et écrivait cette chaîne XML brute dans le flux, mais certaines chaînes devenaient très, très longues (collections). C'est pourquoi j'ai décidé d'un flux - afin que chaque objet puisse écrire de petits morceaux à la fois et qu'une instance de flux soit à la fois sérialisable et MBR.

J'ai décidé de ne pas utiliser XmlSerializer pour des raisons que je ne semblais pas documenter. Mais je vais faire confiance à mon jugement précédent à ce sujet.

Merci pour tout ce qui peut conduire à une compréhension plus approfondie de ce que je travaille avec.

Répondre

2

Vous pouvez simplement écrire les parties xml par classe en tant que chaînes dans le flux au lieu d'utiliser le XmlWriter. Cela vous permet un contrôle total sur les balises de fin. Mais j'ai créé une solution de contournement qui semble fonctionner. Cela vous permet de passer le flux qui est sérialisable entre appdomains.

Tout d'abord une classe d'assistance pour initialiser de nouveaux XmlWriters et corriger le flux avant de le transmettre.

public static class XmlWriterExt 
{ 
    /// <summary> 
    /// Make sure any previous tag is ended by writing dummy text, then backtracking the position 
    /// </summary> 
    public static void PrepareStream(this XmlWriter writer, Stream stream) 
    { 
     writer.WriteElementString("x", string.Empty); 
     writer.Flush(); 
     stream.Position -= 5; //backtrack the dummy element 
    } 

    /// <summary> 
    /// Get an xml writer which works on fragments and without the xml declaration 
    /// </summary> 
    public static XmlWriter GetWriter(Stream stream) 
    { 
     XmlWriterSettings settings = new XmlWriterSettings(); 
     settings.OmitXmlDeclaration = true; 
     settings.ConformanceLevel = ConformanceLevel.Fragment; 
     XmlWriter xmlWriter = XmlWriter.Create(stream, settings); 
     return xmlWriter; 
    } 
} 

Voici quelques classes de test imbriquées les unes dans les autres.

class TopClass 
{ 
    InnerClass _innerClass = new InnerClass(); 

    public void Serialize(Stream stream) 
    { 
     XmlWriter xmlWriter = XmlWriterExt.GetWriter(stream); 
     xmlWriter.WriteStartElement("top"); 
     xmlWriter.PrepareStream(stream); 
     _innerClass.Serialize(stream); 
     xmlWriter.WriteEndElement(); 
     xmlWriter.Flush(); 
    } 
} 

class InnerClass 
{ 
    public void Serialize(Stream stream) 
    { 
     XmlWriter xmlWriter = XmlWriterExt.GetWriter(stream); 
     xmlWriter.WriteElementString("b", "testing"); 
     xmlWriter.Flush(); 
    } 
} 

Code d'essai

MemoryStream ms = new MemoryStream(); 
TopClass top = new TopClass(); 
top.Serialize(ms); 

string result = Encoding.UTF8.GetString(ms.ToArray()); 

et le résultat

<top> 
    <b>testing</b> 
</top> 
+0

ConformanceLevel.Fragment! Argh! C'est pourquoi je poste - j'apprends quelque chose de nouveau à chaque fois. – redman