Skip to main content

Parse XML in iOS with Swift 4.0 with A SOAP Web Service Apple RSS News

A Simple XML Parsing Example in ios with Swift 4.0. 
Parse XML in iOS with Swift 4.0


ASMX - SOAP-XML(Simple Object Access Protocol - Extensible Markup Language)
SOAP - Simple Object Access Protocol itis a xml-based messaging protocol for exchanging information among computer
"ASMX provide the ability to build service that send message using the SOAP"

  • SOAP is communication via internet
  • SOAP can extend HTTP for XML messaging
  • Data transfer for web service

"XML stands for Extensible Markup Language. XML is a markup language much like HTML. XML was designed to store and transport data. XML was designed to be self-descriptive."
its defines a set of rules for encoding documents in a format human-readable and machine-readable.

In this tutorial parse xml web service(apple rss news - https://developer.apple.com/news/rss/news.rss) using a XMLParser object. The results of the parse the data in a tableView in UITableViewController. This tutorial is made with Xcode 10 and built for iOS 12.

Create New Project Xcode a new Single View App

XML parsing in iOS with Swift 4.0

Enter Project Name, Team name, Organization name, or identifier and select language swift.


Now design TableView, Cell in UITableViewController

TableView XML parse Data

1. First Create a XMLParser Class - //  XMLParser.swift
in struct declare properties of object


import Foundation
import UIKit

struct RSSItem {
    var title: String
    var description: String
    var pubDate: String
}

// download xml from a server
// parse xml to Foundation object
// call back


class FeedParser: NSObject, XMLParserDelegate {
    private var rssItem: [RSSItem] = []
    private var currentElement = ""
    
    private var currentTitle = ""
    {
        didSet{
            currentTitle = currentTitle.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
        }
    }
    private var currentDescription = "" {
        didSet{
            currentDescription = currentDescription.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
        }
    }
    
    private var currentPubDate = "" {
        didSet{
            currentPubDate = currentPubDate.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
        }
    }
    private var parserCompletionHandeler: (([RSSItem])-> Void)?

// Download XML
    
   func parseFeed(url: String, completionHandler: (([RSSItem])-> Void)?){
        self.parserCompletionHandeler = completionHandler
        let request = URLRequest(url: URL(string: url)!)
        let urlSession = URLSession.shared
        let task = urlSession.dataTask(with: request) { (data, response, error) in
            guard let data = data else{
                if let error = error {
                    print(error.localizedDescription)
                }
                return
            }
            // parse our xml data
            
            let parser = XMLParser(data: data)
            parser.delegate = self
            parser.parse()
        }
        task.resume()
    }

    // XML Parser Delegate

    
    func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
        currentElement = elementName
        
        if currentElement == "item"{
            currentTitle = ""
            currentDescription = ""
            currentPubDate = ""
        }
        
        
    }
    func parser(_ parser: XMLParser, foundCharacters string: String) {
        switch currentElement {
        case "title": currentTitle += string
            case "description": currentDescription += string
            case "pubDate": currentPubDate += string
        default: break
        }
    }
    func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
        if elementName == "item" {
            let rssItem = RSSItem(title: currentTitle, description: currentDescription, pubDate: currentPubDate)
            self.rssItem.append(rssItem)
        }
    }
    func parserDidEndDocument(_ parser: XMLParser) {
        parserCompletionHandeler?(rssItem)
    }
    func parser(_ parser: XMLParser, parseErrorOccurred parseError: Error) {
        print(parseError.localizedDescription )
    }
}


2. Then Create TableView Cell Properties where are to display data. - NewsTableCell.swift

import Foundation
import UIKit

enum CellState {
    case expanded
    case collapsed
}

class NewsTableCell: UITableViewCell {
    
    @IBOutlet weak var titleLabel: UILabel!
    @IBOutlet weak var descriptionLabel: UILabel!{
        didSet{
            descriptionLabel.numberOfLines = 3
        }
    }
    
    @IBOutlet weak var dateLabel: UILabel!
    
    var item: RSSItem! {
        didSet {
            titleLabel.text = item.title
            descriptionLabel.text = item.description
            dateLabel.text = item.pubDate
            
            
        }
    }
}

3. Fatch Data UITableViewController TableView. // NewsTableViewController.swift

import Foundation
import UIKit

