Flutter XML Data Parsing
Tags: flutter, dart, tutorial, beginners
Published: 2020-08-14 06:19:04

Hello guys, this blog post is a part of a Flutter Video Series we are started to upload on YouTube.
__Flutter News App (Frontend to Backend)__

Here is the video:-

{% youtube qzM7zIIeH8Y %}

In this blog, we are going to implement the backend of our homepage. 

We are going to use XML data and convert into formatted JSON objects to make it easier to use in our app.

##What is an RSS Feed?##

RSS is a web feed that allows users and applications to access updates to websites in a standardized, computer-readable format.

Accessing an RSS Feed directly into our app is not quite possible.
So, we will parse the RSS/XML data into JSON and display it into the UI portion of our application. 

For that, we are going to use the package named `xml2json`: An XML to JSON conversion package.
https://pub.dev/packages/xml2json.

##xml2json##
This package allows the parsing of XML strings and the transformation of the resulting parse tree into the following XML JSON conventions:-

The package uses the [XML](http://pub.dartlang.org/packages/xml) parser to perform the parsing of XML data into a parse tree.

* Parker
* Badgerfish
* Google Data(GData).

The Parker convention is a lossy but lean conversion from XML into JSON, ideal for lightweight XML parsing, where attributes and namespace information is not needed.

Badgerfish and GData both preserve XML information such as attributes and namespaces. These are more suited to heavyweight XML parsing of say RSS feeds where this information may be needed.

Now let's see what our single item in the RSS feed looks like:
{% gist https://gist.github.com/Maadhav/710ce0187cfa88a23e1e1e2b2a27f371
 %}

As we can see here (line:17) the `url` is an _attribute_, hence we need to use either BadgerFish or GData.

In this tutorial, we will be using the GData XML Parser

Add this to your package's pubspec.yaml file:
```yaml
dependencies:
  xml2json: ^4.3.0
```

Let's create a new file for handling the parsing process: 
`rss_to_json.dart`

Lets first import the necessary libraries.
* `convert`: To convert a String into a List/Map
* `xml2json`
* `http`: For getting the XML data from the web

```dart
import 'dart:convert';
import 'package:xml2json/xml2json.dart';
import 'package:http/http.dart' as http;
```
Now create a function `rssToJson`.
```dart
Future<List> rssToJson (String category,
    {String baseUrl = "https://www.hindustantimes.com/rss/"}) async{
  var client = new http.Client();
  final myTransformer = Xml2Json();
  return await client.get(baseUrl + category + "/rssfeed.xml").then((response) {
    return response.body;
  }).then((bodyString) {
    myTransformer.parse(bodyString);
    var json = myTransformer.toGData();
    return jsonDecode(json)['rss']['channel']['item'];
  });
}
```
Here the jsonDecode function is used because the XML parser returns a String. So we just converted the String into a List.

##Using `rssToJson` in our homepage##

Now there are two ways to fetch Json data:
1. FutureBuilder()
2. Future.wait()

We will use Future.wait() in this tutorial.

##Future.wait()##
Future.wait() waits for multiple futures to complete and collects their results.

Returns a future which will complete once all the provided futures have completed, either with their results or with an error if any of the provided futures fail.

The value of the returned future will be a list of all the values that were produced in the order that the futures are provided by iterating futures.

We will create a Map<String, List> named as `newsData`.

```dart
Future getData() async {
    return Future.wait([
      rssToJson('topnews'),
      rssToJson('india'),
      rssToJson('world'),
      rssToJson('business'),
      rssToJson('sports'),
      rssToJson('cricket'),
      rssToJson('tech-features'),
      rssToJson('education'),
      rssToJson('entertainment'),
      rssToJson('music'),
      rssToJson('lifestyle'),
      rssToJson('health-fitness'),
      rssToJson('fashion-trends'),
      rssToJson('art-culture'),
      rssToJson('travel'),
      rssToJson('books'),
      rssToJson('realestate'),
      rssToJson('its-viral'),
    ]).then((value){
       newsData['topnews'] = value[0];
    newsData['india'] = value[1];
    newsData['world'] = value[2];
    newsData['business'] = value[3];
    newsData['sports'] = value[4];
    newsData['cricket'] = value[5];
    newsData['tech'] = value[6];
    newsData['education'] = value[7];
    newsData['entertainment'] = value[8];
    newsData['music'] = value[9];
    newsData['lifestyle'] = value[10];
    newsData['health-fitness'] = value[11];
    newsData['fashion-trends'] = value[12];
    newsData['art-culture'] = value[13];
    newsData['travel'] = value[14];
    newsData['books'] = value[15];
    newsData['realestate'] = value[16];
    newsData['its-viral'] = value[17];
       setState(() {
        isLoading = false;
      });
    });
  }
```
Here `value` containers all the results as a List. 

Now we will call the `initState()` in the Home() Class and call the `getData` function.

```dart
@override
void initState() {
  super.initState();
  getData();
  }
```

Now we are getting the XML Data to JSON but we want this data in the homepage.dart. So we will declare the `Map<String, List>` named `newsData` in `HomePage()` and then we will pass it to its constructor
```dart
class HomePage extends StatefulWidget {
  final Map<String, List> newsData;

  const HomePage({Key key, this.newsData}) : super(key: key);
  @override
  _HomePageState createState() => _HomePageState();
}
```

Now we need to set the data into `HomePageCard` (our reusable Widget).

```dart
TabBarView(
  controller: _tabController,
  children: List.generate(
    categories.length,
    (index) {
      var key = categories[index]
        .imageUrl
        .toString()
        .split("/")[3]
        .split(".")[0]
        .replaceAll("_", "-");
      return ListView.builder(
        padding: EdgeInsets.symmetric(horizontal: 25),
        itemBuilder: (context, i) {
          String time = _newsData[key][i]['pubDate']['__cdata'];
          DateTime timeIST = DateTime.parse(time.split(" ")[3] +
            "-" +
            getMonthNumberFromName(month: time.split(" ")[2]) +
            "-" +
            time.split(" ")[1] +
            " " +
            time.split(" ")[4]);
          timeIST = timeIST
            .add(Duration(hours: 5))
            .add(Duration(minutes: 30));
          return HomePageCard(
            title: _newsData[key][i]['title']['__cdata'],
            description: _newsData[key][i]['description']['__cdata'],
            date: timeIST.day.toString() +
                " " +
                getMonthInWordsFromNumber(month: timeIST.month) +
                " " +
                timeIST.toString().split(" ")[1].substring(0, 5),
                imageUrl: _newsData[key][i]['media\$content']['url'],
            );
        },
        itemCount: _newsData[key]?.length ?? 0,
      );
    },
)),
```
So our backend part is finished So we get the final output.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/xo1eqlbzhmzp7orlw2rn.gif)

Github Source Code Link:-
{% github Code-Decoders/ten_news_yt/%}
Branch: _Part--4--XmlToJson_