Анализ XML с получением строки внутри скобок <something="Как получить эту строку">

Вот образец данных XML, которые я пытаюсь проанализировать. У меня возникли проблемы с выяснением того, как анализировать данные внутри "", вложенного в скобки, т. е. <something="Как получить эту строку">. вот, например, идентификатор хочу получить «Как получить эту строку». Я могу получить данные, если они находятся между открывающейся и закрывающейся морковкой. Я понял.

<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>

Вот мой код XML-парсера и функции делегирования

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)
    }
}

И вот как я загружаю 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)
            }
        }
    }

В методе делегата didStartElement посмотрите на параметр attributes. В этом словаре есть нужные вам данные. Ключи — это имена атрибутов, а значения — значения атрибутов.

HangarRash 17.04.2024 03:18

Раш, я об этом думал, но я могу представить, как это будет выглядеть, и я в замешательстве, что будет с кодом.

Yuda 17.04.2024 03:23

Посмотрите ссылку, которую я только что разместил перед вашим ответом.

HangarRash 17.04.2024 03:24

почему бы не использовать более современный подход с использованием конечной точки API данных JSON. https://aviationweather.gov/api/data/metar?stationString=\KV‌​NY&startTime=2024-03‌​-10T21%3A44%3A22Z&fo‌​rmat=xml&mostRecent=‌​true&format=json Его гораздо проще декодировать и обрабатывать, особенно при использовании более современного асинхронного кода let (data, response) = try await URLSession.shared.data(from: url). Вам не придется писать сотни строк кода для работы со старым XML.

workingdog support Ukraine 17.04.2024 03:56

к сожалению, aviatationweather использовала XML для большого кеша, что является конечным результатом, поскольку я могу искать доступные аэропорты. Я использовал json, но это стало камнем преткновения, потому что есть одно значение, которое я не могу найти через JSON, а именно категория полета аэропорта. Кажется, это только в XML

Yuda 17.04.2024 04:14

«Вещь», которую вы ищете, называется атрибутом (а «морковки» называются начальным и конечным тегами). Как только вы выучите базовый словарный запас, поиск информации в Google станет очень простым. Если вы изобретаете свой собственный словарь, это невозможно.

Michael Kay 17.04.2024 09:11

Скопируй это! Я забыл многое из этого, когда прекратил работу над CS — только приступив к этому, я вспомнил, насколько привлекательным и понятным был процесс Stakeover. Однако я очень ценю, что вы напомнили мне, как они называются, это определенно поможет!

Yuda 17.04.2024 22:09
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
7
63
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В функции делегирования DidStartElement вы получаете словарь attributes. Он содержит атрибуты тега.

Вы бы написали что-то вроде -

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)")
        }
    }

Обратите внимание, что это будут необязательные строки, поэтому вам нужно обработать их и при необходимости преобразовать в целое число.

К вашему сведению: по этому вопросу много дубликатов.

HangarRash 17.04.2024 03:23

Наверное, но было проще написать четкий ответ, который поможет ОП, чем продираться в поисках хорошего обмана.

Paulw11 17.04.2024 03:26

Я пробовал - их было так много, и я знаю, что не помогу, но не смог найти ответ. Я вижу, что вы сделали, но я не понимаю, как я могу обновить FoundCharacters, чтобы затем назначить значение currenAirportSkyCondition is = sky_cover.

Yuda 17.04.2024 03:40

Получил работу!! Спасибо — отмечу как ответ, просто запутался — кажется, мне все равно нужно использовать функцию FoundCharacters для присвоения значений, не заключенных в <>, это правильно?

Yuda 17.04.2024 03:50

Символы вне элементов представляют собой текстовые блоки, поэтому да, вам нужно использовать didStartElement, чтобы идентифицировать текущий элемент, а затем вы можете использовать foundCharacters, чтобы получить текст, связанный с этим элементом. Вероятно, есть веская причина, по которой JSON в наши дни гораздо более популярен, чем XML. Как отметил WorkDog, у этого сервиса есть конечная точка JSON. Благодаря Swift с ним будет намного проще работать Codable

Paulw11 17.04.2024 04:17

Я согласен, что так и было бы, однако Aviationweather использует xml для больших файлов кэша, и есть определенные атрибуты, к которым его JSON-файл предоставляет доступ, в основном и категория полета, что сэкономило мне сотни строк кода, потому что в противном случае мне пришлось бы лично определять каждый рейс. категория

Yuda 17.04.2024 07:43

Другие вопросы по теме