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: - (
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
<?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>
pourquoi ne pas simplement enregistrer le xml dans un fichier, et utiliser xsd ?
- écrivez le fichier sur le disque (je l'ai appelé foo.xml)
- Générer le fichier xsd:
xsd foo.xml
- 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)
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
- Ouvrir Développeur Invite De Commande
Vous pouvez le trouver dansStart 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 - changez l'emplacement de votre répertoire de fichiers XML en tapant
cd /D "C:\path\to\xml"
- créer fichier XSD à partir de votre fichier xml en tapant
xsd file.xml
- 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+
- copier le contenu de votre fichier XML dans le presse-papiers
- ajouter à votre solution un nouveau fichier de classe vide ( Maj + Alt + C )
- ouvrir ce fichier et dans le menu cliquer
Edit > Paste special > Paste XML As Classes
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>();
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);
}
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.
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>
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.
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));
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;
}
}
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
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
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; }
}
ma solution:
- utilisez
Edit > Past Special > Paste XML As Classes
pour obtenir la classe dans votre code - Essayez quelque chose comme ceci: créez une liste de cette classe (
List<class1
>), puis utilisez leXmlSerializer
pour sérialiser cette liste dans un fichierxml
. - 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 "
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 :-)
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.
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; }
}