Skip to content
/ Fuzi Public

A fast & lightweight XML & HTML parser in Swift with XPath & CSS support

License

Notifications You must be signed in to change notification settings

cezheng/Fuzi

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Fuzi (斧子)

Cocoapods Compatible License Platform Twitter

A fast & lightweight XML/HTML parser in Swift that makes your life easier.

Fuzi is based on a Swift port of Mattt Thompson's Ono(斧), with moderate class & interface redesign following standard Swift conventions, along with several bug fixes.

Fuzi(斧子) means "axe", in homage to Ono(斧), which in turn is inspired by Nokogiri (鋸), which means "saw".

简体中文 日本語

A Quick Look

let xml = "..."
do {
  let document = try XMLDocument(string: xml)
  
  if let root = document.root {
    // Accessing all child nodes of root element
    for element in root.children {
      print("\(element.tag): \(element.attributes)")
    }
    
    // Getting child element by tag & accessing attributes
    if let length = root.firstChild(tag:"Length", inNamespace: "dc") {
      print(length["unit"])     // `unit` attribute
      print(length.attributes)  // all attributes
    }
  }
  
  // XPath & CSS queries
  for element in document.xpath("") {
    print("\(element.tag): \(element.attributes)")
  }
  
  if let firstLink = document.firstChild(css: "a, link") {
    print(firstLink["href"])
  }
} catch let error {
  print(error)
}

Features

Inherited from Ono

  • Extremely performant document parsing and traversal, powered by libxml2
  • Support for both XPath and CSS queries
  • Automatic conversion of date and number values
  • Correct, common-sense handling of XML namespaces for elements and attributes
  • Ability to load HTML and XML documents from either String or NSData or [CChar]
  • Comprehensive test suite
  • Full documentation

Improved in Fuzi

  • Simple, modern API following standard Swift conventions, no more return types like AnyObject! that cause unnecessary type casts
  • Customizable date and number formatters
  • Some bugs fixes
  • Support for more CSS selectors (yet to come)
  • More convinience methods for HTML Documents (yet to come)

Requirements

  • iOS 8.0+ / Mac OS X 10.9+
  • Xcode 7.0

Installation

CocoaPods (Not ready yet! Use carthage)

You can use Cocoapods to install Fuzi by adding it to your to your Podfile:

platform :ios, '8.0'
use_frameworks!

target 'MyApp' do
	pod 'Fuzi', '~> 0.1.0'
end

Then, run the following command:

$ pod install

Carthage

Adding the following line to your Cartfile or Cartfile.private:

github "cezheng/Fuzi"

Then, run the following command:

$ carthage update

##Usage ###XML

import Fuzi

let xml = "..."
do {
  // if encoding is omitted, it defaults to NSUTF8StringEncoding
  let doc = try XMLDocument(string: html, encoding: NSUTF8StringEncoding)
  if let root = document.root {
    print(root.tag)
    
    // define a prefix for a namespace
    document.definePrefix("atom", defaultNamespace: "http://www.w3.org/2005/Atom")
    
    // get first child element with given tag in namespace(optional)
    print(root.firstChild(tag: "title", inNamespace: "atom")
    
    // iterate through all children
    for element in root.children {
      print("\(index) \(element.tag): \(element.attributes)")
    }
  }
  // you can also use CSS selector against XMLDocument when you feels it makes sense
} catch let error {
}

###HTML HTMLDocument is a subclass of XMLDocument.

import Fuzi

let html = "<html>...</html>"
do {
  // if encoding is omitted, it defaults to NSUTF8StringEncoding
  let doc = try HTMLDocument(string: html, encoding: NSUTF8StringEncoding)
  
  // CSS queries
  if let elementById = doc.css("#id") {
    print(elementById.stringValue)
  }
  for link in doc.css("a, link") {
      print(link.dump())
      print(link["href"]
  }
  
  // XPath queries
  if let title = doc.firstChild(xpath: "//head/title") {
    print(title.stringValue)
  }
  for paragraph in doc.xpath(".//body/descendant::p") {
    print(meta["class"])
  }
} catch let error {
}

##Migrating From Ono? Looking at example program is the swiftest way to know the difference. The following 2 examples do exactly the same thing.

Ono Example

Fuzi Example

License

Fuzi is released under the MIT license. See LICENSE for details.