Working with XML in Angular JS

Angular JS and Codeigniter

In this tutorial I will show you how to use the X2JS javascript library to parse XML and turn that into an AngularJS object. This is one of my RND project where I am using XML files along with HTML to create an e-learning shell.

Introduction

In this tutorial I have a courseDef xml file which has the module structure. The navigation tree decides the chapters and it’s pages. To keep it simple, I have taken only two chapters with a few pages inside them. And most important which is conversion of XML into JS object is done by the X2JS library. You can download it here.

The Controller

In this controller I have three pages defined – the main index page, the home page which is the default router for Angular and the last one is where I am showing the chapter information.

class Angularxml extends CI_Controller {
  /*calling the constructor*/
  public function __construct() {
    parent::__construct();
  }
  
  /*this is the home page*/
  public function index() {
    /*calling the js file*/
    $this->carabiner->js('xml2json.js');
    $this->carabiner->js('angularxml/angularxml_app.js');
  
    /*setting up the view data*/
    $data['header']['page_title'] = 'Learning CI Tutorial - Parsing and playing with XML in AngularJS'; // title for the page
    $data['content']['view_name'] = 'index_view'; // name of the partial view to load
    $data['content']['view_data'] = array(); // data coming inside the view
  
    /*calling the view file itself*/
    $this->load->view('main_page_view',$data);
  }
  
  public function home() {
    $this->load->view('home_view');
  }
  
  public function chapter_page() {
    $this->load->view('chapter_view');
  }
}

You can also find the file here: View file

The XML file

The XML file is structured as course. Inside it is my navigation. It contains chapters which has pages inside the. The idea is to pick up the html file name from the page tags and render the screens accordingly.

<?xml version="1.0" encoding="ISO-8859-1"?>
  
<course>
  
  <navigation>
    <chapter number="1">
      <name>Getting started</name>
      <page>Building a Drupal 7 Site</page>
      <page>Essential Tools: Drush and Git</page>
    </chapter>
  
    <chapter number="2">
      <name>Building Dynamic Pages Using Views</name>
      <page>There's a Module for That</page>
      <page>Creating Community Web Sites with Organic Groups</page>
      <page>Security in Drupal</page>
      <page>Updating Drupal</page>
      <page>Extending Your Site</page>
    </chapter>
  
  </navigation>
  
</course>

The Angular app

Now comes the main part – the angular code. First I have declared the routes. I have two for now, the home which shows the chapters in the course and the second one to show the pages inside an individual chapter using routeParams.

Currently I have kept the code very simple and so all the $http gets are inside the controller. But in my subsequent tutorials I will have to convert them into factory methods because right now I am loading the same XML every time I change the controller which is a bad thing to do from performance point of view.

There are two controllers – the MainCtrl which is being used by the home page. It is fetching the XML file using $http get and then I am using the “xml_str2json” function to parse the XML data from string to javascript object.

Once that is done, I push each chapter and finally assign that to scope so that inside the HTML I can display it.

Even in the second controller, which is the chapterCtrl I have written almost the same code, except that here I am taking an individual chapter and looping it’s inner pages through the parameter which is passed as chapter id.

/*defining the module*/
var angularXML = angular.module('angularXML', []);
  
angularXML.config(['$routeProvider', function($routeProvider) {
  $routeProvider.when('/home', {templateUrl: base_url + 'angularxml/home', controller: angularXML.MainCtrl});
  $routeProvider.when('/chapter/:id', {templateUrl: base_url + 'angularxml/chapter_page', controller: angularXML.chapterCtrl});
  $routeProvider.otherwise({redirectTo: '/home'});
}]);
  
angularXML.controller('MainCtrl', ['$scope', '$http', function($scope, $http) {
  $scope.title = "How to use XML inside AngularJS";
  $http.get(base_url + 'assets/js/angularxml/courseDef.xml').then(function(response) {
    var chapters = [];
    /*setting up the response*/
    var courseDef = x2js.xml_str2json(response.data);
    $scope.chaptersObj = courseDef.course.navigation.chapter;
  
    /*looping through the chapters*/
    var numOfChapters = $scope.chaptersObj.length;
    for (var i = 0; i < numOfChapters; i++) {
      chapters.push({
        name: $scope.chaptersObj[i].name,
        number: $scope.chaptersObj[i]._number
      });
    }
  
    $scope.chapterNames = chapters;
  });
}]);
  
angularXML.controller('chapterCtrl', ['$scope', '$routeParams', '$http', function($scope, $routeParams, $http) {
  $scope.chapterNumber = $routeParams.id;
  var chapter = $scope.chapterNumber - 1; /* index starts from zero */
  
  $http.get(base_url + 'assets/js/angularxml/courseDef.xml').then(function(response) {
    var chapters = [];
    var pages = [];
  
    /*setting up the response*/
    var courseDef = x2js.xml_str2json(response.data);
    chapters = courseDef.course.navigation.chapter;
  
    var numOfPages = chapters[chapter].length;
    var thisChapter = chapters[chapter];
    var numOfPages = thisChapter.page.length;
  
    /* looping through the pages. */
    for (var i = 0; i < numOfPages; i++) {
      pages.push({
        name: thisChapter.page[i]
      });
    }
  
    $scope.pages = pages;
    $scope.chapterName = thisChapter.name;
  });
  
}]);

You can also find the file here: View file

If you see, the home page now shows two chapters and if you click on an individual chapter it will take you to the chapter’s details page and show you the screen inside it.