The most swifty way to deal with XML data in swift 5.

Overview

Carthage compatible

SwiftyXML

Platform

SwiftyXML use most swifty way to deal with XML data.

Features

  • Infinity subscript
  • dynamicMemberLookup Support (use $ started string to subscript attribute)
  • Optional | Non-optional value access
  • Directly access Enum type value (enums extends from RawRepresentable)
  • Directly for loop in XML children nodes
  • Accurate error throwing
  • XML construct, formatting
  • Single source file

Sample XML:

<catalog>
	<product description="Cardigan Sweater" product_image="cardigan.jpg" >
		<catalog_item gender="Men's" >
			<item_number>QWZ5671</item_number>
			<price>39.95</price>
			<size description="Medium" >
				<color_swatch image="red_cardigan.jpg" >Red</color_swatch>
				<color_swatch image="burgundy_cardigan.jpg" >Burgundy</color_swatch>
			</size>
			<size description="Large" >
				<color_swatch image="red_cardigan.jpg" >Red</color_swatch>
				<color_swatch image="burgundy_cardigan.jpg" >Burgundy</color_swatch>
			</size>
		</catalog_item>
		<catalog_item gender="Women's" >
			<item_number>RRX9856</item_number>
			<price>42.50</price>
			<size description="Small" >
				<color_swatch image="red_cardigan.jpg" >Red</color_swatch>
				<color_swatch image="navy_cardigan.jpg" >Navy</color_swatch>
				<color_swatch image="burgundy_cardigan.jpg" >Burgundy</color_swatch>
			</size>
		</catalog_item>
	</product>
</catalog>

With SwiftyXML all you have to do is:

let xml = XML(string: xmlContent)
let color0 = xml.product.catalog_item.size.color_swatch.1.string //"Burgundy"
// notice that, we use "$" prefix for subscript attribute
let description0 = xml.product.catalog_item.size.1.$description.string //"Large"

This is same as below, SwiftyXML will auto pick the first element as default:

let xml = XML(data: xmlFileData)
let color = xml.product.0.catalog_item.0.size.0.color_swatch.1.string //return "Burgundy"

What about if you input some wrong keys:

let xml = XML(data: xmlFileData)
// print the error
if let color1 = xml.product.catalog_item.wrong_size.wrong_color.1.xml {
    // do stuff ~
    print(color1)
} else {
    print(xml.product.catalog_item.wrong_size.wrong_color.1.error) //.product.0.catalog_item.0: no such children named: "wrong_size"
}

Requirements

  • iOS 8.0+ | macOS 10.10+ | tvOS 9.0+ | watchOS 2.0+
  • Xcode 8

Installation

CocoaPods

You can use CocoaPods to install SwiftyXML by adding it to your Podfile:

platform :ios, '8.0'
use_frameworks!

target 'MyApp' do
    pod 'SwiftyXML', '~> 3.0.0'
end

Carthage

Create a Cartfile that lists the framework and run carthage update. Follow the instructions to add $(SRCROOT)/Carthage/Build/iOS/SwiftyXML.framework to an iOS project.

github "chenyunguiMilook/SwiftyXML" ~> 3.0.0

Manually

  1. Download and drop XML.swift into your project.
  2. Congratulations!

Swift Package Manager

You can use The Swift Package Manager to install SwiftyXML by adding the proper description to your Package.swift file:

.package(url: "https://github.com/chenyunguiMilook/SwiftyXML.git", from: "3.0.2")

Usage

Initialization

import SwiftyXML
let xml = XML(data: xmlFileData)

Access XML and print out the error

if let color1 = xml.product.catalog_item.wrong_size.wrong_color.1.xml {
    // do stuff ~
    print(color1)
} else {
    print(xml.product.catalog_item.wrong_size.wrong_color.1.error)
}

Catch the error

// catch the error
do {
    let color = try xml.product.catalog_item.wrong_size.wrong_color.1.getXML()
    print(color)
} catch {
    print(error)
}

Access XML List

// handle xml list
for catalog in xml.product.catalog_item {
    for size in catalog.size {
        print(size.$description.stringValue)
    }
}

Read Enums

// read enum value, Notice: enum need implements RawRepresentable
public enum Color : String {
    case Red, Navy, Burgundy
}

if let c: Color = xml.product.catalog_item.size.color_swatch.enum() {
    print(c)
}

Construct XML

let store = XML(name: "store")
    .addAttribute(name: "description", value: "Ball Store")
    .addChildren([
        // attributes can be added in the initializer
        XML(name: "product", attributes: [
            "name": "football",
            "weight": 0.453
        ])
    ])

