Zach Rochon Zach Rochon - 4 months ago 113
Swift Question

Complex Conversion XML to Dictionary (Swift / iOS)

I'm racking my brain how to convert this parsed xml into arrays or dictionaries. the xml tags are not helpful because the labels are generic and there are ~10 headers. I might be able to do something based on the order of the labels. any ideas?

NSXMLParser Method Code:

class MyXMLParserDelegate: NSObject, NSXMLParserDelegate {

@objc func parserDidStartDocument(parser: NSXMLParser) {
print("parserDidStartDocument")
}

@objc func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) {
print("didStartElement --> \(elementName)")
}

@objc func parser(parser: NSXMLParser, foundCharacters string: String) {
print("foundCharacters --> \(string)")
}

@objc func parser(parser: NSXMLParser, didEndElement elementName: String,
namespaceURI: String?, qualifiedName qName: String?) {
print("didEndElement --> \(elementName)")
}

@objc func parser(parser: NSXMLParser, didStartMappingPrefix prefix: String,
toURI namespaceURI: String) {
print("didStartMappingPrefix --> Prefix: \(prefix) toURI: \(namespaceURI)")
}

@objc func parser(parser: NSXMLParser, didEndMappingPrefix prefix: String) {
print("didEndMappingPrefix --> Prefix: \(prefix)")
}

@objc func parserDidEndDocument(parser: NSXMLParser) {
//reload table with array
print("parserDidEndDocument")
}
}


Sample results of XML parsing using NSXMLParser methods:

<result>
<header>
<col>
<label>Tree Name</label>
</col>
<col>
<label>Num Levels</label>
</col>
<col>
<label>Defaults Weight</label>
</col>
<col>
<label>Name</label>
</col>
<col>
<label>Abbrev</label>
</col>
<col>
<label>Level</label>
</col>
<col>
<label>Full Name</label>
</col>
</header>
<body>
<row>
<col>Cost Center 1</col>
<col>2</col>
<col>5</col>
<col>Miami Dolphins Front Office</col>
<col/>
<col>0</col>
<col/>
</row>
<row>
<col>Cost Center 1</col>
<col>2</col>
<col>5</col>
<col>Accounts Receivable</col>
<col>A/R</col>
<col>1</col>
<col>Accounts Receivable</col>
</row>
<row>
<col>Cost Center 1</col>
<col>2</col>
<col>5</col>
<col>06</col>
<col>06</col>
<col>1</col>
<col>06</col>
</row>
<row>
<col>Cost Center 2</col>
<col>3</col>
<col>5</col>
<col>Cost Center 2</col>
<col/>
<col>0</col>
<col/>
</row>
<row>
<col>Cost Center 2</col>
<col>3</col>
<col>5</col>
<col>test2</col>
<col/>
<col>1</col>
<col>test2</col>
</row>
<row>
<col>Cost Center 2</col>
<col>3</col>
<col>5</col>
<col>test</col>
<col/>
<col>1</col>
<col>test</col>
</row>
<row>
<col>Cost Center 3</col>
<col>3</col>
<col>5</col>
<col>Cost Center 3</col>
<col/>
<col>0</col>
<col/>
</row>
<row>
<col>Cost Center 3</col>
<col>3</col>
<col>5</col>
<col>test</col>
<col/>
<col>1</col>
<col>test</col>
</row>
</body>
<footer/>
</result>


parserDidStartDocument

didStartElement --> result

foundCharacters -->

didStartElement --> header

foundCharacters -->

didStartElement --> col

foundCharacters -->

didStartElement --> label

foundCharacters --> Tree Name

didEndElement --> label

foundCharacters -->

didEndElement --> col

foundCharacters -->

didStartElement --> col

foundCharacters -->

didStartElement --> label

foundCharacters --> Num Levels

didEndElement --> label

foundCharacters -->

didEndElement --> col

foundCharacters -->

didStartElement --> col

foundCharacters -->

didStartElement --> label

foundCharacters --> Defaults Weight

didEndElement --> label

foundCharacters -->

didEndElement --> col

foundCharacters -->

didStartElement --> col

foundCharacters -->

didStartElement --> label

foundCharacters --> Name

didEndElement --> label

foundCharacters -->

didEndElement --> col

foundCharacters -->

didStartElement --> col

foundCharacters -->

didStartElement --> label

foundCharacters --> Abbrev

didEndElement --> label

foundCharacters -->

didEndElement --> col

foundCharacters -->

didStartElement --> col

foundCharacters -->

didStartElement --> label

foundCharacters --> Level

didEndElement --> label

foundCharacters -->

didEndElement --> col

foundCharacters -->

didStartElement --> col

foundCharacters -->

didStartElement --> label

foundCharacters --> Full Name

didEndElement --> label

foundCharacters -->

didEndElement --> col

foundCharacters -->

didEndElement --> header

foundCharacters -->

didStartElement --> body

foundCharacters -->

didStartElement --> row

foundCharacters -->

didStartElement --> col

foundCharacters --> Cost Center 1

didEndElement --> col

foundCharacters -->

didStartElement --> col

foundCharacters --> 2

didEndElement --> col

foundCharacters -->

...

Answer

Figured it out, albeit likely has more complexity than necessary, will optimize later:

class MyXMLParserDelegate: NSObject, NSXMLParserDelegate {

var counter = 1
var insideBody = false
var insideElement = false
var treeName = [String]()
var numLevels = [String]()
var defaultsWeight = [String]()
var name = [String]()
var abbrev = [String]()
var level = [String]()
var fullName = [String]()


@objc func parserDidStartDocument(parser: NSXMLParser) {
    print("parserDidStartDocument")
}

@objc func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) {
    print("didStartElement       --> \(elementName)")
    if elementName == "body" {
        insideBody = true
    }
    if insideBody == true && elementName == "col" {
        insideElement = true
    }
    if elementName == "row" {
        counter = 1
    }
    print("inside element -->\(insideElement)")
}

@objc func parser(parser: NSXMLParser, foundCharacters string: String) {
    print("foundCharacters       --> \(string)")
    if insideElement == true && insideBody == true {
        switch counter {
        case 1: treeName.append(string)
        case 2: numLevels.append(string)
        case 3: defaultsWeight.append(string)
        case 4: name.append(string)
        case 5: abbrev.append(string)
        case 6: level.append(string)
        case 7: fullName.append(string)
        default: print("nothing to append")
        }
        insideElement = false
        print("inside element -->\(insideElement)")
    }
}

@objc func parser(parser: NSXMLParser, didEndElement elementName: String,
                  namespaceURI: String?, qualifiedName qName: String?) {
    print("didEndElement         --> \(elementName)")
    if elementName == "body" {
        insideBody = false
    }
    if insideBody == true && elementName == "col" {
        if insideElement == true {
            switch counter {
            case 1: treeName.append("--*n/a*--")
            case 2: numLevels.append("--*n/a*--")
            case 3: defaultsWeight.append("--*n/a*--")
            case 4: name.append("--*n/a*--")
            case 5: abbrev.append("--*n/a*--")
            case 6: level.append("--*n/a*--")
            case 7: fullName.append("--*n/a*--")
            default: print("nothing to append")
            }
            insideElement = false
        }
        counter += 1
    }

print("inside element \(insideElement)")
print("counter \(counter)")
}

@objc func parserDidEndDocument(parser: NSXMLParser) {
    //reload table with array
    print("parserDidEndDocument")
    print(treeName)
    print(numLevels)
    print(defaultsWeight)
    print(name)
    print(abbrev)
    print(level)
    print(fullName)
    struct ccArrays {
    }
}
Comments