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
- <?xml version="1.0" encoding="utf-8"?>
- <Collection MaxLevel="7" TileSize="256" Format="jpg" NextItemId="121" ServerFormat="Default" xmlns="https://schemas.microsoft.com/deepzoom/2009">
- <Items>
- <I Id="0" N="0" Source="images/ubiacr.xml">
- <Size Width="600" Height="600" />
- </I>
- <I Id="1" N="1" Source="images/callofdutymw3.xml">
- <Size Width="600" Height="600" />
- </I>
- <I Id="2" N="2" Source="images/pffmigp.xml">
- <Size Width="600" Height="600" />
- </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
- public class Helper
- {
- static HttpClient _clientHttp;
- static Helper()
- {
- _clientHttp = new HttpClient();
- _clientHttp.MaxResponseContentBufferSize = int.MaxValue;
- }
- public static async Task<T> LoadRemoteFileAsync<T>(String RemotePath)
- {
- T t;
- try
- {
- using (Stream stream = await _clientHttp.GetStreamAsync(RemotePath))
- {
- t = DeserializeStream<T>(stream);
- }
- }
- catch (Exception ex)
- {
- System.Diagnostics.Debug.WriteLine(ex.Message);
- throw;
- }
- return t;
- }
- public static async Task<T> LoadLocalFileAsync<T>(String LocalPath)
- {
- var store = KnownFolders.DocumentsLibrary;
- T t; ;
- try
- {
- using (var stream = await store.OpenStreamForReadAsync(LocalPath))
- {
- t = DeserializeStream<T>(stream);
- }
- }
- catch (Exception ex)
- {
- System.Diagnostics.Debug.WriteLine(ex.Message);
- throw;
- }
- return t;
- }
- static T DeserializeStream<T>(Stream stream)
- {
- XmlSerializer deserializer = new XmlSerializer(typeof(T));
- Object collection = deserializer.Deserialize(stream);
- return (T)collection;
- }
- }
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
- private CollectionItemsI[][] itemsIField;
il suffit de le remplacer par exemple par une liste générique
Code Snippet
- private List<CollectionItemsI> itemsField;
Et le tout s’exécute normalement
Comments
- Anonymous
November 11, 2012
Salut Eric, je vois que mon astuce a trouvé preneur !