// attributes can be added to an existing object
let product2 = XML(name: "product")
product2.addAttribute(name: "name", value: "basketball")
product2.addAttribute(name: "weight", value: 0.654)

// children can be added to an existing object
store.addChild(product2)

print(store.toXMLString())
// store xml output
<store description="Ball Store" >
	<product name="football" weight="0.453" />
	<product name="basketball" weight="0.654" />
</store>
Comments
  • Read value by attributes?

    Read value by attributes?

    Hey,

    First of all, I must say this is a great control.

    But I would like to ask is there anyway to access the value by using attributes? Like in your example, let color0 = xml["product"]["catalog_item"]["size"]["color_swatch"][1].string //"Burgundy"

    Can I access the value "Burgundy" without using the number (1 in this case), but with the file name "burgundy_cardigan.jpg"? Thanks!

    opened by babyghost-ys 4
  • How to access children with hyphen in its name

    How to access children with hyphen in its name

    My Xml has a lot of values separated by hyphen like "display-name" or "item-id", but I can't figure ii out on how to access to its values.

    If I use the readme instructions like this:

    let name = xml.channel.0.display-name.string Binary operator '-' cannot be applied to operands of type 'XMLSubscriptResult' and 'String'

    Is there any way to achieve this ?

    opened by garanda21 3
  • Characters are removed before first non-ascii character

    Characters are removed before first non-ascii character

    In the attached xml response (Google geocode response.pdf, this is the response from url https://maps.googleapis.com/maps/api/geocode/xml?&latlng=63,10), the value of xml["result"][0]["address_component"][3]["short_name"].stringValue is "ør-Trøndelag" (xml is the value of XML(data: data) from the response (using Alamofire)). The correct response should be "Sør-Trøndelag". Thus, the first S is missing. I have also seen other examples where multiple (all) characters before the first non-ascii character is removed in the stringValue.

    opened by toreboes 3
  • Manual Installation

    Manual Installation

    CocoaPods and Carthage are awesome tools and make our life really easier, but there are some devs who still don't know how to use them.

    It would be cool to add the Manual installation guide in your README.md. You can take a look at my iOS Readme Template to see how you can do it.

    opened by lfarah 3
  • Amended public XML element properties

    Amended public XML element properties

    The public properties of the XML class (name, attributes, value and children) can mask child XML elements with the same element name when attempting to use DynamicMemberLookup to traverse the XML chain. As the definition of XML element naming at https://www.w3schools.com indicates that an element cannot be given a name starting with xml, I have renamed the 4 public properties listed here with the prefix xml... (creating public properties named xmlName, xmlAttributes, xmlValue and xmlChildren).

    This is to correct a real-world situation where full traversal of the xml tree of the GPX file format (https://en.wikipedia.org/wiki/GPS_Exchange_Format) using DynamicMemberLookup is impossible because of child elements named as "name" in the wptType, rteType, trkType and personType elements.

    opened by andyj-at-aspin 2
  • For make true XML need in the loop get all value and fix then.

    For make true XML need in the loop get all value and fix then.

    For make true XML need in the loop get all value and fix then. Example: let newXMLHead: XML = XML(name: "clients") let usersXML: [XML] = memoryXML!["#clients"]["client"].xmlList! for value in usersXML { let newXML: XML = XML(name: "clients") for (key, subValue) in value.attributes { newXML.addAttribute(name: key, value: subValue.percentEscapeString()) } newXMLHead.addChild(newXML) }

    Where extension String { func percentEscapeString() -> String { return self .replacingOccurrences(of: "&", with: "&amp;") .replacingOccurrences(of: """, with: "&quot;") .replacingOccurrences(of: "'", with: "&#39;") .replacingOccurrences(of: ">", with: "&gt;") .replacingOccurrences(of: "<", with: "&lt;") } }

    Originally posted by @kiri11ko in https://github.com/chenyunguiMilook/SwiftyXML/issues/8#issuecomment-511768551

    opened by kiri11ko 2
  • XML class public properties mask child XML elements with the same name

    XML class public properties mask child XML elements with the same name

    The public properties of the XML class (name, attributes, value and children) can mask child XML elements with the same element name when attempting to use DynamicMemberLookup to traverse the XML chain.

    A real-world occurrence of this issue is that full traversal of the xml tree of the GPX file format (https://en.wikipedia.org/wiki/GPS_Exchange_Format) using DynamicMemberLookup is impossible because of child elements named as "name" in the wptType, rteType, trkType and personType elements.

    I have created a pull request for a suggested fix that renames the public properties of the XML class by adding xml... as a prefix to the property name.

    opened by andyj-at-aspin 1
  • Chaining

    Chaining

    Allow addAttribute and addChild calls to be chained to XML objects. This allows XML objects to be created without needing to define any variables.

    Example:

    You can generate the XML

    <rss version="2.0">
        <channel>
            <title>Example Title</title>
            <description>Example Description</description>
            <item>
                <title>Episode 0</title>
            </item>
        </channel>
    </rss>
    

    in a single go:

    XML(name: "rss")
        .addAttribute(name: "version", value: "2.0")
        .addChildren([
            XML(name: "channel").addChildren([
                XML(name: "title", value: "Example Title"),
                XML(name: "description", value: "Example Description"),
                XML(name: "item").addChildren([
                    XML(name: "title", value: "Episode 0")
                ])
            ])
        ])
    
    opened by skjiisa 1
  • How do you delete a child?

    How do you delete a child?

    In your example xml, how would you delete a complete tag: for example everything between <catalog_item> and </catalog_item> including the starting and ending tags? I want to replace a complete item with an updated version.

    Many thanks

    Robert

    opened by revcom 2
  • Using your sample code, how would you modify an existing value? Like changing the price from 42.50 to 50

    Using your sample code, how would you modify an existing value? Like changing the price from 42.50 to 50

    <catalog>
    	<product description="Cardigan Sweater" product_image="cardigan.jpg" >
    		<catalog_item gender="Men's" >
    			<item_number>QWZ5671</item_number>
    			<price>39.95</price>
    			<size description="Medium" >
    				<color_swatch image="red_cardigan.jpg" >Red</color_swatch>
    				<color_swatch image="burgundy_cardigan.jpg" >Burgundy</color_swatch>
    			</size>
    			<size description="Large" >
    				<color_swatch image="red_cardigan.jpg" >Red</color_swatch>
    				<color_swatch image="burgundy_cardigan.jpg" >Burgundy</color_swatch>
    			</size>
    		</catalog_item>
    		<catalog_item gender="Women's" >
    			<item_number>RRX9856</item_number>
    			<price>42.50</price>
    			<size description="Small" >
    				<color_swatch image="red_cardigan.jpg" >Red</color_swatch>
    				<color_swatch image="navy_cardigan.jpg" >Navy</color_swatch>
    				<color_swatch image="burgundy_cardigan.jpg" >Burgundy</color_swatch>
    			</size>
    		</catalog_item>
    	</product>
    </catalog>
    
    opened by corey-williams 1
  • Construct XML not work correctly

    Construct XML not work correctly

    let newXML = LocalDataModelXML.newTasksXML!
                newXML.addChild(XML(string: tasks))
    

    If construct XML from existing XML new tag added new tag and not parse new tag. After parse final xml view one first tag

    <Doc StatusDoc="new" >
    	<clientsTasks>
    		<clientTask description="Dsdsd" persone="Гребенкина Анастасия" date="1562290361.0" id_client="000006383" name="Dodd’s" />
    	</clientsTasks>
    	<clientsTasks>
    		<clientTask description="Dsdsd" date="1562463999.0" id_client="000006383" persone="Гребенкина Анастасия" name="dsdsdds" />
    	</clientsTasks>
    	<clientsTasks>
    		<clientTask name="dsdsdds" description="Dsdsd" date="1562463999.0" id_client="000006383" persone="Гребенкина Анастасия" />
    	</clientsTasks>
    	<clientsTasks>
    		<clientTask date="1562463999.0" persone="Гребенкина Анастасия" description="Dsdsd" id_client="000006383" name="dsdsdds" />
    	</clientsTasks>
    	<clientsTasks>
    		<clientTask id_client="000006383" name="dsdsdds" date="1562463999.0" persone="Гребенкина Анастасия" description="Dsdsd" />
    	</clientsTasks>
    	<clientsTasks>
    		<clientTask persone="Гребенкина Анастасия" date="1562207178.0" description="dsdsd" id_client="000006383" name="dsdsd" />
    	</clientsTasks>
    	<clientsTasks>
    		<clientTask date="1562121435.0" description="Hello" persone="Казакова Анастасия" name="test update view" id_client="000006383" />
    	</clientsTasks>
    </Doc>
    
    opened by kiri11ko 1
Owner
Kevin
to be a swifty iOS developer ~
Kevin
A simple way to map XML to Objects written in Swift

XMLMapper XMLMapper is a framework written in Swift that makes it easy for you to convert your model objects (classes and structs) to and from XML. Ex

Giorgos Charitakis 109 Jan 6, 2023
Swift minion for simple and lightweight XML parsing

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

Marko Tadić 975 Dec 26, 2022
CheatyXML is a Swift framework designed to manage XML easily

CheatyXML CheatyXML is a Swift framework designed to manage XML easily. Requirements iOS 8.0 or later tvOS 9.0 or later Installation Cocoapods If you'

Louis Bodart 24 Mar 31, 2022
Simple XML parsing in Swift

SWXMLHash SWXMLHash is a relatively simple way to parse XML in Swift. If you're familiar with NSXMLParser, this library is a simple wrapper around it.

David Mohundro 1.3k Jan 3, 2023
Easy XML parsing using Codable protocols in Swift

XMLCoder Encoder & Decoder for XML using Swift's Codable protocols. This package is a fork of the original ShawnMoore/XMLParsing with more features an

Max Desiatov 657 Dec 30, 2022
A fast & lightweight XML & HTML parser in Swift with XPath & CSS support

Fuzi (斧子) A fast & lightweight XML/HTML parser in Swift that makes your life easier. [Documentation] Fuzi is based on a Swift port of Mattt Thompson's

Ce Zheng 994 Jan 2, 2023
Ji (戟) is an XML/HTML parser for Swift

Ji 戟 Ji (戟) is a Swift wrapper on libxml2 for parsing XML/HTML. Features Build XML/HTML Tree and Navigate. XPath Query Supported. Comprehensive Unit T

HongHao Zhang 824 Dec 15, 2022
Kanna(鉋) is an XML/HTML parser for Swift.

Kanna(鉋) Kanna(鉋) is an XML/HTML parser for cross-platform(macOS, iOS, tvOS, watchOS and Linux!). It was inspired by Nokogiri(鋸). ℹ️ Documentation Fea

Atsushi Kiwaki 2.3k Dec 31, 2022
Simple XML Parser implemented in Swift

Simple XML Parser implemented in Swift What's this? This is a XML parser inspired by SwiftyJSON and SWXMLHash. NSXMLParser in Foundation framework is

Yahoo! JAPAN 531 Jan 1, 2023
Generate styled SwiftUI Text from strings with XML tags.

XMLText is a mini library that can generate SwiftUI Text from a given XML string with tags. It uses AttributedString to compose the final text output.

null 15 Dec 7, 2022
Fetch a XML feed and parse it into objects

AlamofireXmlToObjects ?? This is now a subspec of EVReflection and the code is maintained there. ?? You can install it as a subspec like this: use_fra

Edwin Vermeer 65 Dec 29, 2020
📄 A Swift DSL for writing type-safe HTML/CSS in SwiftUI way

?? swift-web-page (swep) Swep is a Swift DSL for writing type-safe HTML/CSS in SwiftUI way. Table of Contents Motivation Examples Safety Design FAQ In

Abdullah Aljahdali 14 Dec 31, 2022
Mathias Köhnke 1.1k Dec 16, 2022
SwiftSoup: Pure Swift HTML Parser, with best of DOM, CSS, and jquery (Supports Linux, iOS, Mac, tvOS, watchOS)

SwiftSoup is a pure Swift library, cross-platform (macOS, iOS, tvOS, watchOS and Linux!), for working with real-world HTML. It provides a very conveni

Nabil Chatbi 3.7k Jan 6, 2023
Swift package to convert a HTML table into an array of dictionaries.

Swift package to convert a HTML table into an array of dictionaries.

null 1 Jun 18, 2022
Mongrel is a Swift and HTML hybrid with a bit of support for CSS and Javascript.

Mongrel is a Swift and HTML hybrid with a bit of support for CSS and Javascript. Using a declaritive style of programming, Mongrel makes writing HTML feel natural and easy. Mongrel also uses a SwiftUI like body structure allowing structs to be completely dedicated as an HTML page or element.

Nicholas Bellucci 12 Sep 22, 2022
A sensible way to deal with XML & HTML for iOS & macOS

Ono (斧) Foundation lacks a convenient, cross-platform way to work with HTML and XML. NSXMLParser is an event-driven, SAX-style API that can be cumbers

Mattt 2.6k Dec 14, 2022
PySwiftyRegex - Easily deal with Regex in Swift in a Pythonic way

PySwiftyRegex Easily deal with Regex in Swift in a Pythonic way.

Ce Zheng 232 Oct 12, 2022
Easily deal with Regex in Swift in a Pythonic way

PySwiftyRegex Easily deal with Regex in Swift in a Pythonic way. 简体中文 日本語 한국어 This is Easy import PySwiftyRegex if let m = re.search("[Tt]his is (.*?

Ce Zheng 232 Oct 12, 2022
The better way to deal with JSON in Objective-C (inspired by SwiftyJSON)

NSTEasyJSON Inpired by SwiftyJSON. NSTEasyJSON makes it easy to deal with JSON data in Objective-C. Why is the typical JSON handling in Objective-C NO

Timur Bernikovich 11 Apr 2, 2020