Comment désérialiser un document XML

comment désérialiser ce document XML:

<?xml version="1.0" encoding="utf-8"?>
<Cars>
  <Car>
    <StockNumber>1020</StockNumber>
    <Make>Nissan</Make>
    <Model>Sentra</Model>
  </Car>
  <Car>
    <StockNumber>1010</StockNumber>
    <Make>Toyota</Make>
    <Model>Corolla</Model>
  </Car>
  <Car>
    <StockNumber>1111</StockNumber>
    <Make>Honda</Make>
    <Model>Accord</Model>
  </Car>
</Cars>

j'ai ceci:

[Serializable()]
public class Car
{
    [System.Xml.Serialization.XmlElementAttribute("StockNumber")]
    public string StockNumber{ get; set; }

    [System.Xml.Serialization.XmlElementAttribute("Make")]
    public string Make{ get; set; }

    [System.Xml.Serialization.XmlElementAttribute("Model")]
    public string Model{ get; set; }
}

.

[System.Xml.Serialization.XmlRootAttribute("Cars", Namespace = "", IsNullable = false)]
public class Cars
{
    [XmlArrayItem(typeof(Car))]
    public Car[] Car { get; set; }

}

.

public class CarSerializer
{
    public Cars Deserialize()
    {
        Cars[] cars = null;
        string path = HttpContext.Current.ApplicationInstance.Server.MapPath("~/App_Data/") + "cars.xml";

        XmlSerializer serializer = new XmlSerializer(typeof(Cars[]));

        StreamReader reader = new StreamReader(path);
        reader.ReadToEnd();
        cars = (Cars[])serializer.Deserialize(reader);
        reader.Close();

        return cars;
    }
}

