Profile
Back to NewsBack
GitHub Trending 5 min
Reader Mode
tadija/AEXML: Swift minion for simple and lightweight XML parsing

tadija/AEXML: Swift minion for simple and lightweight XML parsing

10 hours ago

Swift 5.9</a> Platforms iOS | watchOS | tvOS | macOS</a> CocoaPods</a> Carthage</a> Swift Package Manager</a> License MIT</a>

AEXML

Swift minion for simple and lightweight XML parsing

I made this for personal use, but feel free to use it or contribute.
For more examples check out Sources and Tests.

Index

- Read XML - Write XML

Intro

This is not a robust full featured XML parser, but rather simple, lightweight and easy to use utility for casual XML handling.

Features

  • Read XML data
  • Write XML string
  • Covered with unit tests
  • Covered with inline docs

Usage

Read XML

Let's say this is some XML string you picked up somewhere and made a variable data: Data from that.
<?xml version="1.0" encoding="utf-8"?>
<animals>
    <cats>
        <cat breed="Siberian" color="lightgray">Tinna</cat>
        <cat breed="Domestic" color="darkgray">Rose</cat>
        <cat breed="Domestic" color="yellow">Caesar</cat>
        <cat></cat>
    </cats>
    <dogs>
        <dog breed="Bull Terrier" color="white">Villy</dog>
        <dog breed="Bull Terrier" color="white">Spot</dog>
        <dog breed="Golden Retriever" color="yellow">Betty</dog>
        <dog breed="Miniature Schnauzer" color="black">Kika</dog>
    </dogs>
</animals>

This is how you can use AEXML for working with this data: (for even more examples, look at the unit tests code included in project)

guard let
    let xmlPath = Bundle.main.path(forResource: "example", ofType: "xml"),
    let data = try? Data(contentsOf: URL(fileURLWithPath: xmlPath))
else { return }

do { let xmlDoc = try AEXMLDocument(xml: data, options: options) // prints the same XML structure as original print(xmlDoc.xml) // prints cats, dogs for child in xmlDoc.root.children { print(child.name) } // prints Optional("Tinna") (first element) print(xmlDoc.root["cats"]["cat"].value) // prints Tinna (first element) print(xmlDoc.root["cats"]["cat"].string) // prints Optional("Kika") (last element) print(xmlDoc.root["dogs"]["dog"].last?.value) // prints Betty (3rd element) print(xmlDoc.root["dogs"].children[2].string) // prints Tinna, Rose, Caesar if let cats = xmlDoc.root["cats"]["cat"].all { for cat in cats { if let name = cat.value { print(name) } } } // prints Villy, Spot for dog in xmlDoc.root["dogs"]["dog"].all! { if let color = dog.attributes["color"] { if color == "white" { print(dog.string) } } } // prints Tinna if let cats = xmlDoc.root["cats"]["cat"].all(withValue: "Tinna") { for cat in cats { print(cat.string) } } // prints Caesar if let cats = xmlDoc.root["cats"]["cat"].all(withAttributes: ["breed" : "Domestic", "color" : "yellow"]) { for cat in cats { print(cat.string) } } // prints 4 print(xmlDoc.root["cats"]["cat"].count) // prints Siberian print(xmlDoc.root["cats"]["cat"].attributes["breed"]!) // prints <cat breed="Siberian" color="lightgray">Tinna</cat> print(xmlDoc.root["cats"]["cat"].xmlCompact) // prints Optional(AEXML.AEXMLError.elementNotFound) print(xmlDoc["NotExistingElement"].error) } catch { print("\(error)") }

Write XML

Let's say this is some SOAP XML request you need to generate. Well, you could just build ordinary string for that?
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soap:Header>
    <m:Trans xmlns:m="http://www.w3schools.com/transaction/" soap:mustUnderstand="1">234</m:Trans>
  </soap:Header>
  <soap:Body>
    <m:GetStockPrice>
      <m:StockName>AAPL</m:StockName>
    </m:GetStockPrice>
  </soap:Body>
</soap:Envelope>

Yes, but, you can also do it in a more structured and elegant way with AEXML:

// create XML Document
let soapRequest = AEXMLDocument()
let attributes = ["xmlns:xsi" : "http://www.w3.org/2001/XMLSchema-instance", "xmlns:xsd" : "http://www.w3.org/2001/XMLSchema"]
let envelope = soapRequest.addChild(name: "soap:Envelope", attributes: attributes)
let header = envelope.addChild(name: "soap:Header")
let body = envelope.addChild(name: "soap:Body")
header.addChild(name: "m:Trans", value: "234", attributes: ["xmlns:m" : "http://www.w3schools.com/transaction/", "soap:mustUnderstand" : "1"])
let getStockPrice = body.addChild(name: "m:GetStockPrice")
getStockPrice.addChild(name: "m:StockName", value: "AAPL")

// prints the same XML structure as original print(soapRequest.xml)

Or perhaps like this, using result builders (see #186):

@AEXMLDocumentBuilder
private func buildSoapEnvelope(
    for action: String,
    in serviceType: String,
    with parameters: [String: String] = [:]
) -> AEXMLDocument {
    AEXMLElement("s:Envelope", attributes: [
        "xmlns:s": "http://schemas.xmlsoap.org/soap/envelope/",
        "s:encodingStyle": "http://schemas.xmlsoap.org/soap/encoding/"
    ]) {
        AEXMLElement("s:Body") {
            AEXMLElement("s:\(action)", attributes: [
                "xmlns:u": serviceType
            ]) {
                for parameter in parameters {
                    AEXMLElement(
                        name: parameter.key,
                        value: parameter.value
                    )
                }
            }
        }
    }
}

Installation

.package(url: "https://github.com/tadija/AEXML.git", from: "4.7.2")
github "tadija/AEXML"
pod 'AEXML'

License

AEXML is released under the MIT license. See LICENSE for details.
Chat with me