XML Parsing getting string inside brakets <something="How to get this string">

Advertisements

Here is a sample of the XML data I am trying to parse. Im having trouble figuring out how to parse the data inside the "" that is nested within the brackets i.e <something="How to get this string">. here for example id want to get "How to get this string". I am able to get the Data if its in between the opening and closing carrots I Got this.

<METAR>
   <sky_condition sky_cover="OVC" cloud_base_ft_agl="2100"/> <---- get the OVC from sky_cover
   <flight_category>IFR</flight_category>
   <metar_type>METAR</metar_type>
</METAR>

Here is my XML Parser Code & Delegate functions

import Foundation

class FeedParser: NSObject, XMLParserDelegate {
    private var airportItems: [FlightCategory] = [] // track parsing
    private var currentAirportElement: String = "" // track current item being parsed
    private var parserCompletiongHandler: (([FlightCategory]) -> Void)? // handle completion of parsing
    
    private var currentAirportFlightCategory: String = "" {
        didSet {
            // trim whitespace
            currentAirportFlightCategory = currentAirportFlightCategory.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
        }
    }
    
    private var currenAirportSkyCondition: String = "" {
        didSet {
            currenAirportSkyCondition = currenAirportSkyCondition.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
        }
    }
    
    // MARK: - URL Request
    
    // Hnadle Parsing feed
    func parseFeed(url: String, completionHandler: (([FlightCategory]) -> Void)?) {
        self.parserCompletiongHandler = completionHandler
        
        // URL Session Reques
        let request = URLRequest(url: URL(string: url)!)
        let session = URLSession.shared
        
        let task = session.dataTask(with: request) { data, response, error in
            
            // if no data
            guard let data = data else {
                if let error = error {
                    print(error.localizedDescription)
                }
                
                return
            }
            
            // if data
            // parse xml data
            let parser = XMLParser(data: data)
            parser.delegate = self
            parser.parse()
        }
        
        task.resume()
    }
    
    // MARK: - XML Parser Delegate
    func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
        // track current item
        currentAirportElement = elementName
        if currentAirportElement == "METAR" { // it is there
            // currentAirportElement = ""
            
            currentAirportFlightCategory = ""
            currenAirportSkyCondition = ""
        }
    }
    
    // Once Parser get values of element Handler
    func parser(_ parser: XMLParser, foundCharacters string: String) {
        switch currentAirportElement {
        case "flight_category": currentAirportFlightCategory += string
                
        default: break
        }
    }
    
    // Once Parser at End of element Handler
    func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
        if elementName == "METAR" { // "flight_category"
            let airportItems = FlightCategory(flight_category: currentAirportFlightCategory, sky_condition: currenAirportSkyCondition)
            self.airportItems.append(airportItems)
        }
    }
    
    // Call Completion Handler upon finishing Parsing
    func parserDidEndDocument(_ parser: XMLParser) {
        parserCompletiongHandler?(airportItems)
    }
    
    // Handle Parsing Errors
    func parser(_ parser: XMLParser, parseErrorOccurred parseError: any Error) {
        print(parseError.localizedDescription)
    }
}

And here is how I am loading the XML

private func loadXMLData() async {
        print("hmmmmm")
        let acwXMLURL = "https://aviationweather.gov/api/data/dataserver?requestType=retrieve&dataSource=metars&stationString=\KVNY&startTime=2024-03-10T21%3A44%3A22Z&format=xml&mostRecent=true"
        
        // parser feeder
        let feeder = FeedParser()
        feeder.parseFeed(url: acwXMLURL) { data in
            self.detaileHomeAirportXML = data
        }
    }
    
    private func handleXMLData() async {
        detaileHomeAirportXML?.forEach { item in
            currentFltCat = item.flight_category
            model.airportFltCat = item.flight_category
            print("XML data handled: \(currentFltCat)")
            
            if currentFltCat == "VFR" {
                color = Color(.green)
            } else if currentFltCat == "MVFR" {
                color = Color(.blue)
            } else if currentFltCat == "IFR" {
                color = Color(.red)
            } else if currentFltCat == "LIFR" {
                color = Color(red: 208 / 255, green: 45 / 255, blue: 208 / 255)
            }
        }
    }

>Solution :

In the didStartElement delegation function, you receive an attributes dictionary. This contains the attributes of the tag.

You would write something like –

func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
       
        switch(elementName) {
            case "METAR":
                currentAirportFlightCategory = ""
                currenAirportSkyCondition = ""
            case "sky_condition":
                skyCover = attributes["sky_cover"]
                cloudBase = attributes["cloud_base_ft_agl"]
            default:
                print("Ignoring element \(elementName)")
        }
    }

Note that these will be optional strings, so you need to handle that and convert to integer as required.

Leave a ReplyCancel reply