2

I'm really having problems getting hierarchical XML values back in a form that I can actually use, so any assistance would be much appreciated. I'm pretty new to Swift and IOS development, so to be honest I do not fully understand the parser, but I am hopeful after this that I will!

Here's an example XML that I am trying to parse, this comes back from a soap web service. All that side in terms of connecting and getting the data works perfectly fine

<s:Envelope
    xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <s:Body>
        <get_Entry_DetailsResponse
            xmlns="http://tempuri.org/">
            <get_Entry_DetailsResult>
                <ApiResult
                    xmlns="">
                    <Status>Success</Status>
                    <Parameters>
                        <TotalRecords>1</TotalRecords>
                        <Records>
                            <Entry>
                                <Entry_ID>1234</Entry_ID>
                                <Title>This is the Title</Title>
                                <Description>This is a description.</Description>
                                <Charge_USD>3</Charge_USD>
                                <Charge_GBP>1.5</Charge_GBP>
                                <Classifications>
                                    <Classification_Type>No. Of Colours</Classification_Type>
                                    <Description>10</Description>
                                    <Classification_Type>Height</Classification_Type>
                                    <Description>16.712</Description>
                                    <Classification_Type>Width</Classification_Type>
                                    <Description>1.485</Description>
                                    <Classification_Type>Width Count</Classification_Type>
                                    <Description>11</Description>
                                    <Classification_Type>Pages</Classification_Type>
                                    <Description>6</Description>
                                    <Classification_Type>Type</Classification_Type>
                                    <Description>Type Description</Description>
                                    <Classification_Type>Topic</Classification_Type>
                                    <Description>Transport</Description>
                                    <Classification_Type>Item</Classification_Type>
                                    <Description>Shop Item</Description>
                                    <Classification_Type>Material</Classification_Type>
                                    <Description>Metal</Description>
                                    <Classification_Type>Manufacturer</Classification_Type>
                                    <Description>Unknown</Description>
                                </Classifications>
                            </Entry>
                        </Records>
                    </Parameters>
                </ApiResult>
            </get_Entry_DetailsResult>
        </get_Entry_DetailsResponse>
    </s:Body>
</s:Envelope>

So I can get elements like the Entry_ID, Title, Description, Charge_GBP and Charge_USD fine, it's how to get the classifications back into the code so I can actually use it to output it on the page.

So here is my connectionDidFinishLoading, where I start the parser off and running:

func connectionDidFinishLoading(connection: NSURLConnection!) {
    var xmlParser = NSXMLParser(data: mutableData)
    xmlParser.delegate = self
    xmlParser.parse()
    xmlParser.shouldResolveExternalEntities = true
}

Then here is the XMLParser Delegate stuff:

var mutableData:NSMutableData  = NSMutableData.alloc()
var currentElementName:NSString = ""
var foundCharacters = ""
var appParsedData = [Dictionary<String, String>]()
var currentDataDictionary = Dictionary<String, String>()

func parser(parser: NSXMLParser!, didStartElement elementName: String!, namespaceURI: String!, qualifiedName qName: String!, attributes attributeDict: NSDictionary!) {

        currentElementName = elementName

    }

func parser(parser: NSXMLParser, didEndElement elementName: String!, namespaceURI: String!, qualifiedName qName: String!) {

    if !foundCharacters.isEmpty {
        currentDataDictionary[currentElementName] = foundCharacters
        foundCharacters = ""

        //Last Element so add to main Dictionary
        //Cannot find last element yet on XML so use Charge_GBP for testing until fixed
        if currentElementName == "Charge_GBP" {
            appParsedData.append(currentDataDictionary)
        }
    }
}

func parser(parser: NSXMLParser, foundCharacters string: String!) {
    if (currentElementName == "Entry_ID") || (currentElementName == "Title") || currentElementName == "Description" || currentElementName == "Charge_USD" || currentElementName == "Charge_GBP" || currentElementName == "Classification_Type" {
        foundCharacters += string
    }
}

func parserDidEndDocument(parser: NSXMLParser!) {

    self.setupItemsOnView()

}

Then my setupItemsOnView function which is where I intend to get the values and display them on the view controller so far is:

func setupItemsOnView() {

    for (currentElementName) in appParsedData {
        println("\(currentElementName):")
    }

    let test = appParsedData[0] as Dictionary<String, String>
    let test_entryid = test["Entry_ID"]
    println("Entry ID is \(test_entryid)")

}

Phew, ok, so basically I can get the values Entry_ID, Title, Description, Charge_GBP and Charge_USD in the setupItemsOnView function, but using this method I cannot get the classifications and descriptions values back in a meaningful way from the classifications parent. I'm currently using as you can see a dictionary to store the data, so I wonder if using a Dictionary is the right thing to do or not when you have hierarchical XML, but I have no idea what else to try.

From my background you'd be able to reference the XML with a dot notation and just loop around the parent for all the elements, but I can't get that working in swift, so I just need a usable way to get back the all data in a form that I can then output.

Any code you may offer to help with this would be greatly appreciated.

Cheers

D

Dave
  • 351
  • 4
  • 18

1 Answers1

1

What you'd like is something comparable to jaxb for Swift -- but I'm not aware that it exists. Anyway, parsing in Swift is akin to using a SAX parser. Presumably, you have an class hierarchy in your Swift code that corresponds to the element hierarchy in the XML. The approach I used was stateful -- just instantiate the class corresponding to the element parsed, and keep it in a variable designated for that purpose. Then, your parsing code can populate the class data as it is encountered in subsequent callbacks. Of course, you have to do this hierarchically, and use the didEndElement callback to detect completion.

fred02138
  • 3,323
  • 1
  • 14
  • 17
  • Many thanks for that, that makes alot of sense to me. However one small question, how do I deal with elements that are called the same thing but in different area of the hierarchy? I have a Description child element in the Entry parent tag, and multiple description children in the Classifications parent? As the parser will just see all of these as description and from what I can see I will have no idea what my parent is to know what to do with this data. – Dave Jan 28 '15 at 16:37
  • I see the issue -- the schema seems faulty in that it relies on the ordering of the `` elements and their `` elements. This means you'll have to have additional state variables like `inClassifications` and `lastClassificationTypeElementParsed`. You'll have to maintain the state carefully in order for it to work, but it seems doable. – fred02138 Jan 28 '15 at 16:43
  • Thanks, I now have it working as you suggested. Many thanks for the pointers!! – Dave Jan 28 '15 at 19:59
  • @Dave could you share that as I'm struggling todo the same thing currently? – Number1 Feb 23 '17 at 18:41
  • Hi @Number1 it's all changed in the latest version of swift now. I did another questiona while back at http://stackoverflow.com/questions/32863584/moving-from-nsurlconnection-to-nsurlsession-for-soap-post-in-swift/37167474#37167474 take a look at that it may well help! – Dave Feb 28 '17 at 19:30