example deserialize c# asp.net xml serialization xml-deserialization

c# - deserialize - Cómo deserializar un documento XML



xml to class c# (16)

Como deserializo este documento 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>

Tengo esto:

[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; } }

que no parecen funcionar :-(


Para principiantes

Encontré que las respuestas aquí fueron muy útiles, que dijeron que todavía luché (solo un poco) para que esto funcionara. Entonces, en caso de que ayude a alguien, explicaré la solución de trabajo:

XML de la pregunta original. El xml está en un archivo Class1.xml, una path de path a este archivo se usa en el código para localizar este archivo xml.

Utilicé la respuesta de @erymski para que esto funcionara, así que creé un archivo llamado Car.cs y añadí lo siguiente:

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; } }

El otro bit de código proporcionado por @erymski ...

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

... entra en su programa principal (Program.cs), en static CarCollection XCar() esta manera:

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); } } } }

Espero eso ayude :-)


¿Qué tal si solo guardas el xml en un archivo y usas xsd ?

  1. Escribe el archivo en el disco (lo llamé foo.xml)
  2. Genera el xsd: xsd foo.xml
  3. Genere el C #: xsd foo.xsd /classes

Et voila - y el archivo de código C # que debería poder leer los datos a través de XmlSerializer :

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

(incluye los foo.cs generados en el proyecto)


¿Qué tal una clase genérica para deserializar un documento 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; }

Esta parte puede, o no puede ser necesaria. Abra el documento XML en Visual Studio, haga clic derecho en el XML, elija las propiedades. Luego elige tu archivo de esquema.


A ver si esto ayuda:

[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; } }

Y si falla, use el programa xsd.exe que viene con Visual Studio para crear un documento de esquema basado en ese archivo xml, y luego úselo nuevamente para crear una clase basada en el documento de esquema.


Aquí hay una versión de trabajo. Cambié las etiquetas XmlElementAttribute a XmlElement porque en el xml los valores StockNumber, Make y Model son elementos, no atributos. También quité el reader.ReadToEnd (); (esa function lee la secuencia completa y devuelve una cadena, por lo que la función Deserialze () ya no podía usar el lector ... la posición estaba al final de la secuencia). También me tomé algunas libertades con el nombramiento :).

Aquí están las clases:

[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 función Deserializar:

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();

Y el xml ligeramente ajustado (necesitaba agregar un nuevo elemento para envolver <Cars> ... Net es exigente con las matrices de deserialización):

<?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>


El anser de Kevin es bueno, aparte del hecho de que en el mundo real, a menudo no puede modificar el XML original para satisfacer sus necesidades.

También hay una solución simple para el 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; } }

Y luego puedes simplemente llamar:

var ser = new XmlSerializer(typeof(XmlData)); XmlData data = (XmlData)ser.Deserialize(XmlReader.Create(PathToCarsXml));


El siguiente fragmento de código debería hacer el truco (y puede ignorar la mayoría de los atributos de serialización):

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); }


La idea es que todos los niveles se manejen para la deserialización. Vea una solución de muestra que resolvió mi problema similar.

<?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>

El XML anterior se maneja en dos niveles

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

El nivel interno

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 misma manera que necesita múltiples niveles con el car as array Verifique este ejemplo para la deserialización multinivel.


Mi solución:

  1. Use Edit > Past Special > Paste XML As Classes para obtener la clase en su código
  2. Intente algo como esto: cree una lista de esa clase ( List<class1 >), luego use el XmlSerializer para serializar esa lista a un archivo xml .
  3. Ahora simplemente reemplaza el cuerpo de ese archivo con tus datos e intenta deserialize .

Código:

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

NOTA: debe prestar atención al nombre de la raíz, no lo cambie. El mío es "ArrayOfClass1"


No creo que .net sea ''exigente con los arreglos de deserialización''. El primer documento xml no está bien formado. No hay ningún elemento raíz, aunque parece que hay. El documento xml canónico tiene una raíz y al menos 1 elemento (si lo hay). En tu ejemplo:

<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>


Pruebe esta clase genérica para la serialización y deserialización 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; } }


Si está obteniendo errores al utilizar xsd.exe para crear su archivo xsd, use la clase XmlSchemaInference como se menciona en msdn . Aquí hay una prueba de unidad para demostrar:

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


Solo puede cambiar un atributo para la propiedad de su automóvil Cars de XmlArrayItem a XmlElment. Es decir, de

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

a

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


Tienes dos posibilidades.

Método 1. Herramienta XSD

Supongamos que tiene su archivo XML en esta ubicación C:/path/to/xml/file.xml
  1. Abrir el símbolo del sistema del desarrollador
    Puede encontrarlo en el Start Menu > Programs > Microsoft Visual Studio 2012 > Visual Studio Tools O si tiene Windows 8, simplemente comience a escribir el símbolo del sistema del desarrollador en la pantalla de inicio
  2. Cambie la ubicación de su directorio de archivos XML escribiendo cd /D "C:/path/to/xml"
  3. Cree un archivo XSD a partir de su archivo xml escribiendo xsd file.xml
  4. Crea clases de C # escribiendo xsd /c file.xsd

¡Y eso es! Ha generado clases de C # desde un archivo xml en C:/path/to/xml/file.cs

Método 2 - Pegado especial

Se requiere Visual Studio 2012+
  1. Copie el contenido de su archivo XML al portapapeles
  2. Agregue a su solución un nuevo archivo de clase vacío ( Shift + Alt + C )
  3. Abra ese archivo y en el menú haga clic en Edit > Paste special > Paste XML As Classes

¡Y eso es!

Uso

El uso es muy simple con esta clase de ayuda:

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()); } } }

Todo lo que tienes que hacer ahora, es:

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>();


intente este bloque de código si su archivo .xml se ha generado en algún lugar del disco y si ha usado la 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();`

Nota: C:/serialize.xml es la ruta de mi archivo .xml. Puedes cambiarlo por tus necesidades.


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; } }