Comment Désérialise document XML
-
21-08-2019 - |
Question
Comment puis-je deserialize 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 semble pas fonctionner: - (
La solution
Voici une version de travail. J'ai changé les étiquettes de XmlElementAttribute XmlElement parce que dans le xml du Numéro de stock, la marque et les valeurs du modèle sont des éléments, pas d'attributs. J'ai aussi enlevé le reader.ReadToEnd (); (Cette fonction lit tout le flux et retourne une chaîne, de sorte que la fonction Deserialze () ne pouvait plus utiliser le lecteur ... la position était à la fin du cours d'eau). J'ai aussi pris quelques libertés avec la dénomination:)
.Voici 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; }
}
La fonction Désérialiser:
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é (je besoin d'ajouter un nouvel élément à 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>
Autres conseils
Que diriez-vous que vous venez d'enregistrer le xml dans un fichier, et utilisez xsd pour générer des classes C #?
- Ecrire le fichier sur le disque (je l'ai nommé foo.xml)
- Générer le xsd:
xsd foo.xml
- Génération C #:
xsd foo.xsd /classes
Et le tour est joué - et le fichier de code C # 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);
}
(y compris les foo.cs générés dans le projet)
Vous avez deux possibilités.
Méthode 1. XSD outil
Supposons que vous avez votre fichier XML dans cet emplacement
C:\path\to\xml\file.xml
- Ouvrir Invite de commandes de développeur
Vous pouvez le trouver dans
Start Menu > Programs > Microsoft Visual Studio 2012 > Visual Studio Tools
Ou si vous avez Windows 8 peut commencer à taper Développeur Invite de commande Écran de démarrage - Changer l'emplacement dans votre répertoire de fichier XML en tapant
cd /D "C:\path\to\xml"
- Créer fichier XSD de votre fichier xml en tapant
xsd file.xml
- Créer C classes # en tapant
xsd /c file.xsd
Et voilà! Vous avez généré des classes C # à partir du fichier xml dans C:\path\to\xml\file.cs
Méthode 2 - Collage spécial
Visual Studio requis 2012+
- Copier le contenu de votre fichier XML dans le presse-papiers
- Ajoutez à votre solution nouveau fichier de classe vide ( Maj + Alt + C )
- Ouvrez ce fichier et dans le menu cliquez sur
Edit > Paste special > Paste XML As Classes
Et voilà!
Utilisation
L'utilisation 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, 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);
}
Voyez 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 utiliser le programme xsd.exe 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 sur la base du document de schéma.
Je ne pense pas que .net est «pointilleux sur les tableaux désérialisation. Le premier document XML est pas bien formé. Il n'y a aucun élément racine, bien qu'il semble qu'il y ait. Le document XML canonique a une racine et au moins 1 élément (le cas échéant). 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 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();`
Remarque: le chemin est C:\serialize.xml
de mon fichier .xml. Vous pouvez le modifier pour vos besoins.
Le Anser de Kevin est bon, à part le fait que dans le monde réel, vous êtes souvent pas en mesure de modifier le XML d'origine en fonction de vos besoins.
Il y a une solution simple pour le XML original, aussi:
[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 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 Xml sérialisation et désérialisation.
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;
}
}
pour les débutants
J'ai trouvé les réponses ici très utile, qui dit que je toujours eu du mal (juste un peu) pour obtenir ce travail. Ainsi, dans le cas où il aide quelqu'un que j'épelle la solution de travail:
XML de Original Question. Le XML est dans un Class1.xml de fichier, un fichier à path
est utilisé dans le code pour localiser ce fichier xml.
J'ai utilisé la réponse par @erymski pour obtenir ce travail, donc créé un fichier appelé Car.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 bit 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 (Program.cs), dans comme ceci static CarCollection XCar()
:
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);
}
}
}
}
it helps: -)
L'idée est d'avoir tous les niveaux pour être manipulé désérialisation S'il vous plaît voir une solution échantillon qui a résolu mon problème similaire
<?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; }
}
Le 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; }
}
Way même vous avez besoin de multiples niveaux avec car as array
Consultez cet exemple pour désérialisation multi-niveaux
Si vous obtenez des erreurs en utilisant xsd.exe pour créer votre fichier XSD, puis utilisez la classe XmlSchemaInference comme mentionné 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 simplement changer un attribut pour vous Voitures propriété de voiture XmlArrayItem à XmlElment. C'est, 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; }
}
My solution:
- Use
Edit > Past Special > Paste XML As Classes
to get the class in your code - Try something like this: create a list of that class (
List<class1
>), then use theXmlSerializer
to serialize that list to axml
file. - Now you just replace the body of that file with your data and try to
deserialize
it.
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: you must pay attention to the root name, don't change it. Mine is "ArrayOfClass1"
How about a generic class to deserialize an XML document
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// 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;
}
This part may, or may not be necessary. Open the XML document in Visual Studio, right click on the XML, choose properties. Then choose your schema file.
async public static Task<JObject> XMLtoNETAsync(XmlDocument ToConvert)
{
//Van XML naar JSON
string jsonText = await Task.Run(() => JsonConvert.SerializeXmlNode(ToConvert));
//Van JSON naar .net object
var o = await Task.Run(() => JObject.Parse(jsonText));
return o;
}