XMLProcessor

A simple XML parser that creates a JSON object graph in Swift.

Example

Parsing a string of XML into an object graph is simple:

let data = "<root><node>value</node></root>".data(using: .utf8)!

let processor = XMLProcessor()
if let object = processor.parse(data: data) {
  if let root = object["root"] as? Dictionary<String,Any> {
    // do something with root dictionary
  }
}

Processing

To deal with the differences between XML and JavaScript objects (JSON), some processing is done on the XML.

NOTE: Do not assume that the order of the keys in the object dictionaries will be the same as they occurred in the XML. No order is preserved during processing (as is the case with JSON parsing).

If the XML has multiple nodes with the same name, they are put into an array. For example, the following XML:

<root>
	<metadata>Example</metadata>
	<entry>
		<title>First</title>
	</entry>
	<entry>
		<title>Second</title>
	</entry>
</root>		

Will generate:

{
	"root": {
		"metadata": "Example",
		"entry": [
			{
				"title": "First"
			},
			{
				"title": "Second"
			}
		]
	}
}

When evaluating the result, you can use Swift’s type coercion. Using the example above, root["entry"] as? Array<Any> will return a value.

A node’s attributes are stored in a sibling object with a “$attrs” key. The dollar sign was chosen because it’s an invalid XML node name, but is a valid JavaScript property name. This makes it easier to access with a path.

For example, this XML:

<root>
	<node first="1" second="2" third="3">value</node>
</root>

Produces:

{
	"root" : {
		"node" : "value",
		"node$attrs" : {
			"first" : "1",
			"second" : "2",
			"third" : "3"
		}
	}
}

Note that these two processing steps can be combined in some cases. An example is multiple link nodes with nothing but attributes:

<root>
	<link first="abc" second="def" />
	<link first="hij" second="klm" />
</root>

Will only produce attribute dictionaries:

{
	"root" : {
		"link$attrs" : [
			{
				"first" : "abc",
				"second" : "def"
			},
			{
				"first" : "hij",
				"second" : "klm"
			}
		]
	}
}

Note also that text that’s not a part of a node will be ignored. For example:

<root>
	text
	<node>value</node>
</root>

Results:

{
	"root" : {
		"node" : "value"
	}
}

This functionality should be enough to parse XML generated from hierarchical data, such as an RSS feed generated by a WordPress database of posts.

Sample

A sample app in SwiftUI shows how XMLProcessor can be used to read an Atom RSS feed and use it to create a Text view generated with Markdown from the feed.

GitHub

View Github