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

Overview

Fuzi (斧子)

Build Status CocoaPods Compatible License Carthage Compatible Platform Twitter

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 Ono(斧), using most of its low level implementaions 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 = "..."
// or
// let xmlData = <some NSData or Data>
do {
  let document = try XMLDocument(string: xml)
  // or
  // let document = try XMLDocument(data: xmlData)
  
  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("//element") {
    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
  • More convenience methods for HTML Documents
  • Access XML nodes of all types (Including text, comment, etc.)
  • Support for more CSS selectors (yet to come)

Requirements

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

Use version 0.4.0 for Swift 2.3.

Installation

There are 4 ways you can install Fuzi to your project.

Using CocoaPods

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', '~> 1.0.0'
end

Then, run the following command:

$ pod install

Using Swift Package Manager

The Swift Package Manager is now built-in with Xcode 11 (currently in beta). You can easily add Fuzi as a dependency by choosing File > Swift Packages > Add Package Dependency... or in the Swift Packages tab of your project file and clicking on +. Simply use https://github.com/cezheng/Fuzi as repository and Xcode should automatically resolve the current version.

Manually

  1. Add all *.swift files in Fuzi directory into your project.
  2. In your Xcode project Build Settings:
    1. Find Search Paths, add $(SDKROOT)/usr/include/libxml2 to Header Search Paths.
    2. Find Linking, add -lxml2 to Other Linker Flags.

Using Carthage

Create a Cartfile or Cartfile.private in the root directory of your project, and add the following line:

github "cezheng/Fuzi" ~> 1.0.0

Run the following command:

$ carthage update

Then do the followings in Xcode:

  1. Drag the Fuzi.framework built by Carthage into your target's General -> Embedded Binaries.
  2. In Build Settings, find Search Paths, add $(SDKROOT)/usr/include/libxml2 to Header Search Paths.

Usage

XML

import Fuzi

let xml = "..."
do {
  // if encoding is omitted, it defaults to NSUTF8StringEncoding
  let document = try XMLDocument(string: html, encoding: String.Encoding.utf8)
  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 as XMLError {
  switch error {
  case .noError: print("wth this should not appear")
  case .parserFailure, .invalidData: print(error)
  case .libXMLError(let code, let message):
    print("libxml error code: \(code), message: \(message)")
  }
}

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: String.Encoding.utf8)
  
  // CSS queries
  if let elementById = doc.firstChild(css: "#id") {
    print(elementById.stringValue)
  }
  for link in doc.css("a, link") {
      print(link.rawXML)
      print(link["href"])
  }
  
  // XPath queries
  if let firstAnchor = doc.firstChild(xpath: "//body/a") {
    print(firstAnchor["href"])
  }
  for script in doc.xpath("//head/script") {
    print(script["src"])
  }
  
  // Evaluate XPath functions
  if let result = doc.eval(xpath: "count(/*/a)") {
    print("anchor count : \(result.doubleValue)")
  }
  
  // Convenient HTML methods
  print(doc.title) // gets <title>'s innerHTML in <head>
  print(doc.head)  // gets <head> element
  print(doc.body)  // gets <body> element
  
} catch let error {
  print(error)
}

I don't care about error handling

import Fuzi

let xml = "..."

// Don't show me the errors, just don't crash
if let doc1 = try? XMLDocument(string: xml) {
  //...
}

let html = "<html>...</html>"

// I'm sure this won't crash
let doc2 = try! HTMLDocument(string: html)
//...

I want to access Text Nodes

Not only text nodes, you can specify what types of nodes you would like to access.

let document = ...
// Get all child nodes that are Element nodes, Text nodes, or Comment nodes
document.root?.childNodes(ofTypes: [.Element, .Text, .Comment])

Migrating From Ono?

Looking at example programs is the swiftest way to know the difference. The following 2 examples do exactly the same thing.

Ono Example

Fuzi Example

Accessing children

Ono

[doc firstChildWithTag:tag inNamespace:namespace];
[doc firstChildWithXPath:xpath];
[doc firstChildWithXPath:css];
for (ONOXMLElement *element in parent.children) {
  //...
}
[doc childrenWithTag:tag inNamespace:namespace];

Fuzi

doc.firstChild(tag: tag, inNamespace: namespace)
doc.firstChild(xpath: xpath)
doc.firstChild(css: css)
for element in parent.children {
  //...
}
doc.children(tag: tag, inNamespace:namespace)

Iterate through query results

Ono

Conforms to NSFastEnumeration.

// simply iterating through the results
// mark `__unused` to unused params `idx` and `stop`
[doc enumerateElementsWithXPath:xpath usingBlock:^(ONOXMLElement *element, __unused NSUInteger idx, __unused BOOL *stop) {
  NSLog(@"%@", element);
}];

// stop the iteration at second element
[doc enumerateElementsWithXPath:XPath usingBlock:^(ONOXMLElement *element, NSUInteger idx, BOOL *stop) {
  *stop = (idx == 1);
}];

// getting element by index 
ONOXMLDocument *nthElement = [(NSEnumerator*)[doc CSS:css] allObjects][n];

// total element count
NSUInteger count = [(NSEnumerator*)[document XPath:xpath] allObjects].count;

Fuzi

Conforms to Swift's SequenceType and Indexable.

// simply iterating through the results
// no need to write the unused `idx` or `stop` params
for element in doc.xpath(xpath) {
  print(element)
}

// stop the iteration at second element
for (index, element) in doc.xpath(xpath).enumerate() {
  if idx == 1 {
    break
  }
}

// getting element by index 
if let nthElement = doc.css(css)[n] {
  //...
}

// total element count
let count = doc.xpath(xpath).count

Evaluating XPath Functions

Ono

ONOXPathFunctionResult *result = [doc functionResultByEvaluatingXPath:xpath];
result.boolValue;    //BOOL
result.numericValue; //double
result.stringValue;  //NSString

Fuzi

if let result = doc.eval(xpath: xpath) {
  result.boolValue   //Bool
  result.doubleValue //Double
  result.stringValue //String
}

License

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

Comments
  • Can I import this into my Objective-C project?

    Can I import this into my Objective-C project?

    Thanks for the great library! I am using Ono and AFOnoResponseSerializer (https://github.com/AFNetworking/AFOnoResponseSerializer) but I found it doesn't work well for some CSS selectors even though they are not that complex. For example, even "h1.title" or ".highlighted .itemImg .img" do not seem to work. Does Fuzi work for these CSS selectors? If so, is there a way to import Fuji in my Objective-C project and work with AFOnoResponseSerializer? Thanks!

    question 
    opened by objcchobo 16
  • Framework issues

    Framework issues

    Hi, I added framework to my project manually but had some issues:

    1. I had to add libxml2.tbd to framework

    2. It had only macOS framework. There is not one for iOS, etc. Every os should have separate framework

    3. It's not updated for Xcode 8.1 (recommended settings)

    question 
    opened by amosavian 14
  • Added property `createdWithError`

    Added property `createdWithError`

    The value is true if NodeSet was generated as a result of badly formed or unsupported XPath query. libxml2 in that case will return nil instead of a pointer. This bool property will provide a way how to distinguish to cases

    • NodeSet is empty because there are no queried elements
    • NodeSet is empty because of XPath syntax error
    opened by Parabak 13
  • Build fails with xcode 9.3 (Beta)

    Build fails with xcode 9.3 (Beta)

    Description:

    Building Fuzi with xcode 9.3 fails with error Redefinition of module 'libxml2' [ I think the issue is because of the file module.modulemap. The error should go way by renaming it to something else like Fuzi_module.modulemap.]

    • Expected behaviour: Successful Build without errors.

    • Actual behaviour: Build Failure.

    Environment

    • Package Manager:

      • [ ] Carthage, version:
      • [X] CocoaPods, version:1.4
      • [ ] Manually
    • Fuzi version: Latest (2.0.1)

    • Xcode version: 9.3

    How to reproduce:

    Just include Fuzi to a new project using cocoapods and try building with xcode 9.3 Sample -> Fuzi_xcode93.zip

    opened by skathiresan 12
  • Root Element with attributes not working

    Root Element with attributes not working

    Hi Team,

              Its good using the FUZI.I am having a problem when my xml document's root element having attributes then its not working.
    

    When i removed the attributes in the root element. Its a charm.Giving the desired results.

    Please tell me the solution for doing this.

    question 
    opened by Ajayiosdeveloper 11
  • SPM support broken in Xcode 11 beta 4

    SPM support broken in Xcode 11 beta 4

    See #101

    /Applications/Xcode-beta.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.0.sdk/usr/include/libxml2/libxml/HTMLparser.h:15:10: 'libxml/xmlversion.h' file not found
    

    Reading up on PackageDescription, the .headerSearchPath has to be relative and not absolute, but it wasn't really enforced before Xcode 11 beta 4, which allowed us to use $(SDKROOT)/usr/include/libxml2 to point to the correct libxml2 headers. Another issue seems to be that I can't get Xcode to read the .unsafeFlags which would allow to at least build the Package (but not distribute it). I'll open an issue in SPM as well.

    opened by thebluepotato 10
  • Redefinition of module 'libxml2' error when using framework that uses Fuzi

    Redefinition of module 'libxml2' error when using framework that uses Fuzi

    I run into an issue using Fuzi via Carthage and two nested frameworks. Framework A has a Carthage dependency to Fuzi and is itself a carthage dependency of framework B. Building framework A works fine, however framework B ends up with 2 module maps and a redefinition of libxml2 (as Fuzi is contained in framework A and as a resolved dependency pulled into B). I don't have much experience using module maps, so this might very well be an error on my side or maybe an Carthage issue.

    opened by daehn 9
  • Remove wrapping libxml2 modulemap for Xcode 9.3

    Remove wrapping libxml2 modulemap for Xcode 9.3

    Fixes #77. Although the issue has been referenced by several PRs, this PR patches in another way, that does remove libxml2/module.modulemap from Fuzi.

    The modulemap is no longer needed because Xcode 9.3 has the modulemap in its SDK. (It's not included in Xcode 9.2 and before.) Accordingly this also removes SWIFT_INCLUDE_PATHS a.k.a. Import Paths as it no longer exists, and adds -lxml2 to the project as README says at the Install Manually section.

    opened by banjun 8
  • better performance in accessing children by tag name

    better performance in accessing children by tag name

    I hope fast Swift XML parser more fast! (comparable to Objective-C ones!)

    Finding children with func cXMLNode(tag:...) takes extra cost of Swift.String generation from C String, and thus higher level String comparison String.compare(...) consume much cpu time (profiled by Instruments).

    func cXMLNode takes libxml types. On the other hand, string literals can be converted UnsafePointer<CChar> (a.k.a. C String, UnsafePointer<xmlChar>, ...) via Swift.StaticString. Using StaticString, we can compare libxml tag name to the string on the libxml level xmlStrcasecmp without copying memory.

    with this PR, element.children(staticTag: "key") to get children in better performance 🏎

    I have tried overloading func children for both String and StaticString, but string literals seems to fall to String always. this cause func firstChild and func children to be duplicated into String version and StaticString versions.

    opened by banjun 8
  • rawXML self-closes empty tags

    rawXML self-closes empty tags

    rawXML self-closes empty tags, this can cause problems (with frames in my case)

    I've changed this function to look like that, and it seems to have fixed the problem

    import <libxml2/libxml/xmlsave.h> (in libxml2-fuzi.h)

    public private(set) lazy var rawXML: String = { let buffer = xmlBufferCreate() let ctxt = xmlSaveToBuffer(buffer, nil, Int32(XML_SAVE_NO_EMPTY.rawValue)) xmlSaveTree(ctxt,self.cNode) xmlSaveClose(ctxt) let dumped = ^-^xmlBufferContent(buffer) ?? "" xmlBufferFree(buffer) return dumped }()

    bug 
    opened by laurent-humbert 8
  • Iterate Text Nodes

    Iterate Text Nodes

    Hey!

    Is there a possibility to also have text nodes when iterating over the children of a XMLElement? Right now we use xpath with the //text() selector for this.

    br denis

    enhancement 
    opened by ghost 8
  • firstChild does not properly work with tag name `text`

    firstChild does not properly work with tag name `text`

    Description:

    • Expected behaviour: element.firstChild(tag: "text") return first text node instead of element node with tag name "text"

    • Actual behaviour: returns element not text node

    Environment

    • Package Manager: CocoaPods, version: 1.11.2

    • Fuzi version: 3.1.3

    • Xcode version: 13.4

    How to reproduce:

    <parent>
       <text>Some text</text>
    </parent>
    

    parent.firstChild(tag: "text")?.stringValue == " \n" instead of parent.firstChild(tag: "text")?.stringValue == "Some text" parent.firstChild(tag: "text")?.type == .Text instead of parent.firstChild(tag: "text")?.type == .Element

    parent.children(tag: "text") finds proper nodes as it checks also element type

    opened by Igor-Palaguta 1
  • `XMLNodeType` declares `~=` infix operator with wrong precedence

    `XMLNodeType` declares `~=` infix operator with wrong precedence

    Description:

    • Expected behaviour:

    The ~= infix operator declaration should use the same precedence (ComparisonPrecedence) as Swift's built-in operator.

    • Actual behaviour:

    Node.swift defines the ~= infix operator as follows:

    infix operator ~=
    

    This causes the operator to have DefaultPrecedence resulting in the following build error whenever the ~= operator is used with other types in a Swift file that imports Fuzi:

    Ambiguous operator declarations found for operator
    

    This can be resolved by re-defining the ~= operator as follows at the point of use:

    infix operator ~= : ComparisonPrecedence
    

    However this should not be necessary.

    Suggested Solution

    Change the operator definition in Node.swift to:

    infix operator ~= : ComparisonPrecedence
    

    Environment

    • Package Manager:

      • [ ] SPM, version 5.5
    • Fuzi version: 3.1.3

    • Xcode version: 13.2.1

    How to reproduce:

    1. Open the attached project
    2. Build
    3. Xcode will emit a build error
    4. Comment out operator definition in Sources/FuziTest/FuziTest.swift to fix error.

    FuziTest.zip

    opened by sepw 0
  • Support for Linux and GitHub Actions

    Support for Linux and GitHub Actions

    • Fix compiling for Linux through SPM
    • Add GitHub Actions (checks on Linux, macOS 10 and macOS 11)

    Kudos to https://github.com/SwiftDocOrg/Markup as I've copied much of their setup.

    It works well in my testing, though I had to disable a part of Document.swift when running on Linux as that lead to compile failures. I'm not sure what the impact of that is, though the tests all succeed.

    Closes #46 and #113

    opened by nighthawk 1
  • Document encoding is not compiling on linux

    Document encoding is not compiling on linux

    On the system libxml2-dev package is installed, and /usr/include/libxml -> /usr/include/libxml2/libxml symlinked and /usr/include/libxml2/module.modulemap exists with the following content:

    module libxml2 [system] [extern_c] {
        link "xml2"
    
        umbrella "libxml"
        export *
        module * { export * }
        exclude header "libxml/DOCBparser.h"
    }
    

    If I create a template swift package with Fuzi as a dependency in it:

    // swift-tools-version:5.3
    // The swift-tools-version declares the minimum version of Swift required to build this package.
    
    import PackageDescription
    
    let package = Package(
        name: "spm-test",
        products: [
            // Products define the executables and libraries a package produces, and make them visible to other packages.
            .library(
                name: "spm-test",
                targets: ["spm-test"]),
        ],
        dependencies: [
            // Dependencies declare other packages that this package depends on.
            // .package(url: /* package url */, from: "1.0.0"),
            .package(url: "https://github.com/cezheng/Fuzi.git", from: "3.1.2"),
        ],
        targets: [
            // Targets are the basic building blocks of a package. A target can define a module or a test suite.
            // Targets can depend on other targets in this package, and on products in packages this package depends on.
            .target(
                name: "spm-test",
                dependencies: ["Fuzi"]),
            .testTarget(
                name: "spm-testTests",
                dependencies: ["spm-test"]),
        ]
    )
    

    Compilation is failing on the following code snippet:

    https://github.com/cezheng/Fuzi/blob/f08c8323da21e985f3772610753bcfc652c2103f/Sources/Document.swift#L34-L42

    The error message I get is this:

    /home/pi/spm-test/.build/checkouts/Fuzi/Sources/Document.swift:36:22: error: cannot find 'CFStringConvertIANACharSetNameToEncoding' in scope
          let encoding = CFStringConvertIANACharSetNameToEncoding(encodingName as CFString?)
                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    /home/pi/spm-test/.build/checkouts/Fuzi/Sources/Document.swift:37:22: error: cannot find 'kCFStringEncodingInvalidId' in scope
          if encoding != kCFStringEncodingInvalidId {
                         ^~~~~~~~~~~~~~~~~~~~~~~~~~
    /home/pi/spm-test/.build/checkouts/Fuzi/Sources/Document.swift:38:47: error: cannot find 'CFStringConvertEncodingToNSStringEncoding' in scope
            return String.Encoding(rawValue: UInt(CFStringConvertEncodingToNSStringEncoding(encoding)))
                                                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    /home/pi/spm-test/.build/checkouts/Fuzi/Sources/Document.swift:36:22: error: cannot find 'CFStringConvertIANACharSetNameToEncoding' in scope
          let encoding = CFStringConvertIANACharSetNameToEncoding(encodingName as CFString?)
                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    /home/pi/spm-test/.build/checkouts/Fuzi/Sources/Document.swift:37:22: error: cannot find 'kCFStringEncodingInvalidId' in scope
          if encoding != kCFStringEncodingInvalidId {
                         ^~~~~~~~~~~~~~~~~~~~~~~~~~
    /home/pi/spm-test/.build/checkouts/Fuzi/Sources/Document.swift:38:47: error: cannot find 'CFStringConvertEncodingToNSStringEncoding' in scope
            return String.Encoding(rawValue: UInt(CFStringConvertEncodingToNSStringEncoding(encoding)))
    

    I saw that Kanna has something to patch this behavior but I am not sure how to implement it:

    https://github.com/tid-kijyun/Kanna/blob/c657fb9f5827ef138068215c76ad0bb62bbc92da/Sources/Kanna/libxmlHTMLDocument.swift#L29

    opened by gazsiazasz 1
  • Allow access to namespace URIs

    Allow access to namespace URIs

    I have a use case where I need to access the namespace URIs declared in the root element. Fuzi's default namespace handling works well for me and I have ready access to the prefixes as necessary. But their associated URIs seem to be unavailable. Are namespace URIs currently available via Fuzi's public API? Thanks!

    opened by siegesmund 0
Releases(3.1.3)
  • 3.1.3(Dec 13, 2020)

  • 3.1.2(Mar 27, 2020)

  • 3.1.1(Jun 26, 2019)

  • 3.1.0(May 25, 2019)

  • 3.0.0(Apr 1, 2019)

  • 2.2.1(Apr 1, 2019)

    • Fixed a bug that parses an HTML document with xmlReadMemory. This worked previously because the compiler used to treat convenience initializers in a polymorphic manner, which does not match the spec.
    Source code(tar.gz)
    Source code(zip)
  • 2.2.0(Apr 1, 2019)

  • 2.1.0(Apr 30, 2018)

    • Added a throw version of xpath method to Queryable protocol so that there is now a way to see the error when you pass in an invalid XPath query string instead of just getting a silent empty result. The non-throw xpath method is still there so you don't need to change your code. Thanks @Parabak !
    • Fixed all warnings in Xcode 9.3.
    Source code(tar.gz)
    Source code(zip)
  • 2.0.2(Apr 3, 2018)

  • 2.0.1(Oct 19, 2017)

    • Disabled coverage to prevent potential AppStore rejection if using Carthage ( Thanks @mhmiles )
    • Fixed firstChild crash bug when ns is specified for certain documents ( #70. Thanks @banjun )
    Source code(tar.gz)
    Source code(zip)
  • 2.0.0(Sep 14, 2017)

    • Swift 4 is here!(credits to @jdivittorio3 and @ashleymills)
    • Support using StaticString as tag names and performance optimization(#51, credits to @banjun)
    Source code(tar.gz)
    Source code(zip)
  • 1.0.1(Oct 26, 2016)

    • Fixed a bug that causes Fuzi to crash when creating XMLDocument with invalid data.
    • Restructured directory structure (intending to support SPM, but no luck yet)
    • Use a single Xcode scheme for iOS/macOS/watchOS/tvOS.
    Source code(tar.gz)
    Source code(zip)
  • 1.0.0(Sep 17, 2016)

  • 0.4.0(Sep 17, 2016)

    This is the final release for Swift 2.3. The master branch will be in Swift 3.

    Changes

    • Updated with Swift 2.3
    • Fixed an issue that might dump html node as self-closed even if the original node in document is not
    • Fixed a bug in NSRange conversion that did not use utf16 indexes
    • Some cleanup
    Source code(tar.gz)
    Source code(zip)
  • 0.3.1(Mar 29, 2016)

  • 0.3.0(Nov 20, 2015)

    Changes

    • Added XMLNode type to represent other types of nodes that are not element
    • Import from libxml2 XMLNodeType enum for determining node types
    • Support fetching specified types of Nodes from children, README updated with an example (https://github.com/cezheng/Fuzi/issues/3)
    • Minor optimizations on HTML convenience methods
    Source code(tar.gz)
    Source code(zip)
  • 0.2.0(Oct 22, 2015)

  • 0.1.1(Sep 26, 2015)

    • Minor improvements such as printable documents & avoiding unnecessary iteration on finding first child
    • Minor fixes relating to encoding & strong reference cycle
    Source code(tar.gz)
    Source code(zip)
  • 0.1.0(Sep 16, 2015)

    • Initial release!
    • Interface redesign based on Ono's lower level implementation
    • All necessary Ono methods ported
    • All Ono tests imported
    • CSS to XPath conversion bug fixed
    • XPath eval memory leak bug fixed
    • libxml2 error bug fixed
    Source code(tar.gz)
    Source code(zip)
Owner
Ce Zheng
Swifter who also writes C++
Ce Zheng
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
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 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
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
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
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
The most swifty way to deal with XML data in swift 5.

SwiftyXML SwiftyXML use most swifty way to deal with XML data. Features Infinity subscript dynamicMemberLookup Support (use $ started string to subscr

Kevin 99 Sep 6, 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 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
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
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
Convert text with HTML tags, links, hashtags, mentions into NSAttributedString. Make them clickable with UILabel drop-in replacement.

Convert text with HTML tags, links, hashtags, mentions into NSAttributedString. Make them clickable with UILabel drop-in replacement.

Pavel Sharanda 1.1k Dec 26, 2022
An Objective-C framework for your everyday HTML needs.

HTMLKit An Objective-C framework for your everyday HTML needs. Quick Overview Installation Parsing The DOM CSS3 Selectors Quick Overview HTMLKit is a

Iskandar Abudiab 229 Dec 12, 2022
Mathias Köhnke 1.1k Dec 16, 2022
🔥 🔥 🔥Support for ORM operation,Customize the PQL syntax for quick queries,Support dynamic query,Secure thread protection mechanism,Support native operation,Support for XML configuration operations,Support compression, backup, porting MySQL, SQL Server operation,Support transaction operations.

?? ?? ??Support for ORM operation,Customize the PQL syntax for quick queries,Support dynamic query,Secure thread protection mechanism,Support native operation,Support for XML configuration operations,Support compression, backup, porting MySQL, SQL Server operation,Support transaction operations.

null 60 Dec 12, 2022
A lightweight CSS parser for parsing and creating CSS stylesheets

SwiftCSSParser A lightweight CSS parser for Swift that uses cssparser (cpp) under the hood. Basic usage Here's a simple code snippet to get you starte

null 9 Jul 20, 2022