Avatar billede sandrasmurf Nybegynder
18. april 2010 - 14:49 Der er 12 kommentarer og
1 løsning

Humlen ved XmlSerializer.Deserialize

Hej eksperter

Jeg sidder og leger med en WebService, der hedder Discogs.com.

Udfordringen er, at jeg simpelthen ikke kan lure, hvordan man får lavet deres XML svar om til noget man kan bruge i sit program. Eksemplerne som Google kan finde til mig "snyder" i den forstand at eksemplerne altid både serializer og deserializer. Jeg skal kun deserialize.

Jeg forsøger at bruge XmlSerializer.Deserialize, men mangler retningslinier for at bruge metoden. I øjeblikket gør metoden nemlig intet og der smides ingen fejl, så jeg håber, at få et indspark til den korrekte brug af metoden.

Jeg vil gerne kunne sende søgninger afsted i denne form
"http://www.discogs.com/artist/Dizzy+Mizz+Lizzy?f=xml"

Til det formål har jeg lavet nedenstående metode med inspiration fra Discogs User Forum.

Og jeg modtager et XML svar i nedenstående format.

Er der nogen som kan hjælpe med at udforme klassen DiscogsResponse(indsat nedenstående), således, at deserialiseringen virker efter hensigten.
Avatar billede sandrasmurf Nybegynder
18. april 2010 - 14:49 #1
public void SearchArtist(string artistName)
{
  string requestUrl = string.Format("http://www.discogs.com/artist/{0}?f=xml", artistName.Replace(' ', '+'));

  WebClient wc = new WebClient();
  wc.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip");
  wc.Proxy = null;

  using (GZipStream stream = new GZipStream(wc.OpenRead(requestUrl), CompressionMode.Decompress, false))
  {
      using (StreamReader reader = new StreamReader(stream))
      {
        string str = reader.ReadToEnd();
        XmlSerializer serializer = new XmlSerializer(typeof (DiscogsResponse));
        DiscogsResponse resp = (DiscogsResponse) serializer.Deserialize(new XmlTextReader(str, xmlNodeType.Element, null));
        Console.WriteLine(resp);
      }
  }
}
Avatar billede sandrasmurf Nybegynder
18. april 2010 - 14:51 #2
XML svaret fra Discogs.com. Visual Studio Copy Paste har tilføjet +/- tegn.

resp stat="ok" version="1.0" requests="37">
  - <artist>
    - <images>
      <image height="450" type="secondary" uri="http://www.discogs.com/image/A-257957-1105887527.jpg" uri150="http://www.discogs.com/image/A-150-257957-1105887527.jpg" width="307" />
    </images>
    <name>Dizzy Mizz Lizzy</name>
    - <urls>
      <url>http://www.dizzymizzlizzy.com</url>
    </urls>
    - <members>
      <name>Tim Christensen</name>
    </members>
    + <releases>
      - <release id="401451" status="Accepted" type="Main">
        <title>Dizzy Mizz Lizzy</title>
        <format>CD</format>
        <label>EMI-Medley (Denmark)</label>
        <year>1994</year>
      </release>
      - <release id="1937605" status="Accepted" type="Main">
        <title>Dizzy Mizz Lizzy</title>
        <format>CD</format>
        <label>EMI-Medley (Denmark)</label>
        <year>1994</year>
      </release>
</artist>
</resp>
Avatar billede sandrasmurf Nybegynder
18. april 2010 - 14:53 #3
Et spinkelt forsøg på at lave en DiscogsResponse klasse til Deserialize metoden.

    [XmlRoot("resp")]
    public class DiscogsResponse
    {
        [XmlElement("name")]
        public string Name { get; set; }
        [XmlElement("urls")]
        public List<string> Urls { get; set; }

        [XmlElement("releases")]
        public List<Release> Artists { get; set; }
    }

    [XmlRoot("release")]
    public class Release
    {
        [XmlAttribute("id")]
        public string Id { get; set; }
        [XmlElement("title")]
        public string Title { get; set; }
        [XmlElement("label")]
        public string RecordLabel { get; set; }
        [XmlElement("year")]
        public string Year { get; set; }
    }
Avatar billede sandrasmurf Nybegynder
18. april 2010 - 16:11 #4
Angående DiscogsResponse klassen.

1) Burde det ikke være nok at skrive XML deklarationer i kantede paranteser foran klasser og properties? Og så definere 1 XmlRoot og flere XmlElement og XmlAttribute.

2) Skal man have properties, der svarer til hver attribut og NodeElement i XML filen eller kan man nøjes med dem man "skal bruge"?

3)
Må man godt bruge Autoproperties og Generic Lists?
Avatar billede janus_007 Nybegynder
19. april 2010 - 00:01 #5
Jeg skal lige høre, hvorfor bruge tid på deserialisering, vil det ikke være langt nemmere blot at hente de informationer du skal igennem Linq?

pseudo:
var sourceXml = MyDownloader.Download("....Discogs.com");

var xmldoc = XDocument.Parse(sourceXml);

