Flutter Dart Http XML rest convert to Json

I'm trying to get a album list from a server, the server uses xml and I'm trying to convert it to json but for some reason it doesn't work/comes back as null.


import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:xml2json/xml2json.dart';
import 'package:get/get.dart';
import 'package:xml/xml.dart' as xml;

class RecentlyAddedHome extends StatefulWidget {
  @override
  _RecentlyAddedHomState createState() => _RecentlyAddedHomState();
}

  Future<List<AlbumsResponse>> fetchRecentlyAddedAlbums() async{
  final aresponse = await http.get(recentAlbumsURL);
  xml2json.parse(aresponse.body);
  var jsondata = xml2json.toGData();
  var data = json.decode(jsondata);
  print(data);
  return AlbumsResponse.fromJson(data).toList();
}


class _RecentlyAddedHomState extends State<RecentlyAddedHome> {
  final Future<List<AlbumsResponse>> albumsresponse = fetchRecentlyAddedAlbums();
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        child: FutureBuilder(
          future: fetchRecentlyAddedAlbums(),
          builder: (context, data){
            if (data.hasData){
              List<AlbumsResponse> albumsresponse = data.data;
              return ListView.builder(
              itemCount: albumsresponse.length,
              itemBuilder: (context, index){
                return ListTile(
                  title: Text(albumsresponse[index].title,style: TextStyle(fontSize: 25.0),),
                );
              }, 
              );
            }
          },
        )
      )
    );
  }
}

this is my model for it

import 'package:xml/xml.dart' as xml;
import 'package:music_app_prototype/services/auth.dart';
import 'package:http/http.dart' as http;

 class AlbumsResponse {
  final String title;
  final int albumid;
  final String artist;
  final int coverart;

  AlbumsResponse({this.albumid, this.artist, this.coverart, this.title});

  factory AlbumsResponse.fromJson(Map<String, dynamic> json){
    return AlbumsResponse(
      title: json['_title'] as String,
      albumid: json['_albumid'] as int,
      artist: json['_artist'] as String,
      coverart: json['_coverart'] as int,
    );
  }
  get albumtitle => this.title;

  Future<List<AlbumsResponse>> toList() {}
}

and this is what the server sends me when i make the request

<?xml version="1.0" encoding="UTF-8"?>
<subsonic-response xmlns="http://subsonic.org/restapi" status="ok" version="1.15.0">
    <albumList>
        <album id="695" parent="577" isDir="true" title="Whatever" album="Whatever" artist="Kaytranada" genre="Hip-Hop" coverArt="695" playCount="0" created="2020-04-18T02:01:55.546Z"/>
        <album id="850" parent="581" isDir="true" title="Cruel Intentions" album="Cruel Intentions" artist="Tory Lanez" genre="Hip-Hop" coverArt="850" playCount="1" created="2020-04-18T01:56:48.148Z"/>
        <album id="649" parent="574" isDir="true" title="So Far Gone" album="So Far Gone" artist="Drake" year="2009" genre="Hip-Hop/Rap" coverArt="649" playCount="0" created="2020-04-18T01:49:12.120Z"/>
        <album id="668" parent="575" isDir="true" title="Myst" album="Myst" artist="Herzeloyde" year="2020" genre="Electro" coverArt="668" playCount="1" created="2020-04-05T03:08:36.596Z"/>
        <album id="607" parent="572" isDir="true" title="Survival" album="Survival" artist="Dave East" year="2019" genre="Hip-Hop/Rap" coverArt="607" playCount="2" created="2020-03-01T02:29:48.072Z"/>
        <album id="792" parent="580" isDir="true" title="Yikes" album="Yikes" artist="Nicki Minaj" year="2020" genre="Rap/Hip Hop" coverArt="792" playCount="0" created="2020-02-17T04:47:49.067Z"/>
        <album id="790" parent="580" isDir="true" title="Sucka Free" album="Sucka Free" artist="Nicki Minaj" year="2008" genre="Hip-Hop" coverArt="790" playCount="0" created="2020-01-02T01:34:11.738Z"/>
        <album id="786" parent="580" isDir="true" title="Playtimes Over" album="Playtimes Over" artist="Nicki Minaj" year="2007" genre="Hip-Hop" coverArt="786" playCount="0" created="2020-01-02T01:34:11.716Z"/>
        <album id="715" parent="578" isDir="true" title="No Ceilings 2" album="No Ceilings 2" artist="Lil Wayne" year="2009" genre="Hip-Hop" coverArt="715" playCount="0" created="2020-01-02T01:34:04.226Z"/>
        <album id="788" parent="580" isDir="true" title="Queen" album="Queen" artist="Nicki Minaj" year="2018" genre="Hip-Hop/Rap" coverArt="788" playCount="0" created="2020-01-02T00:25:00.671Z"/>
    </albumList>
