2013-05-15 11 views
9

Ho la seguente struttura XML (modificata per brevità) di cui non ho il controllo.Deserializzare l'elemento XML nidificato in classe in C#

<GetVehicles> 
    <ApplicationArea> 
     <Sender> 
      <Blah></Blah> 
     </Sender> 
    </ApplicationArea> 
    <DataArea> 
     <Error> 
      <Blah></Blah> 
     </Error> 
     <Vehicles> 
      <Vehicle> 
       <Colour>Blue</Colour> 
       <NumOfDoors>3</NumOfDoors> 
       <BodyStyle>Hatchback</BodyStyle> 
      <Vehicle> 
     </Vehicles> 
    </DataArea> 
</GetVehicles> 

Ho la seguente Classe:

[XmlRoot("GetVehicles"), XmlType("Vehicle")] 
public class Vehicle 
{ 
    public string Colour { get; set; } 
    public string NumOfDoors { get; set; } 
    public string BodyStyle { get; set; } 
} 

io voglio essere in grado di deserializzare il codice XML in una singola istanza di questa classe di veicoli. Il 99% delle volte, l'XML dovrebbe restituire solo un singolo elemento "Veicolo". Non mi sto ancora occupando di questo se contiene più elementi "Veicolo" all'interno dell'elemento "Veicoli".

Sfortunatamente, i dati XML non vengono attualmente associati alle proprietà della mia classe; vengono lasciati in bianco dopo aver chiamato il mio metodo Deserialize.

Per completezza, ecco il mio metodo Deserialize:

private static T Deserialize<T>(string data) where T : class, new() 
{ 
    if (string.IsNullOrEmpty(data)) 
     return null; 

    var ser = new XmlSerializer(typeof(T)); 

    using (var sr = new StringReader(data)) 
    { 
     return (T)ser.Deserialize(sr); 
    } 
} 

Non mi preoccupo per gli altri elementi più generali come 'Settore applicazione', 'Errore', ecc sono solo interessante per l'estrazione dei dati all'interno dell'elemento "Veicolo". Come faccio a deserializzare questi dati dall'XML?

risposta

6

Non sono a conoscenza del contesto completo del problema, quindi questa soluzione potrebbe non essere adatta al tuo dominio. Ma una soluzione è quella di definire il modello come:

[XmlRoot("Vehicle")] //<-- optional 
public class Vehicle 
{ 
    public string Colour { get; set; } 
    public string NumOfDoors { get; set; } 
    public string BodyStyle { get; set; } 
} 

e passare nodo specifico in Deserialize metodo che utilizza LINQ to XML:

var vehicle = XDocument.Parse(xml) 
         .Descendants("Vehicle") 
         .First(); 

Vehicle v = Deserialize<Vehicle>(vehicle.ToString()); 


//display contents of v 
Console.WriteLine(v.BodyStyle); //prints Hatchback 
Console.WriteLine(v.Colour);  //prints Blue 
Console.WriteLine(v.NumOfDoors); //prints 3 
+0

Funziona alla grande. Molte grazie. – marcusstarnes

6

Sulla risposta di Ilya:

Questo può essere ottimizzato un po ' , dal momento che esiste già un nodo caricato: non è necessario passare l'xml a una stringa (utilizzando vehicle.ToString()), per fare in modo che il serializzatore debba riesaminarlo (utilizzando un StringReader).

Invece, possiamo creato un lettore utilizzando direttamente XNode.CreateReader:

private static T Deserialize<T>(XNode data) where T : class, new() 
{ 
    if (data == null) 
     return null; 

    var ser = new XmlSerializer(typeof(T)); 
    return (T)ser.Deserialize(data.CreateReader()); 
} 

O se i dati è un XmlNode, utilizzare un XmlNodeReader:

private static T Deserialize<T>(XmlNode data) where T : class, new() 
{ 
    if (data == null) 
     return null; 

    var ser = new XmlSerializer(typeof(T)); 
    using (var xmlNodeReader = new XmlNodeReader(data)) 
    { 
     return (T)ser.Deserialize(xmlNodeReader); 
    } 
} 

Possiamo quindi usare:

var vehicle = XDocument.Parse(xml) 
         .Descendants("Vehicle") 
         .First(); 

Vehicle v = Deserialize<Vehicle>(vehicle); 
+0

Grande nota, grazie. –

+0

Sì, ha funzionato bene per me e utilizzava XmlNode. Tuttavia, il codice non ha funzionato immediatamente. Avevo bisogno di modificare leggermente il codice nel modo seguente: xmlNodeReader.ReadStartElement(); return (T) ser.Deserialize (xmlNodeReader.ReadSubtree()); –

Problemi correlati