2013-07-19 3 views
7

J'ai créé une classe C#:XmlSerializer Convertir C# objet en chaîne xml

public class books { 
    public int bookNum { get; set; } 
    public class book { 
     public string name { get; set; } 
     public class record { 
      public string borrowDate { get; set; } 
      public string returnDate { get; set; } 
     } 
     public record[] records { get; set; } 
    } 
    public book[] books { get; set; } 
} 

Mais est quand j'utilise XmlSerializer convertir en chaîne XML. Le résultat n'est pas le même que ci-dessous xml.

Quel est le problème de ma classe C#? Je veux utiliser XmlSerializer pour sortir le résultat au lieu d'utiliser XmlDocument.

Des idées? Merci d'avance!

<books> 
    <bookNum>2</bookNum> 
    <book> 
     <name>Book 1</name> 
     <record> 
      <borrowDate>2013-7-1</borrowDate> 
      <returnDate>2013-7-12</returnDate> 
     </record> 
     <record>    
      <borrowDate>2013-8-1</borrowDate> 
      <returnDate>2013-8-5</returnDate> 
     </record> 
    </book> 
    <book> 
     <name>Book 2</name> 
     <record> 
      <borrowDate>2013-6-1</borrowDate> 
      <returnDate>2013-6-12</returnDate> 
     </record> 
     <record>    
      <borrowDate>2013-7-1</borrowDate> 
      <returnDate>2013-7-5</returnDate> 
     </record> 
    </book> 
</books> 

EDIT

Ci-dessous mon code C# et le résultat ouput:

books books = new books { 
     bookNum = 2, 
     Books = new books.book[] { 
      new books.book { 
       name = "Book1", 
       records = new books.book.record[] { 
        new books.book.record { 
         borrowDate = "2013-1-3", 
         returnDate = "2013-1-5" 
        }, 
        new books.book.record { 
         borrowDate = "2013-2-3", 
         returnDate = "2013-4-5" 
        } 
       } 
      }, 
      new books.book { 
       name = "Book1", 
       records = new books.book.record[] { 
        new books.book.record { 
         borrowDate = "2013-1-3", 
         returnDate = "2013-1-5" 
        }, 
        new books.book.record { 
         borrowDate = "2013-2-3", 
         returnDate = "2013-4-5" 
        } 
       } 
      } 
     } 
    }; 


    XmlSerializer xsSubmit = new XmlSerializer(typeof(books)); 

    XmlDocument doc = new XmlDocument(); 

    System.IO.StringWriter sww = new System.IO.StringWriter(); 
    XmlWriter writer = XmlWriter.Create(sww); 
    xsSubmit.Serialize(writer, books); 
    var xml = sww.ToString(); // Your xml 
    context.Response.Write(xml); 

XML:

<books> 
    <bookNum>2</bookNum> 
    <Books> 
     <book> 
      <name>Book1</name> 
      <records> 
       <record> 
        <borrowDate>2013-1-3</borrowDate> 
        <returnDate>2013-1-5</returnDate> 
       </record> 
       <record> 
        <borrowDate>2013-2-3</borrowDate> 
        <returnDate>2013-4-5</returnDate> 
       </record> 
      </records> 
     </book> 
     <book> 
      <name>Book1</name> 
      <records> 
       <record> 
        <borrowDate>2013-1-3</borrowDate> 
        <returnDate>2013-1-5</returnDate> 
       </record> 
       <record> 
        <borrowDate>2013-2-3</borrowDate> 
        <returnDate>2013-4-5</returnDate> 
       </record> 
      </records> 
     </book> 
    </Books> 
</books> 
+1

publier la sortie du XMLSerializer? –

+0

"Le résultat n'est pas le même que ci-dessous xml" - comment c'est "pas le même"? Qu'est-ce que vous obtenez à la place? (Note de côté: vous utilisez un format inhabituel pour les dates en XML - ISO8601 YYYY-MM-DD) –

+0

si vous faites une sérialisation xml vous ne pouvez pas obtenir votre xml personnalisé – Manish

Répondre

7

Vous ne pouvez pas sérialiser la classe de votre q uestion en utilisant des outils de sérialisation standard de sorte qu'il aura <book> entrées au même niveau que le nœud <bookNum>.

Lorsque la classe enregistrée avec la liste des outils de sérialisation standard de votre <book> nœuds sera toujours niché dans le noeud séparé du tableau qui sera sur le même niveau que le noeud <bookNum>. Mêmes préoccupations records champ tableau sur book classe.

Pour générer sortie XML que vous voulez - avec <book> nœuds sur le même niveau que <bookNum> noeud - vous devrez implémenter l'interface IXmlSerializable dans votre classe books pour la sérialisation personnalisée. Pour voir des exemples de mise en œuvre IXmlSerializable, visitez ces liens: StackOverflow answer, CodeProject article.

