swiftyxmlparserlogo

Swift 5.0 Carthage compatible Version License Platform

用 Swift 实现的简单 XML 解析器

这是什么?

这是一个受 SwiftyJSONSWXMLHash 启发的 XML 解析器。

Foundation 框架中的 NSXMLParser 是一种 “SAX” 解析器。它性能足够,但有点不方便。因此,我们实现了封装它的 “DOM” 解析器。

特性

要求

安装

Carthage

1. 创建 Cartfile

github "https://github.com/yahoojapan/SwiftyXMLParser"

2. 安装

> carthage update

CocoaPods

1. 创建 Podfile

platform :ios, '9.0'
use_frameworks!

pod "SwiftyXMLParser", :git => 'https://github.com/yahoojapan/SwiftyXMLParser.git'

2. 安装

> pod install

示例

import SwiftyXMLParser

let str = """
<ResultSet>
    <Result>
        <Hit index=\"1\">
            <Name>Item1</Name>
        </Hit>
        <Hit index=\"2\">
            <Name>Item2</Name>
        </Hit>
    </Result>
</ResultSet>
"""

// parse xml document
let xml = try! XML.parse(str)

// access xml element
let accessor = xml["ResultSet"]

// access XML Text

if let text = xml["ResultSet", "Result", "Hit", 0, "Name"].text {
    print(text)
}

if let text = xml.ResultSet.Result.Hit[0].Name.text {
    print(text)
}

// access XML Attribute
if let index = xml["ResultSet", "Result", "Hit", 0].attributes["index"] {
    print(index)
}

// enumerate child Elements in the parent Element
for hit in xml["ResultSet", "Result", "Hit"] {
    print(hit)
}

// check if the XML path is wrong
if case .failure(let error) =  xml["ResultSet", "Result", "TypoKey"] {
    print(error)
}

用法

1. 解析 XML

let str = """
<ResultSet>
    <Result>
        <Hit index=\"1\">
            <Name>Item1</Name>
        </Hit>
        <Hit index=\"2\">
            <Name>Item2</Name>
        </Hit>
    </Result>
</ResultSet>
"""

xml = try! XML.parse(str) // -> XML.Accessor
let str = """
<ResultSet>
    <Result>
        <Hit index=\"1\">
            <Name>Item1</Name>
        </Hit>
        <Hit index=\"2\">
            <Name>Item2</Name>
        </Hit>
    </Result>
</ResultSet>
"""

let string = String(decoding: data, as: UTF8.self)

xml = XML.parse(data) // -> XML.Accessor
let srt = "<xmlopening>@ß123\u{1c}</xmlopening>"

let xml = XML.parse(str.data(using: .utf8))

if case .failure(XMLError.interruptedParseError) = xml {
  print("invalid character")
}

更多信息,请参阅 https://developer.apple.com/documentation/foundation/xmlparser/errorcode

2. 访问子元素

let element = xml.ResultSet // -> XML.Accessor

3. 访问孙元素

let element = xml["ResultSet"]["Result"] // -> <Result><Hit index=\"1\"><Name>Item1</Name></Hit><Hit index=\"2\"><Name>Item2</Name></Hit></Result>
let path = ["ResultSet", "Result"]
let element = xml[path] // -> <Result><Hit index=\"1\"><Name>Item1</Name></Hit><Hit index=\"2\"><Name>Item2</Name></Hit></Result>
let element = xml["ResultSet", "Result"] // -> <Result><Hit index=\"1\"><Name>Item1</Name></Hit><Hit index=\"2\"><Name>Item2</Name></Hit></Result>
let element = xml.ResultSet.Result // -> <Result><Hit index=\"1\"><Name>Item1</Name></Hit><Hit index=\"2\"><Name>Item2</Name></Hit></Result>

4. 访问特定的孙元素

let element = xml.ResultSet.Result.Hit[1] // -> <Hit index=\"2\"><Name>Item2</Name></Hit>

5. 访问元素中的属性

if let attributeValue = xml.ResultSet.Result.Hit[1].attributes?["index"] {
  print(attributeValue) // -> 2
}

6. 访问元素中的文本

if let text = xml.ResultSet.Result.Hit[1].Name.text {
    print(text) // -> Item2
} 
struct Entity {
  var name = ""
}
let entity = Entity()
entity.name ?= xml.ResultSet.Result.Hit[1].Name.text // assign if it has text
struct Entity {
  var name: Int = 0
}
let entity = Entity()
entity.name ?= xml.ResultSet.Result.Hit[1].Name.int // assign if it has Int

还有其他语法糖,bool、url 和 double。

struct Entity {
  var names = [String]()
}
let entity = Entity()
entity.names ?<< xml.ResultSet.Result.Hit[1].Name.text // assign if it has text

7. 访问 CDATA

let str = """
<Data name="DATE">
    <value><![CDATA[2018-07-08]]></value>
</Data>
"""

// parse xml document
let xml = try! XML.parse(str)
        
if let cdata = xml.Data.value.element?.CDATA, 
   let cdataStr = String(data: cdata, encoding: .utf8) {
   print(cdataStr) // -> "2018-07-08"
}

8. 计数子元素

let numberOfHits = xml.ResultSet.Result.Hit.all?.count 

9. 检查错误

print(xml.ResultSet.Result.TypoKey) // -> "TypoKey not found."

10. 作为 SequenceType 访问

for element in xml.ResultSet.Result.Hit {
  print(element.text)
}
xml.ResultSet.Result.Hit.map { $0.Name.text }

11. 生成 XML 文档

print(Converter(xml.ResultSet).makeDocument())

与 Alamofire 协同工作

SwiftyXMLParser 与 Alamofire 配合良好。您可以轻松解析响应。

import Alamofire
import SwiftyXMLParser

Alamofire.request(.GET, "https://itunes.apple.com/us/rss/topgrossingapplications/limit=10/xml")
         .responseData { response in
            if let data = response.data {
                let xml = XML.parse(data)
                print(xml.feed.entry[0].title.text) // outputs the top title of iTunes app raning.
            }
        }

此外,还有 Alamofire 的扩展可以与 SwiftyXMLParser 结合使用。

迁移指南

当前 master 分支 支持 Xcode 10。如果您想将此库与旧版本的 Swift 一起使用,请阅读发行说明并安装最后一个兼容版本。

许可证

本软件根据 MIT 许可证发布,请参阅 LICENSE 文件。