Wie kann ich dieses XML-Dokument deserialisieren?
<?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>
Ich habe das:
[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;
}
}
das scheint nicht zu funktionieren :-(
Hier ist eine funktionierende Version. Ich habe die XmlElementAttribute-Beschriftungen in XmlElement geändert, da in der XML-Datei die Werte StockNumber, Make und Model Elemente und keine Attribute sind. Ich habe auch den Reader entfernt.ReadToEnd (); (Da function den gesamten Stream liest und einen String zurückgibt, konnte die Deserialze () - Funktion den Reader nicht mehr verwenden ... die Position befand sich am Ende des Streams. Ich habe auch ein paar Freiheiten mit der Benennung gemacht :).
Hier sind die Klassen:
[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; }
}
Die Deserialize-Funktion:
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();
Und die etwas angepasste xml-Datei (Ich musste ein neues Element hinzufügen, um <Cars> einzuwickeln ... Das Netz ist wählerisch bei der Deserialisierung von Arrays):
<?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>
Wie wäre es, wenn Sie die XML-Datei in einer Datei speichern und mit xsd C # -Klassen erstellen?
xsd foo.xml
xsd foo.xsd /classes
Et voila - und C # -Codedatei, die die Daten über XmlSerializer
lesen kann:
XmlSerializer ser = new XmlSerializer(typeof(Cars));
Cars cars;
using (XmlReader reader = XmlReader.Create(path))
{
cars = (Cars) ser.Deserialize(reader);
}
(füge die generierten foo.cs in das Projekt ein)
Das folgende Snippet sollte den Trick ausführen (und Sie können die meisten Serialisierungsattribute ignorieren):
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);
}
Sehen Sie, ob das hilft:
[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; }
}
Andernfalls verwenden Sie das Programm xsd.exe, das im Lieferumfang von Visual Studio enthalten ist, um ein auf dieser XML-Datei basierendes Schemadokument zu erstellen, und verwenden Sie es erneut, um eine auf dem Schemadokument basierende Klasse zu erstellen.
Ich denke nicht, dass .net 'Deserialisierung von Arrays' wählerisch macht. Das erste XML-Dokument ist nicht gut ausgebildet. Es gibt kein Stammelement, obwohl es so aussieht, als wäre es vorhanden. Das kanonische XML-Dokument hat einen Stamm und mindestens ein Element (falls überhaupt). In deinem Beispiel:
<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>
versuchen Sie diesen Codeblock, wenn Ihre XML-Datei irgendwo auf der Festplatte erstellt wurde und Sie List<T>
verwendet haben:
//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();`
Hinweis: C:\serialize.xml
ist der Pfad der XML-Datei. Sie können es für Ihre Bedürfnisse ändern.
Kevins Anser ist gut, abgesehen davon, dass Sie in der realen Welt die ursprüngliche XML-Datei häufig nicht an Ihre Bedürfnisse anpassen können.
Es gibt auch eine einfache Lösung für das ursprüngliche XML:
[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; }
}
Und dann kannst du einfach anrufen:
var ser = new XmlSerializer(typeof(XmlData));
XmlData data = (XmlData)ser.Deserialize(XmlReader.Create(PathToCarsXml));
Probieren Sie diese generische Klasse für die XML-Serialisierung und Deserialisierung aus.
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;
}
}
Ich fand die Antworten hier sehr hilfreich und sagte, ich habe immer noch Schwierigkeiten (nur ein bisschen), um das zum Laufen zu bringen. Falls es jemandem hilft, formuliere ich die funktionierende Lösung:
XML aus der ursprünglichen Frage. Die XML-Datei befindet sich in einer Datei Class1.xml. Im Code wird eine path
zu dieser Datei verwendet, um diese XML-Datei zu finden.
Ich habe die Antwort von @erymski verwendet, um diese Funktion zum Laufen zu bringen. Deshalb habe ich eine Datei namens Car.cs erstellt und Folgendes hinzugefügt:
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; } }
Der andere Code von @erymski ...
using (TextReader reader = new StreamReader(path)) { XmlSerializer serializer = new XmlSerializer(typeof(CarCollection)); return (CarCollection) serializer.Deserialize(reader); }
... geht in Ihr Hauptprogramm (Program.cs), in static CarCollection XCar()
wie folgt:
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);
}
}
}
}
Ich hoffe es hilft :-)
Die Idee ist, dass alle Ebenen für die Deserialisierung behandelt werden
<?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>
Das obige XML wird in zwei Ebenen behandelt
[XmlType("TRANSACTION_RESPONSE")]
public class TransactionResponse
{
[XmlElement("TRANSACTION")]
public BankQueryResponse Response { get; set; }
}
Die innere Ebene
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; }
}
Genauso wie Sie mehrere Ebenen benötigen mit car as array
Überprüfen Sie dieses Beispiel für mehrstufige Deserialisierung
Sie können nur ein Attribut für Ihre Autos-Autos Eigenschaft von XmlArrayItem in Xml Element ändern. Das heißt von
[System.Xml.Serialization.XmlRootAttribute("Cars", Namespace = "", IsNullable = false)]
public class Cars
{
[XmlArrayItem(typeof(Car))]
public Car[] Car { get; set; }
}
zu
[System.Xml.Serialization.XmlRootAttribute("Cars", Namespace = "", IsNullable = false)]
public class Cars
{
[XmlElement("Car")]
public Car[] Car { get; set; }
}
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;
}
Meine Lösung:
Edit > Past Special > Paste XML As Classes
, um die Klasse in Ihrem Code abzurufenList<class1
>) und verwenden Sie dann die XmlSerializer
, um diese Liste in eine xml
-Datei zu serialisieren.deserialize
zu machen.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();
HINWEIS: Sie müssen auf den Stammnamen achten, ihn nicht ändern. Mein ist "ArrayOfClass1"
Wenn Sie mit xsd.exe Fehler beim Erstellen Ihrer xsd-Datei erhalten, verwenden Sie die XmlSchemaInference-Klasse, wie unter on msdn erwähnt. Hier ist ein Unit-Test, um zu demonstrieren:
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
Wie wäre es mit einer generischen Klasse, um ein XML-Dokument zu deserialisieren?
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// 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;
}
Dieser Teil kann erforderlich sein oder nicht. Öffnen Sie das XML-Dokument in Visual Studio, klicken Sie mit der rechten Maustaste auf das XML, und wählen Sie Eigenschaften aus. Wählen Sie dann Ihre Schemadatei.
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; }
}