Une autre solution sera - comme indiqué dans user Alexandr commentaire à ma réponse - pour hériter votre classe books à partir du type List<book> et d'avoir sur votre champ de classe bookrecords de type classe qui est héritée de le type List<record>.

Lorsque la sérialisation classe de votre question, en supposant que votre assignée bonne XmlRoot, XmlElement, XmlArray and XmlArrayItem attributes comme suit:

[XmlRoot("books")] 
public class books 
{ 
    [XmlElement("bookNum")] 
    public int bookNum { get; set; } 

    [XmlRoot("book")] 
    public class book 
    { 
     [XmlElement("name")] 
     public string name { get; set; } 

     [XmlRoot("record")] 
     public class record 
     { 
      [XmlElement("borrowDate")] 
      public string borrowDate { get; set; } 

      [XmlElement("returnDate")] 
      public string returnDate { get; set; } 
     } 

     [XmlArray("borrowRecords")] 
     [XmlArrayItem("record")] 
     public record[] records { get; set; } 
    } 

    [XmlArray("booksList")] 
    [XmlArrayItem("book")] 
    public book[] books { get; set; } 
} 

vous obtiendrez XML sortie comme suit:

<books> 
    <bookNum>2</bookNum> 
    <booksList> 
     <book> 
      <name>Book 1</name> 
      <borrowRecords> 
       <record> 
        <borrowDate>2013-1-3</borrowDate> 
        <returnDate>2013-1-5</returnDate> 
       </record> 
       <record>    
        <borrowDate>2013-2-3</borrowDate> 
        <returnDate>2013-4-5</returnDate> 
       </record> 
      </borrowRecords> 
     </book> 
     <book> 
      <name>Book 2</name> 
      <borrowRecords> 
       <record> 
        <borrowDate>2013-1-3</borrowDate> 
        <returnDate>2013-1-5</returnDate> 
       </record> 
       <record>    
        <borrowDate>2013-2-3</borrowDate> 
        <returnDate>2013-4-5</returnDate> 
       </record> 
      </borrowRecords> 
     </book> 
    </booksList> 
</books> 
+1

Vous êtes sur de ça? Parce que je pense que je l'ai fait il ya un certain temps en ayant la classe racine ('books' dans ce cas) étendre' List 'et en lui appliquant des propriétés avec l'attribut' XmlElement' ... – Alxandr

+0

@Alxandr Inheriting list est une autre option - cela change un peu les conditions du problème. +1 pour bonne idée –

+0

Je suppose aussi que c'est faisable sans hériter de la liste, simplement en fournissant une méthode 'Add', mais je ne sais pas comment les internes du XmlSerializer fonctionnent ... – Alxandr

8

J'ai fait la modification suivante votre code de classe. Je suis incapable de dupliquer la sérialisation XML à l'aide du sérialiseur par défaut, car il ne dupliquera pas l'élément 'Record' sans lui donner un élément conteneur.

[System.Xml.Serialization.XmlRoot("books")] 
public class books 
{ 
    public int bookNum { get; set; } 
    public class book { 
     public string name { get; set; } 
     public class record { 
      public string borrowDate { get; set; } 
      public string returnDate { get; set; } 
     } 
     public record[] records { get; set; } 
    } 
    public book[] books { get; set; } 
} 

sérialisation cela me donne la sortie suivante

<books xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <bookNum>2</bookNum> 
    <books> 
    <book> 
     <name>first</name> 
     <records> 
     <record> 
      <borrowDate>19/07/2013 4:41:29 PM</borrowDate> 
      <returnDate>19/07/2013 4:41:29 PM</returnDate> 
     </record> 
     </records> 
    </book> 
    </books> 
</books> 

en utilisant ce code de test

books bks = new books(); 
bks.bookNum = 2; 
bks.books = new books.book[]{ new books.book{name="first", records = new books.book.record[] {new books.book.record{borrowDate = DateTime.Now.ToString(), returnDate = DateTime.Now.ToString()}}}}; 

System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(books)); 

XmlWriterSettings settings = new XmlWriterSettings(); 
settings.Encoding = new UnicodeEncoding(false, false); // no BOM in a .NET string 
settings.Indent = true; 
settings.OmitXmlDeclaration = true; 

using(StringWriter textWriter = new StringWriter()) { 
    using(XmlWriter xmlWriter = XmlWriter.Create(textWriter, settings)) { 
     serializer.Serialize(xmlWriter, bks); 
    } 
    return textWriter.ToString(); //This is the output as a string 
} 
+0

Nous ne pouvons pas laisser le et être le même niveau? –

+1