qui ne semblent pas fonctionner: - (

385
demandé sur Dariusz Woźniak 2008-12-13 00:49:58

16 réponses

Voici une version de travail. J'ai changé les étiquettes XmlElementAttribute en XmlElement parce que dans le xml les valeurs Stocknumber, Make et Model sont des éléments, pas des attributs. Aussi j'ai enlevé le lecteur.ReadToEnd (); (que function lit le flux entier et renvoie une chaîne, de sorte que la fonction Deserialze () ne pouvait plus utiliser le lecteur...la position était à la fin du flux). J'ai aussi pris quelques libertés avec le nom :).

ici sont les classes:

[Serializable()]
public class Car
{
    [System.Xml.Serialization.XmlElement("StockNumber")]
    public string StockNumber { get; set; }

    [System.Xml.Serialization.XmlElement("Make")]
    public string Make { get; set; }

    [System.Xml.Serialization.XmlElement("Model")]
    public string Model { get; set; }
}


[Serializable()]
[System.Xml.Serialization.XmlRoot("CarCollection")]
public class CarCollection
{
    [XmlArray("Cars")]
    [XmlArrayItem("Car", typeof(Car))]
    public Car[] Car { get; set; }
}

Le Désérialiser de la fonction:

CarCollection cars = null;
string path = "cars.xml";

XmlSerializer serializer = new XmlSerializer(typeof(CarCollection));

StreamReader reader = new StreamReader(path);
cars = (CarCollection)serializer.Deserialize(reader);
reader.Close();

et le xml légèrement modifié (j'avais besoin d'ajouter un nouvel élément pour envelopper ...Net est pointilleux sur la désérialisation des tableaux):

<?xml version="1.0" encoding="utf-8"?>
<CarCollection>
<Cars>
  <Car>
    <StockNumber>1020</StockNumber>
    <Make>Nissan</Make>
    <Model>Sentra</Model>
  </Car>
  <Car>
    <StockNumber>1010</StockNumber>
    <Make>Toyota</Make>
    <Model>Corolla</Model>
  </Car>
  <Car>
    <StockNumber>1111</StockNumber>
    <Make>Honda</Make>
    <Model>Accord</Model>
  </Car>
</Cars>
</CarCollection>
304
répondu Kevin Tighe 2008-12-12 22:40:18

pourquoi ne pas simplement enregistrer le xml dans un fichier, et utiliser xsd ?

  1. écrivez le fichier sur le disque (je l'ai appelé foo.xml)
  2. Générer le fichier xsd: xsd foo.xml
  3. générer le C#: xsd foo.xsd /classes

Et voilà - et le code C# de fichier qui devrait être en mesure de lire les données via XmlSerializer :

    XmlSerializer ser = new XmlSerializer(typeof(Cars));
    Cars cars;
    using (XmlReader reader = XmlReader.Create(path))
    {
        cars = (Cars) ser.Deserialize(reader);
    }

(inclure le foo généré.cs dans le projet)

393
répondu Marc Gravell 2008-12-12 22:49:34

Vous avez deux possibilités.

Méthode 1. XSD tool


Supposons que vous ayez votre fichier XML à cet endroit C:\path\to\xml\file.xml
  1. Ouvrir Développeur Invite De Commande

    Vous pouvez le trouver dans Start Menu > Programs > Microsoft Visual Studio 2012 > Visual Studio Tools Ou si vous avez Windows 8 peut juste commencer à taper invite de commande de développeur dans écran de Démarrage
  2. changez l'emplacement de votre répertoire de fichiers XML en tapant cd /D "C:\path\to\xml"
  3. créer fichier XSD à partir de votre fichier xml en tapant xsd file.xml
  4. créer C # classes en tapant xsd /c file.xsd

et c'est tout! Vous avez généré des classes C# à partir du fichier xml dans C:\path\to\xml\file.cs

Méthode 2-Pâte spéciale


Requis Visual Studio 2012+
  1. copier le contenu de votre fichier XML dans le presse-papiers
  2. ajouter à votre solution un nouveau fichier de classe vide ( Maj + Alt + C )
  3. ouvrir ce fichier et dans le menu cliquer Edit > Paste special > Paste XML As Classes

    enter image description here

et c'est tout!

Utilisation


L'Usage est très simple avec cette classe d'aide:

using System;
using System.IO;
using System.Web.Script.Serialization; // Add reference: System.Web.Extensions
using System.Xml;
using System.Xml.Serialization;

namespace Helpers
{
    internal static class ParseHelpers
    {
        private static JavaScriptSerializer json;
        private static JavaScriptSerializer JSON { get { return json ?? (json = new JavaScriptSerializer()); } }

        public static Stream ToStream(this string @this)
        {
            var stream = new MemoryStream();
            var writer = new StreamWriter(stream);
            writer.Write(@this);
            writer.Flush();
            stream.Position = 0;
            return stream;
        }


        public static T ParseXML<T>(this string @this) where T : class
        {
            var reader = XmlReader.Create(@this.Trim().ToStream(), new XmlReaderSettings() { ConformanceLevel = ConformanceLevel.Document });
            return new XmlSerializer(typeof(T)).Deserialize(reader) as T;
        }

        public static T ParseJSON<T>(this string @this) where T : class
        {
            return JSON.Deserialize<T>(@this.Trim());
        }
    }
}

Tout ce que vous avez à faire maintenant, c'est:

    public class JSONRoot
    {
        public catalog catalog { get; set; }
    }
    // ...

    string xml = File.ReadAllText(@"D:\file.xml");
    var catalog1 = xml.ParseXML<catalog>();

    string json = File.ReadAllText(@"D:\file.json");
    var catalog2 = json.ParseJSON<JSONRoot>();
199
répondu Damian Drygiel 2013-10-27 02:11:51

l'extrait suivant devrait faire l'affaire (et vous pouvez ignorer la plupart des attributs de sérialisation):

public class Car
{
  public string StockNumber { get; set; }
  public string Make { get; set; }
  public string Model { get; set; }
}

[XmlRootAttribute("Cars")]
public class CarCollection
{
  [XmlElement("Car")]
  public Car[] Cars { get; set; }
}

...

using (TextReader reader = new StreamReader(path))
{
  XmlSerializer serializer = new XmlSerializer(typeof(CarCollection));
  return (CarCollection) serializer.Deserialize(reader);
}
73
répondu 2008-12-22 22:24:49

voir si cela aide:

[Serializable()]
[System.Xml.Serialization.XmlRootAttribute("Cars", Namespace = "", IsNullable = false)]
public class Cars
{
    [XmlArrayItem(typeof(Car))]
    public Car[] Car { get; set; }
}

.

[Serializable()]
public class Car
{
    [System.Xml.Serialization.XmlElement()]
    public string StockNumber{ get; set; }

    [System.Xml.Serialization.XmlElement()]
    public string Make{ get; set; }

    [System.Xml.Serialization.XmlElement()]
    public string Model{ get; set; }
}

et à défaut, utilisez le xsd.exe programme qui vient avec visual studio pour créer un document de schéma basé sur ce fichier xml, puis l'utiliser à nouveau pour créer une classe basée sur le document de schéma.

22
répondu Joel Coehoorn 2008-12-12 22:09:59

Je ne pense pas. Le premier document xml n'est pas bien formé. Il n'y a aucun élément racine, bien qu'il semble qu'il y est. Le document xml canonique comporte une racine et au moins un élément (s'il y a lieu). Dans votre exemple:

<Root> <-- well, the root
  <Cars> <-- an element (not a root), it being an array
    <Car> <-- an element, it being an array item
    ...
    </Car>
  </Cars>
</Root>
9
répondu janbak 2012-01-26 12:06:48

essayez ce bloc de code si votre .le fichier xml a été généré quelque part dans le disque et si vous avez utilisé List<T> :

//deserialization

XmlSerializer xmlser = new XmlSerializer(typeof(List<Item>));
StreamReader srdr = new StreamReader(@"C:\serialize.xml");
List<Item> p = (List<Item>)xmlser.Deserialize(srdr);
srdr.Close();`

Note: C:\serialize.xml est mon .xml du fichier chemin d'accès. Vous pouvez le changer pour vos besoins.

7
répondu sheetal nainwal 2013-10-07 11:15:05

L'anser de Kevin est bon, mis à part le fait que dans le monde réel, vous n'êtes souvent pas en mesure de modifier le XML original pour répondre à vos besoins.

il y a aussi une solution simple pour le XML original:

[XmlRoot("Cars")]
public class XmlData
{
    [XmlElement("Car")]
    public List<Car> Cars{ get; set; }
}

public class Car
{
    public string StockNumber { get; set; }
    public string Make { get; set; }
    public string Model { get; set; }
}

et ensuite vous pouvez simplement appeler:

var ser = new XmlSerializer(typeof(XmlData));
XmlData data = (XmlData)ser.Deserialize(XmlReader.Create(PathToCarsXml));
6
répondu Kim Homann 2018-01-13 14:11:38

essayez cette classe générique pour la sérialisation et la Desérialisation Xml.

public class SerializeConfig<T> where T : class
{
    public static void Serialize(string path, T type)
    {
        var serializer = new XmlSerializer(type.GetType());
        using (var writer = new FileStream(path, FileMode.Create))
        {
            serializer.Serialize(writer, type);
        }
    }

    public static T DeSerialize(string path)
    {
        T type;
        var serializer = new XmlSerializer(typeof(T));
        using (var reader = XmlReader.Create(path))
        {
            type = serializer.Deserialize(reader) as T;
        }
        return type;
    }
}
4
répondu Hasan Javaid 2016-05-12 06:18:13

L'idée est d'avoir tous les niveau traitées pour la désérialisation Consultez un exemple de solution qui a résolu mon problème semblable

<?xml version="1.0" ?> 
 <TRANSACTION_RESPONSE>
    <TRANSACTION>
        <TRANSACTION_ID>25429</TRANSACTION_ID> 
        <MERCHANT_ACC_NO>02700701354375000964</MERCHANT_ACC_NO> 
        <TXN_STATUS>F</TXN_STATUS> 
        <TXN_SIGNATURE>a16af68d4c3e2280e44bd7c2c23f2af6cb1f0e5a28c266ea741608e72b1a5e4224da5b975909cc43c53b6c0f7f1bbf0820269caa3e350dd1812484edc499b279</TXN_SIGNATURE> 
        <TXN_SIGNATURE2>B1684258EA112C8B5BA51F73CDA9864D1BB98E04F5A78B67A3E539BEF96CCF4D16CFF6B9E04818B50E855E0783BB075309D112CA596BDC49F9738C4BF3AA1FB4</TXN_SIGNATURE2> 
        <TRAN_DATE>29-09-2015 07:36:59</TRAN_DATE> 
        <MERCHANT_TRANID>150929093703RUDZMX4</MERCHANT_TRANID> 
        <RESPONSE_CODE>9967</RESPONSE_CODE> 
        <RESPONSE_DESC>Bank rejected transaction!</RESPONSE_DESC> 
        <CUSTOMER_ID>RUDZMX</CUSTOMER_ID> 
        <AUTH_ID /> 
        <AUTH_DATE /> 
        <CAPTURE_DATE /> 
        <SALES_DATE /> 
        <VOID_REV_DATE /> 
        <REFUND_DATE /> 
        <REFUND_AMOUNT>0.00</REFUND_AMOUNT> 
    </TRANSACTION>
  </TRANSACTION_RESPONSE> 

le XML ci-dessus est traité en deux niveaux

  [XmlType("TRANSACTION_RESPONSE")]
public class TransactionResponse
{
    [XmlElement("TRANSACTION")]
    public BankQueryResponse Response { get; set; }

}

Au niveau Intérieur

public class BankQueryResponse
{
    [XmlElement("TRANSACTION_ID")]
    public string TransactionId { get; set; }

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

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

    [XmlElement("TRAN_DATE")]
    public DateTime TranDate { get; set; }

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


    [XmlElement("REFUND_DATE")]
    public DateTime RefundDate { get; set; }

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


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

    [XmlAttribute("MERCHANT_TRANID")]
    public string MerchantTranId { get; set; }

}

de la même façon que vous avez besoin de plusieurs niveaux avec car as array cochez cet exemple pour la desérialisation à plusieurs niveaux

2
répondu makdu 2017-05-23 11:55:19

si vous obtenez des erreurs en utilisant xsd.exe pour créer votre fichier xsd, utilisez la classe XmlSchemaInference comme indiqué sur msdn . Voici un test unitaire pour démontrer:

using System.Xml;
using System.Xml.Schema;

[TestMethod]
public void GenerateXsdFromXmlTest()
{
    string folder = @"C:\mydir\mydata\xmlToCSharp";
    XmlReader reader = XmlReader.Create(folder + "\some_xml.xml");
    XmlSchemaSet schemaSet = new XmlSchemaSet();
    XmlSchemaInference schema = new XmlSchemaInference();

    schemaSet = schema.InferSchema(reader);


    foreach (XmlSchema s in schemaSet.Schemas())
    {
        XmlWriter xsdFile = new XmlTextWriter(folder + "\some_xsd.xsd", System.Text.Encoding.UTF8);
        s.Write(xsdFile);
        xsdFile.Close();
    }
}

// now from the visual studio command line type: xsd some_xsd.xsd /classes
1
répondu goku_da_master 2014-10-16 20:39:54

vous pouvez juste changer un attribut pour vous Voitures propriété de voiture de XmlArrayItem à XmlElment. C'est, à partir de

[System.Xml.Serialization.XmlRootAttribute("Cars", Namespace = "", IsNullable = false)]
public class Cars
{
    [XmlArrayItem(typeof(Car))]
    public Car[] Car { get; set; }
}

à

[System.Xml.Serialization.XmlRootAttribute("Cars", Namespace = "", IsNullable = false)]
public class Cars
{
    [XmlElement("Car")]
    public Car[] Car { get; set; }
}
1
répondu XU Weijiang 2014-11-17 05:20:35

ma solution:

  1. utilisez Edit > Past Special > Paste XML As Classes pour obtenir la classe dans votre code
  2. Essayez quelque chose comme ceci: créez une liste de cette classe ( List<class1 >), puis utilisez le XmlSerializer pour sérialiser cette liste dans un fichier xml .
  3. Maintenant, vous venez de remplacer le corps de ce fichier avec vos données et d'essayer de deserialize .

Code:

StreamReader sr = new StreamReader(@"C:\Users\duongngh\Desktop\Newfolder\abc.txt");
XmlSerializer xml = new XmlSerializer(typeof(Class1[]));
var a = xml.Deserialize(sr);
sr.Close();

NOTE: vous devez faire attention au nom racine, ne le changez pas. Le mien est "ArrayOfClass1 "

1
répondu haiduong87 2017-08-10 03:03:59

Pour Débutants

j'ai trouvé les réponses ici très utile, cela dit j'ai toujours mal (juste un peu) pour obtenir ce travail. Ainsi, au cas où cela aiderait quelqu'un, je vais Énoncer la solution de travail:

XML à partir de l'Original Question. Le xml est dans une classe de fichier 1.xml, un path de ce fichier est utilisé dans le code pour localiser ce fichier xml.

j'ai utilisé la réponse de @erymski pour obtenir ce fonctionnement, donc créé un fichier appelé Voiture.cs et ajouté ce qui suit:

using System.Xml.Serialization;  // Added

public class Car
{
    public string StockNumber { get; set; }
    public string Make { get; set; }
    public string Model { get; set; }
}

[XmlRootAttribute("Cars")]
public class CarCollection
{
    [XmlElement("Car")]
    public Car[] Cars { get; set; }
}

l'autre morceau de code fourni par @erymski ...

using (TextReader reader = new StreamReader(path))
{
  XmlSerializer serializer = new XmlSerializer(typeof(CarCollection));
  return (CarCollection) serializer.Deserialize(reader);
}

... va dans votre programme principal (programme.cs), dans static CarCollection XCar() comme ceci:

using System;
using System.IO;
using System.Xml.Serialization;

namespace ConsoleApp2
{
    class Program
    {

        public static void Main()
        {
            var c = new CarCollection();

            c = XCar();

            foreach (var k in c.Cars)
            {
                Console.WriteLine(k.Make + " " + k.Model + " " + k.StockNumber);
            }
            c = null;
            Console.ReadLine();

        }
        static CarCollection XCar()
        {
            using (TextReader reader = new StreamReader(@"C:\Users\SlowLearner\source\repos\ConsoleApp2\ConsoleApp2\Class1.xml"))
            {
                XmlSerializer serializer = new XmlSerializer(typeof(CarCollection));
                return (CarCollection)serializer.Deserialize(reader);
            }
        }
    }
}

Espère que cela aide :-)

1
répondu SlowLearner 2018-05-22 10:12:40

Que Diriez-vous d'une classe générique pour désérialiser un document XML

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Generic class to load any xml into a class
// used like this ...
// YourClassTypeHere InfoList = LoadXMLFileIntoClass<YourClassTypeHere>(xmlFile);

using System.IO;
using System.Xml.Serialization;

public static T LoadXMLFileIntoClass<T>(string xmlFile)
{
    T returnThis;
    XmlSerializer serializer = new XmlSerializer(typeof(T));
    if (!FileAndIO.FileExists(xmlFile))
    {
        Console.WriteLine("FileDoesNotExistError {0}", xmlFile);
    }
    returnThis = (T)serializer.Deserialize(new StreamReader(xmlFile));
    return (T)returnThis;
}

la présente partie peut être ou ne pas être nécessaire. Ouvrez le document XML dans Visual Studio, faites un clic droit sur le XML, choisissez Propriétés. Ensuite, choisissez votre fichier de schéma.

0
répondu David C Fuchs 2017-12-02 05:06:29
string employeedata = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><tag><name>test</bar></nmae>";//demo xml data
        using (TextReader sr = new StringReader(employeedata))
        {
            XmlSerializer serializer = new XmlSerializer(typeof(Employee));//pass type name in XmlSerializer constructor here
            Employee response = (Employee)serializer.Deserialize(sr);
            Console.WriteLine(response.name);
        }

[System.Xml.Serialization.XmlRoot("tag")]
public class Employee
{
    public string name { get; set; }
}
0
répondu Sunil Dhappadhule 2018-10-07 13:24:03