4
 struct person{
    var name = " "
    var sex = " "
    var age = " "
    }

var personArray: [person] = []

My Xml string contains two group of data

<a>
<name> abc </name>
<sex> male </sex>
<age> 13   </age>
</a>
<a>
<name> bcd </name>
<sex> male </sex>
<age> 14   </age>
</a>

How can i parse this xml string into personArray? i know how to parse a xml string into single object. but i don't know how to parse this into Array.

1

1 Answer 1

3

You can use NSXMLParser (or XMLParser as it now is in Swift 3). NSXMLDocument is also a possibility, but isn't available of iOS, whereas XMLParser is available on all OSs. Here's a simple implementation of your case...

struct Person { // NB capitalised your type - it's good practice
    var name = " "
    var sex = " "
    var age = " "
}
let inputString = "<a><name> abc </name><sex> male </sex><age> 13   </age></a><a><name> bcd </name><sex> male </sex><age> 14   </age></a>"

// Wrap it up or it won't be valid XML
let document = "<doc>" + inputString + "</doc>" 

// We can create a parser from a URL, a Stream, or NSData.
if let data = document.data(using: .utf16) { // Get the NSData
    let xmlParser = XMLParser(data: data) 
    let delegate = MyDelegate() // This is your own delegate - see below
    xmlParser.delegate = delegate 
    if xmlParser.parse() {
        print("Result \(delegate.personArray)")
        // "Result [Person(name: " abc ", sex: " male ", age: " 13   "), Person(name: " bcd ", sex: " male ", age: " 14   ")]\n" - as required
    }
}

class MyDelegate: NSObject, XMLParserDelegate {
    // Simple state machine to capture fields and add completed Person to array
    var personArray: [Person] = []
    enum State { case none, name, sex, age }
    var state: State = .none
    var newPerson: Person? = nil

    func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) {
        switch elementName {
        case "a" :
            self.newPerson = Person()
            self.state = .none
        case "sex":
            self.state = .sex
        case "name":
            self.state = .name
        case "age":
            self.state = .age
        default:
            self.state = .none
        }
    }
    func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
        if let newPerson = self.newPerson, elementName == "a" {
            self.personArray.append(newPerson)
            self.newPerson = nil
        }
        self.state = .none
    }

    func parser(_ parser: XMLParser, foundCharacters string: String) {
        guard let _ = self.newPerson else { return }
        switch self.state {
        case .name:
            self.newPerson!.name = string
        case .age:
            self.newPerson!.age = string
        case .sex:
            self.newPerson!.sex = string
        default:
            break
        }
    }

    func parser(_ parser: XMLParser, parseErrorOccurred parseError: Error) {
    }            
}

To get it work in Playgrounds you'll need to declare the delegate first (above the invocation), but it reads better this way...

Sign up to request clarification or add additional context in comments.

1 Comment

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.