var artists = from doc in xmlDoc.Elements(artists).Element("artist")
select new Artists(){
Name = doc.Name, osv....
Releases = doc.Elements("releases").Select(x => new Release(){Id = x.id, Title = x.Title),
.....
}
Avatar billede sandrasmurf Nybegynder
19. april 2010 - 03:23 #6
Jamen, det er da bestemt også en mulighed at tygge sig igennem XML response'et med XmlDocument :-)

Men nu ville jeg gerne finde ud af, hvordan deserialisering virker. Jeg har fundet en beskrivelse af noget kode, der tilsyneladende kan transmogriffe et Discogs XML response om til et objekt.

Det ligner magi, at man med 2 liniers XmlSerializer kode og et par velvalgte xml tags i sin DiscogsResponse klasse, kan slippe for at skrue en masse XmlDoc kode sammen. (Hvis det altså er sådan at det virker)
Avatar billede arne_v Ekspert
19. april 2010 - 03:43 #7
Kode som virker:

using System;
using System.IO;
using System.IO.Compression;
using System.Net;
using System.Web;
using System.Xml.Serialization;

namespace E
{
    public class Program
    {
        public static void Main(string[] args)
        {
            string key = "xxxxxxxxxxx";
            string artistName = "Dizzy Mizz Lizzy";
            string requestUrl = string.Format("http://www.discogs.com/artist/{0}?f=xml&api_key={1}", HttpUtility.UrlEncode(artistName), key);
            WebClient wc = new WebClient();
            wc.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip");
            using (GZipStream stream = new GZipStream(wc.OpenRead(requestUrl), CompressionMode.Decompress, false))
            {
                using (StreamReader reader = new StreamReader(stream))
                {
                    string str = reader.ReadToEnd();
                    XmlSerializer serializer = new XmlSerializer(typeof (resp));
                    resp r = (resp) serializer.Deserialize(new StringReader(str));
                    foreach(respArtist a in r.artist)
                    {
                        Console.WriteLine("a=" + a.name);
                        foreach(respArtistReleasesRelease ar in a.releases)
                        {
                            Console.WriteLine("ar=" + ar.title);
                        }
                    }
                }
            }
            Console.ReadKey();
        }
    }
}

Tricket er naturligvis data klasserne.

Proceduren er:

1) gem et eksempel på XML som d.xml
2) xsd d.xml
3) xsd /classes d.xsd
4) tilret d.cs (jeg har tilføjet namespace og så måtte jeg erstatte nogle [][] med [])
Avatar billede arne_v Ekspert
19. april 2010 - 03:43 #8
Hvis det site var top-prof, så ville de have leveret nogle blabla.xsd filer som kunne have genereret korrekt kode uden tilretning.
Avatar billede sandrasmurf Nybegynder
19. april 2010 - 15:04 #9
Det ser lovende ud. Jeg glæder mig til at kigge på det, når jeg kommer fra workz.

Bliver spændende om d.cs ligner min DiscogsResponse klasse eller om det er eksotisk opbygget.

Må man omdøbe klasse navnene eller ligger de fast?
Avatar billede arne_v Ekspert
19. april 2010 - 15:14 #10
Strukturen er rimelig normal. Class property navnene matcher XML element navne og er derfor rimeligt 1:1 laeselige.

Navnene ser lidt saere ud fordi de starter med lowercase, men det kan man jo vende sig til.

Jeg mener godt at du kan omdoebe, men jeg vil ikke anbefale det. Det er grundliggende genereret kode. Jeg ville tilfoeje andre properties (det er en partial class) evt. lave en wrapper class.
Avatar billede sandrasmurf Nybegynder
19. april 2010 - 20:21 #11
Så slap jeg igennem med din løsning Arne. Som du skriver, så virker det uden problemer.

Men det er godt nok et stykke fra hvad jeg forventede. Koden fra xsd.exe beskrev du som "rimelig normal", men i mine øjne er den stadig langt fra noget jeg selv ville skrive og inkludere i mine assemblies. Man skal selv tilpasse den autogenererede kode inden det virker og man bør skrive Wrapper klasser.

Tak for hjælpen til at afprøve XmlSerializeren op mod en XML webservice. Jeg tror desværre ikke at jeg kommer til at bruge kundskaben i dette projekt, men det er altid dejligt at afprøve nye ting.

Smid et svar.
Avatar billede arne_v Ekspert
20. april 2010 - 03:21 #12
Du skal ikke bekymre dig over at koden ser grim ud. Det er genereret kode. Den kode som kommer ud af VS designer for win forms ser heller ikke super godt ud. Det er bare sådan det er.

Det er trist at man skal rette i koden. Du kan undgå at rette namespace with at angive /namespace:blabla til den sidste xsd kommando. Den med at rette fra 2D til 1D array er sværere. Årsagen er at XML->XSD ikke er en 100% sikker konvertering. Hvis de leverede en XSD til brugerne så ville problemet ikke eksistere, så ville du få korrekt kode ud af det.

Det eneste andet problem er så de lower case navne. Og det kan jo camoufleres pænt ved at definere nogle delegating properties og eventuelt nogle wrapper klasser. Hvis man synes at det er umagen værd.

Det er bedre end manuelt at skrive klasser som serialiserer til et bestemt XML format!
Avatar billede arne_v Ekspert
20. april 2010 - 03:21 #13
Og et svar fra mig.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester