Good afternoon everyone. Tell me how to reach the child elements of the XML?
Add child elements of <offer> to the structure Offer.
File XML
<yml_catalog date="2023-12-28 17:13">
<shop>
<name>applen1.ru</name>
<company>applen1.ru</company>
<url>https://applen1.ru</url>
<platform>1C-Bitrix</platform>
<currencies>
<currency id="RUB" rate="1"/>
</currencies>
<categories>
<category id="32">Ремонт техники Apple</category>
<category id="15" parentId="32">Ремонт iPhone</category>
<category id="166" parentId="15">Сложный ремонт</category>
<category id="20" parentId="15">Ремонт iPhone 3G/3Gs</category>
</categories>
<offers>
<offer id="188" available="true">
<url>https://applen1.ru/remont/detail/zamena-stekla-iphone-6s/</url>
<price>2590</price>
<currencyId>RUB</currencyId>
<categoryId>94</categoryId>
<categoryId>149</categoryId>
<picture>https://applen1.ru/upload/iblock/5b6/5b6fa009db959cd4d73b0f80dcb2649b.png</picture>
<name>Замена стекла iPhone 6s</name>
<description>Треснуло или разбилось сенсорное стекло iPhone 6S. Экран плохо реагирует на нажатие или самопроизвольно "дергается" при работе.</description>
</offer>
<offer id="198" available="true">
<url>https://applen1.ru/remont/detail/zamena-akkumulyatora-akb-iphone-6s/</url>
<price>1990</price>
<currencyId>RUB</currencyId>
<categoryId>94</categoryId>
<picture>https://applen1.ru/upload/iblock/d18/d18702e7a02df389891e2ea0f5b837d1.jpg</picture>
<name>Замена аккумулятора iPhone 6s</name>
<description>iPhone 6S не включается, быстро садится, плохо заряжается, выключается, не разрядившись полностью.</description>
</offer>
</offers>
</shop>
</yml_catalog>
My code
View
import UIKit
import PlaygroundSupport
final class MyViewController : UIViewController {
private let customUI = CustomElement()
private let fileManagert = FileManagerMock()
private lazy var buttonLoad: UIButton = customUI.createButton()
private var ooffer: [Offer] = []
override func loadView() {
let view = UIView()
view.backgroundColor = .white
buttonLoad.frame = CGRect(x: 100, y: 250, width: 200, height: 46)
buttonLoad.addTarget(self, action: #selector(buttonDidLoad), for: .touchUpInside)
view.addSubview(buttonLoad)
self.view = view
}
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()
Action UI
private extension MyViewController {
@objc func buttonDidLoad() {
fileManagert.filePatch { responce in
switch responce {
case .success(let data):
guard let currentData = data.data(using: .utf8) else { return }
let parser = MemoParser(data: currentData)
if parser.parse() {
}
case .failure(let error):
print("ERROR \(error.localizedDescription)")
}
}
}
}
final class FileManagerMock {
func filePatch(responceResult: (Result<String, Error>) -> Void) {
if let filepath = Bundle.main.path(forResource: "ExampleTest", ofType: "xml") {
do {
let contents = try String(contentsOfFile: filepath)
responceResult(.success(contents))
} catch let error {
responceResult(.failure(error))
}
} else {
print("Error load file!")
}
}
}
struct Offer {
var offer: String
var available: String
var price: String
var categoryID: [String]
var description: String
var name: String
var id: String
}
final class MemoParser: XMLParser {
private var category = [String: Any]()
private var currentElement = ""
private var offer = Offer(offer: "",
available: "String",
price: "",
categoryID: [],
description: "",
name: "",
id: ""
)
private var offers: [Offer] = []
override init(data: Data) {
super.init(data: data)
self.delegate = self
}
}
extension MemoParser: XMLParserDelegate {
// Looking for an element 'offer'
func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
switch elementName {
case "offer":
// Adding attributes 'id' and 'offer'
offer = disassembleOffer(dictionary: attributeDict)
default:
currentElement = elementName
}
}
// Searching the dictionary by keys
private func disassembleOffer(dictionary: [String : String]) -> Offer {
// Temp structure 'Offer'
var tempOffer = Offer(
offer: "",
available: "String",
price: "",
categoryID: [],
description: "",
name: "",
id: ""
)
for (attr_key, attr_val) in dictionary {
switch attr_key {
case "id":
tempOffer.id = attr_val
case "available":
tempOffer.available = attr_val
default:
break
}
}
return tempOffer
}
func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
if elementName == "offer" {
// Add current category in array categoryes
offers.append(offer)
}
}
// Called when a character sequence is found
func parser(_ parser: XMLParser, foundCharacters string: String) {
if !string.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
if category[currentElement] == nil {
category.updateValue(string, forKey: currentElement)
}
}
}
// Called when a CDATA block is found
func parser(_ parser: XMLParser, foundCDATA CDATABlock: Data) {
guard String(data: CDATABlock, encoding: .utf8) != nil else {
print("CDATA contains non-textual data, ignored")
return
}
}
// Processing completed
func parserDidEndDocument(_ parser: XMLParser) {
for (_, offer) in offers.enumerated() {
print(offer)
}
}
}
final class CustomElement {
func createButton() -> UIButton {
let button = UIButton()
button.configuration = .filled()
button.configuration?.title = "Load"
button.configuration?.cornerStyle = .medium
button.configuration?.baseBackgroundColor = .gray
return button
}
}