livres est l'élément de conteneur pour le livre. C'est ainsi qu'il sait qu'ils appartiennent à la même propriété lors de la re-sérialisation. –

2

Je sais que cela est deux ou trois ans de retard, mais je l'ai été en mesure d'atteindre le structure que vous avez désiré juste en utilisant XmlElementAttribute.

J'ai découvert cela en utilisant XSD.exe pour générer des définitions de schéma à partir de xml et générer du code .Net à partir de fichiers xsd. Pour autant que je sache, cela fonctionne dans .Net 3.5 à 4.6.

Voici la définition de classe je:

public class books 
{ 
    public int bookNum { get; set; } 
    public class book { 
     public string name { get; set; } 
     public class record { 
      public string borrowDate { get; set; } 
      public string returnDate { get; set; } 
     } 
     [XmlElement("record")] 
     public record[] records { get; set; } 
    } 
    [XmlElement("book")] 
    public book[] allBooks { get; set; } 
} 

Et voici un extrait LinqPad qui illustre la sérialisation/désérialisation (basé sur l'extrait de code de David Colwell, merci BTW pour la pointe sur la façon d'exclure la nomenclature, il était juste ce que je cherchais):

books bks = new books(); 
books bks2 = null; 
bks.bookNum = 2; 
bks.allBooks = new books.book[] 
     { 
      new books.book { 
       name="book 1", 
       records = new books.book.record[] { 
         new books.book.record{borrowDate = DateTime.Now.ToString(), returnDate = DateTime.Now.ToString()} 
        } 
       }, 
      new books.book { 
       name="book 2", 
       records = new books.book.record[] { 
         new books.book.record{borrowDate = DateTime.Now.ToString(), returnDate = DateTime.Now.ToString()}, 
         new books.book.record{borrowDate = DateTime.Now.ToString(), returnDate = DateTime.Now.ToString()}} 
        }, 
     }; 
string xmlString; 

System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(books)); 

XmlWriterSettings settings = new XmlWriterSettings(); 
settings.Encoding = new UnicodeEncoding(false, false); // no BOM in a .NET string 
settings.Indent = true; 
settings.OmitXmlDeclaration = true; 

XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); 
// exclude xsi and xsd namespaces by adding the following: 
ns.Add(string.Empty, string.Empty); 

using(StringWriter textWriter = new StringWriter()) { 
    using(XmlWriter xmlWriter = XmlWriter.Create(textWriter, settings)) { 
     serializer.Serialize(xmlWriter, bks, ns); 
    } 
    xmlString = textWriter.ToString(); //This is the output as a string 
} 

xmlString.Dump(); 

// Deserialize the xml string now  
using (TextReader reader = new StringReader(xmlString)) { 
    bks2 = (books)serializer.Deserialize(reader); 
} 

bks2.Dump(); 

Ce produit XML qui peut être sérialisé et désérialisé sans mettre en œuvre IXmlSerializable, tels que:

<books> 
    <bookNum>2</bookNum> 
    <book> 
    <name>book 1</name> 
    <record> 
     <borrowDate>2/2/2016 5:57:25 PM</borrowDate> 
     <returnDate>2/2/2016 5:57:25 PM</returnDate> 
    </record> 
    </book> 
    <book> 
    <name>book 2</name> 
    <record> 
     <borrowDate>2/2/2016 5:57:25 PM</borrowDate> 
     <returnDate>2/2/2016 5:57:25 PM</returnDate> 
    </record> 
    <record> 
     <borrowDate>2/2/2016 5:57:25 PM</borrowDate> 
     <returnDate>2/2/2016 5:57:25 PM</returnDate> 
    </record> 
    </book> 
</books> 
0

Si vous avez besoin d'autres classes, telles que book2 dans la classe books, vous avez des instructions spéciales pour l'implémenter. exemple

public class books 
{     
    public int bookNum {get; set; } 
   public class book { 
         public string name {get; set; } 
         public class record { 
             public string borrowDate {get; set; } 
             public string returnDate {get; set; } 
         } 
         [XmlElement ("record")] 
         public record [] records {get; set; } 
     } 
     [XmlElement ("book")] 
     public book [] allBooks {get; set; } 

     public int book2Num {get; set; } 
     public class book2 { 
         public string name {get; set; } 
         public class record { 
             public string borrowDate {get; set; } 
             public string returnDate {get; set; } 
         } 
         [XmlElement ("record")] 
         public record [] records {get; set; } 
     } 
     [XmlElement ("book2")] 
     public book2 [] allBook2 {get; set; } 
}` 

Lorsque je tente d'exécuter le programme que j'ai l'erreur suivante:

« Informations complémentaires: Erreur lors de la réflexion du type »

+0

Veuillez modifier la réponse pour élaborer sur le sujet des instructions spéciales. – sorak

Questions connexes