class NewsTableViewController: UITableViewController {
    private var rssItems: [RSSItem]?
    private var cellState: [CellState]?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.estimatedRowHeight = 155.0
        tableView.rowHeight = UITableView.automaticDimension
        fetchData()
    }
    private func fetchData(){
    let feedparser = FeedParser()
        feedparser.parseFeed(url: "https://developer.apple.com/news/rss/news.rss") { (rssItems) in
            self.rssItems = rssItems
            self.cellState = Array(repeating: .collapsed, count: rssItems.count)
            OperationQueue.main.addOperation {
                self.tableView.reloadSections(IndexSet(integer: 0), with: .left)
            }
            
        }
        
    }
    
    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        guard let rssItems = rssItems else {
            return 0
        }
        return rssItems.count
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! NewsTableCell
        if let item = rssItems?[indexPath.row]{
            cell.item = item
            cell.selectionStyle = .none
            if let cellState = cellState{
                cell.descriptionLabel.numberOfLines = (cellState[indexPath.row] == .expanded) ? 0 : 4
            }
        }
        return cell
        
    }
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
        let cell = tableView.cellForRow(at: indexPath) as! NewsTableCell
        tableView.beginUpdates()
        cell.descriptionLabel.numberOfLines = (cell.descriptionLabel.numberOfLines == 0) ? 3 : 0
        cellState?[indexPath.row] = (cell.descriptionLabel.numberOfLines == 0) ? .expanded: .collapsed
        tableView.endUpdates() 
    }
}

Finally Output - here parse data with XMLParser

Parse XML in iOS with Swift 4.0 with A SOAP Web Service Apple RSS News



Comments

Popular posts from this blog

Add a Scene Delegate to your existing project with Storyboard in Swift

To add a scene delegate, first, create a new Swift file that you’ll call "SceneDelegate" containing a subclass of UIResponder, just like the AppDelegate, and that conforms to UIWindowSceneDelegate.  As your app might supports other versions than iOS 13, make this class only available for iOS 13. This is what you should have : If you are working a project that is storyboard based, please set storyboard  initial view controller SceneDelegate.swift import UIKit @available ( iOS 13.0 , *) class SceneDelegate : UIResponder , UIWindowSceneDelegate {     var window : UIWindow ?     func scene ( _ scene: UIScene , willConnectTo session: UISceneSession , options connectionOptions: UIScene . ConnectionOptions ) {                  let storyboard = UIStoryboard (name: "Main" , bundle: nil )         let initialViewController = storyboard. instantiateViewController (withIdentifier: "ViewController" )         let mainNavigationController = UINavigationControlle

How Create Animated Circle Progress Bar iOS 11 Swift 4

  Animated Circle Progress Bar iOS 11 Swift 4 With MBCircularProgressBa r - https://github.com/MatiBot/MBCircularProgressBar A circular, animatable & highly customizable progress bar from the Interface Builder Swift, Using pod fite MBCircularProgressBar Installation Cocoapods terminal. pod "MBCircularProgressBar" That - A Simple Steps to installed pod file -        Open terminal        Command on terminal go to project folder Cd path        set your project path on terminal.        command : pod init        open pod file - open -e podfile        added in pod file with in : pod "MBCircularProgressBar"        Command : Pod install        Close project of Xcode        open your Project from terminals        Command : open PodDemos.xcworkspace After opern StoryBoard and Now drag a UIView over the viewController in storyboard Or set UIView Constraint width, height or verticle or horzentail space and set a class MBCircul

How to Use Multiple Sections in UITableView iOS Swift !

Multiple sections in UITableView iOS Swift. UITableView is very important part of iOS ecosystem. So we split tableviews in sections. Then its easier to find right information.  1. First let’s create a project as usual. Create a new single view application X code project. Set project name to UIViewController.  2. Go to main storyboard & select view controller & use UITableView 3. Select tableview & make it initial view controller  4 Create a custom Sections Class like Name => TableSections, create register cell static return “ getCellNibs ” method. Then create  4 section enum “TableItems” then after append all sections to an array model. import UIKit struct CellNib {      static func getCellNibs () -> [ String ] {          return [ "Cell1" , "Cell2" , "Cell3" , "Cell4" ]     } } enum TableItems : Int {      case TableSections1      case TableSections2      case TableSections3      case TableSections4 } class TableSec