Tips & Tricks : Dé-sérialisation d’un flux XML avec la WinRT

 

Bonjour,

J’ai un document XML que je voudrais dé-sérialiser à l’aide des méthodes classiques de .NET

Code Snippet

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <Collection MaxLevel="7" TileSize="256" Format="jpg" NextItemId="121" ServerFormat="Default" xmlns="https://schemas.microsoft.com/deepzoom/2009">
  3.   <Items>
  4.     <I Id="0" N="0" Source="images/ubiacr.xml">
  5.       <Size Width="600" Height="600" />
  6.     </I>
  7.     <I Id="1" N="1" Source="images/callofdutymw3.xml">
  8.       <Size Width="600" Height="600" />
  9.     </I>
  10.     <I Id="2" N="2" Source="images/pffmigp.xml">
  11.       <Size Width="600" Height="600" />
  12.     </I>

 

La 1ère étape consiste a créer une classe en C# qui me permettra de mapper les éléments XML, en éléments plus compréhensible par mon code.

Soit j’écris cette classe manuellement, soit j’utilise l’outil XSD.EXE pour le faire automatiquement.

Outil que vous retrouverez dans ce répertoire : C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools

- Tout d’abord il me faut un schéma XSD que je n’ai pas. Pas de soucis nous allons le créer.

XSD.EXE MonFichier.xml /OutPutDir:C:\Temp

Cette ligne créée un fichier MonFichier.xsd

- Ensuite il faut créer la classe en elle même à partir de ce dernier fichier

XSD.EXE MonFichier.xsd /Classes /Language:CS

Cette ligne créée un fichier MonFichier.cs que vous pourrez incorporer dans votre projet.

Mais dans l’état actuel des choses, dans un projet Windows 8 pour le Store (WinRT), le fichier CS, ne compile pas, il faut le modifier manuellement.

En effet l’outil y injecte des espaces de noms et des classes qui sont exclues du sous ensemble .NET utilisable avec la WinRT.

Par exemple, vous pourrez supprimer manuellement toutes les références aux espaces de noms :

[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]

Tout va bien, tout compile, vous pouvez donc dé-sérialiser votre fichier xml, avec un code du style :

Code Snippet

  1. public class Helper
  2.   {
  3.       static HttpClient _clientHttp;
  4.       static Helper()
  5.       {
  6.           _clientHttp = new HttpClient();
  7.           _clientHttp.MaxResponseContentBufferSize = int.MaxValue;
  8.       }
  9.       public static async Task<T> LoadRemoteFileAsync<T>(String RemotePath)
  10.       {            
  11.           T t;
  12.           try
  13.           {
  14.  
  15.               using (Stream stream = await _clientHttp.GetStreamAsync(RemotePath))
  16.               {
  17.                   t = DeserializeStream<T>(stream);
  18.               }
  19.           }
  20.           catch (Exception ex)
  21.           {
  22.               System.Diagnostics.Debug.WriteLine(ex.Message);
  23.               throw;
  24.           }
  25.           return t;
  26.       }
  27.  
  28.       public static async Task<T> LoadLocalFileAsync<T>(String LocalPath)
  29.       {
  30.           var store = KnownFolders.DocumentsLibrary;
  31.           T t; ;
  32.           try
  33.           {
  34.               using (var stream = await store.OpenStreamForReadAsync(LocalPath))
  35.               {
  36.                   t = DeserializeStream<T>(stream);
  37.               }
  38.           }
  39.           catch (Exception ex)
  40.           {
  41.               System.Diagnostics.Debug.WriteLine(ex.Message);
  42.               throw;
  43.           }
  44.           return t;
  45.       }
  46.       static T DeserializeStream<T>(Stream stream)
  47.       {
  48.  
  49.           XmlSerializer deserializer = new XmlSerializer(typeof(T));
  50.           Object collection = deserializer.Deserialize(stream);
  51.           return (T)collection;
  52.       }
  53.   }

 

Mais à l’exécution l’exception suivante est levée

Unable to generate a temporary class (result=1).
error CS0012: The type 'System.Object' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.

Ceci est du au faite que l’outil à généré des données membres de type Jagged array comme illustré dans le code suivant

Code Snippet

  1. private CollectionItemsI[][] itemsIField;

 

 

  il suffit de le remplacer par exemple par une liste générique   

Code Snippet

  1. private List<CollectionItemsI> itemsField;

Et le tout s’exécute normalement