</subsonic-response>

When i try to go to the Recently added page it says my build function returned null? I see that i get the data but it still doesn't show up. Can anyone help me, I'm not sure what I'm doing wrong, if i don't have to convert it from xml to json, how to do i work with it in xml form? Thanks!

1 answer

  • answered 2020-06-01 01:34 chunhunghan

    You can copy paste run full code below
    Step 1: Parse with payloadFromJson and return data.subsonicResponse.albumList.album, see full code for detail Payload class definition

    Payload payloadFromJson(String str) => Payload.fromJson(json.decode(str));
    ...
    final aresponse = http.Response(xml, 200);
    
    xml2json.parse(aresponse.body);
    var jsondata = xml2json.toGData();
    var data = payloadFromJson(jsondata);
    var albumList = data.subsonicResponse.albumList.album;
    
    return albumList;
    

    Step 2: builder need to define type AsyncSnapshot<List<AlbumsResponse>> and check connectionState

     builder: (context, AsyncSnapshot<List<AlbumsResponse>> data) {
            switch (data.connectionState) {
              case ConnectionState.none:
                return Text('none');
              case ConnectionState.waiting:
                return Center(child: CircularProgressIndicator());
              case ConnectionState.active:
                return Text('');
              case ConnectionState.done:
                if (data.hasData) {
    

    working demo

    enter image description here

    full code

    import 'package:flutter/material.dart';
    import 'package:xml2json/xml2json.dart';
    import 'package:http/http.dart' as http;
    import 'dart:convert';
    
    Payload payloadFromJson(String str) => Payload.fromJson(json.decode(str));
    
    String payloadToJson(Payload data) => json.encode(data.toJson());
    
    class Payload {
      Payload({
        this.version,
        this.encoding,
        this.subsonicResponse,
      });
    
      String version;
      String encoding;
      SubsonicResponse subsonicResponse;
    
      factory Payload.fromJson(Map<String, dynamic> json) => Payload(
            version: json["version"],
            encoding: json["encoding"],
            subsonicResponse: SubsonicResponse.fromJson(json["subsonic-response"]),
          );
    
      Map<String, dynamic> toJson() => {
            "version": version,
            "encoding": encoding,
            "subsonic-response": subsonicResponse.toJson(),
          };
    }
    
    class SubsonicResponse {
      SubsonicResponse({
        this.status,
        this.version,
        this.xmlns,
        this.albumList,
      });
    
      String status;
      String version;
      String xmlns;
      AlbumList albumList;
    
      factory SubsonicResponse.fromJson(Map<String, dynamic> json) =>
          SubsonicResponse(
            status: json["status"],
            version: json["version"],
            xmlns: json["xmlns"],
            albumList: AlbumList.fromJson(json["albumList"]),
          );
    
      Map<String, dynamic> toJson() => {
            "status": status,
            "version": version,
            "xmlns": xmlns,
            "albumList": albumList.toJson(),
          };
    }
    
    class AlbumList {
      AlbumList({
        this.album,
      });
    
      List<AlbumsResponse> album;
    
      factory AlbumList.fromJson(Map<String, dynamic> json) => AlbumList(
            album: List<AlbumsResponse>.from(
                json["album"].map((x) => AlbumsResponse.fromJson(x))),
          );
    
      Map<String, dynamic> toJson() => {
            "album": List<dynamic>.from(album.map((x) => x.toJson())),
          };
    }
    
    class AlbumsResponse {
      AlbumsResponse({
        this.id,
        this.parent,
        this.isDir,
        this.title,
        this.album,
        this.artist,
        this.genre,
        this.coverArt,
        this.playCount,
        this.created,
        this.year,
      });
    
      String id;
      String parent;
      String isDir;
      String title;
      String album;
      String artist;
      String genre;
      String coverArt;
      String playCount;
      DateTime created;
      String year;
    
      factory AlbumsResponse.fromJson(Map<String, dynamic> json) => AlbumsResponse(
            id: json["id"],
            parent: json["parent"],
            isDir: json["isDir"],
            title: json["title"],
            album: json["album"],
            artist: json["artist"],
            genre: json["genre"],
            coverArt: json["coverArt"],
            playCount: json["playCount"],
            created: DateTime.parse(json["created"]),
            year: json["year"] == null ? null : json["year"],
          );
    
      Map<String, dynamic> toJson() => {
            "id": id,
            "parent": parent,
            "isDir": isDir,
            "title": title,
            "album": album,
            "artist": artist,
            "genre": genre,
            "coverArt": coverArt,
            "playCount": playCount,
            "created": created.toIso8601String(),
            "year": year == null ? null : year,
          };
    }
    
    Xml2Json xml2json = Xml2Json();
    Future<List<AlbumsResponse>> fetchRecentlyAddedAlbums() async {
      //final aresponse = await http.get(recentAlbumsURL);
      String xml = '''
      <?xml version="1.0" encoding="UTF-8"?>
    <subsonic-response xmlns="http://subsonic.org/restapi" status="ok" version="1.15.0">
        <albumList>
            <album id="695" parent="577" isDir="true" title="Whatever" album="Whatever" artist="Kaytranada" genre="Hip-Hop" coverArt="695" playCount="0" created="2020-04-18T02:01:55.546Z"/>
            <album id="850" parent="581" isDir="true" title="Cruel Intentions" album="Cruel Intentions" artist="Tory Lanez" genre="Hip-Hop" coverArt="850" playCount="1" created="2020-04-18T01:56:48.148Z"/>
            <album id="649" parent="574" isDir="true" title="So Far Gone" album="So Far Gone" artist="Drake" year="2009" genre="Hip-Hop/Rap" coverArt="649" playCount="0" created="2020-04-18T01:49:12.120Z"/>
            <album id="668" parent="575" isDir="true" title="Myst" album="Myst" artist="Herzeloyde" year="2020" genre="Electro" coverArt="668" playCount="1" created="2020-04-05T03:08:36.596Z"/>
            <album id="607" parent="572" isDir="true" title="Survival" album="Survival" artist="Dave East" year="2019" genre="Hip-Hop/Rap" coverArt="607" playCount="2" created="2020-03-01T02:29:48.072Z"/>
            <album id="792" parent="580" isDir="true" title="Yikes" album="Yikes" artist="Nicki Minaj" year="2020" genre="Rap/Hip Hop" coverArt="792" playCount="0" created="2020-02-17T04:47:49.067Z"/>
            <album id="790" parent="580" isDir="true" title="Sucka Free" album="Sucka Free" artist="Nicki Minaj" year="2008" genre="Hip-Hop" coverArt="790" playCount="0" created="2020-01-02T01:34:11.738Z"/>
            <album id="786" parent="580" isDir="true" title="Playtimes Over" album="Playtimes Over" artist="Nicki Minaj" year="2007" genre="Hip-Hop" coverArt="786" playCount="0" created="2020-01-02T01:34:11.716Z"/>
            <album id="715" parent="578" isDir="true" title="No Ceilings 2" album="No Ceilings 2" artist="Lil Wayne" year="2009" genre="Hip-Hop" coverArt="715" playCount="0" created="2020-01-02T01:34:04.226Z"/>
            <album id="788" parent="580" isDir="true" title="Queen" album="Queen" artist="Nicki Minaj" year="2018" genre="Hip-Hop/Rap" coverArt="788" playCount="0" created="2020-01-02T00:25:00.671Z"/>
        </albumList>
    </subsonic-response>
    ''';
    
      final aresponse = http.Response(xml, 200);
    
      xml2json.parse(aresponse.body);
      var jsondata = xml2json.toGData();
      var data = payloadFromJson(jsondata);
      var albumList = data.subsonicResponse.albumList.album;
      //print(albumList.toString());
      return albumList;
    }
    
    class RecentlyAddedHome extends StatefulWidget {
      @override
      _RecentlyAddedHomState createState() => _RecentlyAddedHomState();
    }
    
    class _RecentlyAddedHomState extends State<RecentlyAddedHome> {
      final Future<List<AlbumsResponse>> albumsresponse =
          fetchRecentlyAddedAlbums();
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
            body: Container(
                child: FutureBuilder(
          future: fetchRecentlyAddedAlbums(),
          builder: (context, AsyncSnapshot<List<AlbumsResponse>> data) {
            switch (data.connectionState) {
              case ConnectionState.none:
                return Text('none');
              case ConnectionState.waiting:
                return Center(child: CircularProgressIndicator());
              case ConnectionState.active:
                return Text('');
              case ConnectionState.done:
                if (data.hasData) {
                  List<AlbumsResponse> albumsresponse = data.data;
                  return ListView.builder(
                    itemCount: albumsresponse.length,
                    itemBuilder: (context, index) {
                      return ListTile(
                        title: Text(
                          albumsresponse[index].title,
                          style: TextStyle(fontSize: 25.0),
                        ),
                      );
                    },
                  );
                }
            }
          },
        )));
      }
    }
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
            visualDensity: VisualDensity.adaptivePlatformDensity,
          ),
          home: RecentlyAddedHome(),
        );
      }
    }