Разбор самозакрывающихся тегов XML в Swift

У меня есть XML-файл, содержащий следующие данные:

<Book>
    <title>Some Random Book</title>
        <author>Someone Someone</author>
        <book_type>
            <FICT />
            <REF />
        </book_type>
</Book>

Я пытаюсь написать для него структуру, но не знаю, как бороться с самозакрывающимися тегами внутри "book_type". Это перечисления? Не все книги будут иметь «book_type», а если и есть, то их может быть несколько, как в примере выше.

Вот что у меня есть, не уверен, что это правильно:

struct Book {
    var title: String?
    var author: String?
    var book_type: BookType?
}

enum BookType {
    case fiction
    case nonfiction     
    case reference
    case autobiography  
}

Спасибо!

Найдите в Интернете парсеры XML; у любого из них есть документация, в которой указано, что делать.

lorem ipsum 15.08.2024 22:50
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
1
71
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Каждый тег в XML можно рассматривать как представляющий объект. В данном случае Book — это сложный объект с несколькими атрибутами. title и author являются простыми объектами и могут быть представлены существующим типом данных (String). Из примера видно, что Book может иметь несколько типов книг, поэтому book_type можно представить как массив. Это может быть массив строк или перечислений, это зависит от вас и от того, как эти значения будут использоваться в другом месте кода.

Что касается самозакрывающихся тегов, я считаю, что имя тега обычно представляет собой имя атрибута, а не значение тега. Самозакрывающийся тег аналогичен объекту со значениями по умолчанию. В случае наличия нескольких значений может быть сложно увидеть разницу, поскольку вы не даете имена элементам в списке.

Я бы организовал данные XML примерно так:

<Book>
    <title>Some Random Book</title>
    <author>Someone Someone</author>
    <book_type>
        <type>FICT</type>
        <type>REF</type>
    </book_type>
</Book>

И структура модели Swift:

struct Book {
    var title: String?
    var author: String?
    var book_type: [BookType]
}

enum BookType {
    case fiction
    case nonfiction     
    case reference
    case autobiography  
}

Надеюсь, это поможет.

Спасибо! К сожалению, я не создаю XML — я получаю его с самозакрывающимися тегами через API.

RRR 16.08.2024 16:49

Проблема, с которой вы столкнулись, не имеет ничего общего с анализом XML. Это действительный XML; разобрать его достаточно легко. Проблема в том, что вам нужно придумать какой-то способ представления XML как объекта. То, как вы это сделаете, полностью зависит от вас; нет никаких волшебных правил. Следует иметь в виду, что не каждая топология XML легко преобразуется в объект Swift — и это пример такой топологии.

Если вы точно знаете, что четыре типа книг, которые вы перечислили в перечислении BookType, — единственные, которые когда-либо будут встречаться, то мне кажется, что book_type Book наиболее удобно было бы набором BookType, поскольку порядок не меняется. t имеет значение и данный тип либо есть, либо его нет в списке (а если book_type нет, то набор может быть просто пустым):

struct Book {
    let title: String
    let author: String
    let book_type: Set<BookType>
}

enum BookType {
    case fiction
    case nonfiction     
    case reference
    case autobiography  
}

Вы заметите, что я не сделал ничего необязательного, поскольку предполагаю, что у каждой книги есть название и автор. Но это только предположение; вам предстоит спроектировать эти объекты на основе известных вам способов легальной структуризации XML.


Если вам не ясно, как перейти от исходного XML к заданному объекту Book, вот полный (но игрушечный) пример, в котором мы создаем ваш пример XML и анализируем его в viewDidLoad контроллера представления:

import UIKit

class ViewController: UIViewController {

    let parserDelegate = BookParserDelegate()

    override func viewDidLoad() {
        super.viewDidLoad()
        let xml = """
        <Book>
            <title>Some Random Book</title>
            <author>Someone Someone</author>
            <book_type>
                <FICT />
                <REF />
            </book_type>
        </Book>
        """
        let xmlData = xml.data(using: .utf8)!
        let parser = XMLParser(data: xmlData)
        parser.delegate = parserDelegate
        parser.parse()
        if let book = parserDelegate.theBook {
            print(book)
        }
    }
}

class BookParserDelegate: NSObject, XMLParserDelegate {
    struct Collector {
        var title = ""
        var author = ""
        var book_types = Set<BookType>()
    }
    var collector = Collector()
    var currentPath: WritableKeyPath<Collector, String>?
    var doingBookTypes = false
    var theBook: Book?

    func parser(
        _ parser: XMLParser,
        didStartElement elementName: String,
        namespaceURI: String?,
        qualifiedName qName: String?,
        attributes attributeDict: [String : String] = [:]
    ) {
        if elementName == "title" {
            currentPath = \.title
        } else if elementName == "author" {
            currentPath = \.author
        } else if elementName == "book_type" {
            doingBookTypes = true
        } else if doingBookTypes {
            if let type = BookType(rawValue: elementName) {
                collector.book_types.insert(type)
            }
        }
    }
    func parser(
        _ parser: XMLParser,
        didEndElement elementName: String,
        namespaceURI: String?,
        qualifiedName qName: String?
    ) {
        currentPath = nil
        if elementName == "book_type" {
            doingBookTypes = false
        } else if elementName == "Book" {
            theBook = Book(
                title: collector.title,
                author: collector.author,
                book_type: collector.book_types
            )
        }
    }
    func parser(
        _ parser: XMLParser,
        foundCharacters string: String
    ) {
        if let currentPath {
            collector[keyPath: currentPath] = string
        }
    }
}

struct Book {
    let title: String
    let author: String
    let book_type: Set<BookType>
}

enum BookType: String {
    case fiction = "FICT"
    case reference = "REF"
}

Результат:

Book(
    title: "Some Random Book", 
    author: "Someone Someone", 
    book_type: Set([.reference, .fiction])
)

что я считаю правильным для данного XML. Обратите внимание: я не использовал все четыре случая вашего BookType, поскольку они не встречаются в примере XML, и вы не сказали мне, как они будут выглядеть, если они встречаются. В любом случае, это всего лишь игрушечный пример; очистка кода, его настройка и т. д. оставлены в качестве упражнения для читателя.

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