Basic xml parsing


Basic XML parsing in swift (Mac):

import Foundation


let xmlStr:String = "<media>" +
                        "<book>The shining</book>" +
                        "<music type=\"digital\"></music>" +
                        "<movie title=\"Psycho\"/>" +
                    "</media>"
func testing(){
    let xmlDoc:NSXMLDocument = try! NSXMLDocument(XMLString: xmlStr, options: 0)
    let rootElement:NSXMLElement = xmlDoc.rootElement()!
    let children:NSArray = rootElement.children!
    let count = children.count//or use rootElement.childCount
    let a = XMLParser.childAt(children, 0)
    XMLParser.value(a!)
    for (var i = 0; i < count; i++) {
        let child:NSXMLElement = XMLParser.childAt(children, i)!
        Swift.print("child.localName: " + "\(child.localName)")
        if let type:String = XMLParser.attribute(child, "type") { print("type: " + type) }
        //print(XMLParser.attribute(child, "type"))
        let attributes:[Dictionary<String,String>] = XMLParser.attributes(child)
        if(attributes.count > 0) {  print("attr.value: "+"\(attributes[0]["value"])") }
           
        print("value: " + XMLParser.value(child))
        
        //
        print("hasAttribute: " + "\(XMLAsserter.hasAttribute(child,"type"))")
        //XPath expressions
    }
}

testing()

NOTE: the above example works in xcode playground. (plug and play)

Basics of parsing XML in ios :

//parserDidStartDocument: This one is called when the parsing actually starts. It’s obvious that is called just once per XML document.
//parserDidEndDocument: This one is the complement of the first one, and is called when the parser reaches the end of the XML data.
//parser:parseErrorOccurred: This delegate method is called when an error occurs during the parsing. The method contains an error object, which you can use to define the actual error.
//parser:didStartElement:namespaceURI:qualifiedName:attributes: This one is called when the opening tag of an element is found.
//parser:didEndElement:namespaceURI:qName: On the contrary to the above method, this is called when the closing tag of an element is found.
//parser:foundCharacters: This method is called during the parsing of the contents of an element. Its second argument is a string value containing the character that was just parsed.

//EXAMPLE: 

import UIKit

class TableViewController: UITableViewController, XMLParserDelegate {
    var books: [Book] = []
    var elementName: String = ""//name of each element name at variouse stages in the xml hierarchy
    var bookTitle = ""
    var bookAuthor = ""
    
    override func viewDidLoad() {
        super.viewDidLoad()
        if let path = Bundle.main.url(forResource: "books", withExtension: "xml") {
            if let parser = XMLParser(contentsOf: path) {//gets the content and creates the Parser instance
                parser.delegate = self//set this class as the Parsers delegate
                parser.parse()//initiates the parsing
            }
        }
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    // MARK: - Table view data source
    override func numberOfSections(in tableView: UITableView) -> Int {
         return 1
    }
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return books.count
    }
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath as IndexPath)
        let book = books[indexPath.row]
        cell.textLabel?.text = book.bookTitle
        cell.detailTextLabel?.text = book.bookAuthor
        return cell
    }
    /**
     * At the begining of an element
     */
    func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) {
        self.elementName = elementName
        if elementName == "book" {
            if attributeDict["id"] == "2" {
                Swift.print("found it 👌")
            }
            bookTitle = String()
            bookAuthor = String()
        }
    }
    /**
     * At the end of an element
     */
    func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
        if elementName == "book" {//when a book element completes parsing. Use the temp data and populate the Book struct, then append that book struct
            let book = Book.init(bookTitle: bookTitle, bookAuthor: bookTitle)
            books.append(book)
        }
    }
    /**
     * ON every character in the element
     */
    func parser(_ parser: XMLParser, foundCharacters string: String) {
        let data = string.trimmingCharacters(in: NSCharacterSet.whitespacesAndNewlines)
        
        if !data.isEmpty {//make sure its not empty data!?!?
            if elementName == "title" {//when elementName is title then append the char to the temp data
                bookTitle += data
            } else if elementName == "author" {//when elementName is title then append the char to the temp data
                bookAuthor += data
            }
        }
    }
    
}

<?xml version="1.0"?>
<catalog>
    <book id="1">
        <title>To Kill a Mockingbird</title>
        <author>Harper Lee</author>
    </book>
    <book id="2">
        <title>1984</title>
        <author>George Orwell</author>
    </book>
    <book id="b3">
        <title>The Lord of the Rings</title>
        <author>J.R.R Tolkien</author>
    </book>
    <book id="4">
        <title>The Catcher in the Rye</title>
        <author>J.D. Salinger</author>
    </book>
    <book id="5">
        <title>The Great Gatsby</title>
        <author>F. Scott Fitzgerald</author>
    </book>
</catalog>