SwiftSoup Documentation

repository·master·Indexed 26 days ago

https://github.com/scinfu/swiftsoup

A pure Swift library for HTML parsing and manipulation conforming to the WHATWG HTML5 specification. It supports macOS, iOS, tvOS, watchOS, and Linux. Key features include automatic HTML/XML detection, CSS selector-based element selection, DOM modification, and HTML cleaning via whitelists to prevent XSS. It provides tools for parsing from strings or URLs and includes a CLI harness for performance benchmarking.

Tokens
3K
Snippets
14
Records
15
Agent score
40%

What's inside SwiftSoup

  1. Enable the in-code profiler

    master

    The Profiler type is only compiled when the PROFILE flag is set. To use it, build the SwiftSoupProfile target with the -DPROFILE flag. The CLI will print a profiler summary at the end of the run.

    swift run -c release -Xswiftc -DPROFILE SwiftSoupProfile --fixtures /path/to/fixtures
  2. Install SwiftSoup via Swift Package Manager

    master

    To install SwiftSoup using Swift Package Manager, add the dependency to your Package.swift file:

    ...
    dependencies: [
        .package(url: "https://github.com/scinfu/SwiftSoup.git", from: "2.6.0"),
    ],
    targets: [
        .target( name: "YourTarget", dependencies: ["SwiftSoup"]),
    ]
    ...
  3. Automatic Format Detection (HTML vs XML)

    master

    The SwiftSoup.parse(...) method automatically detects whether the input is XML or HTML. It looks for an <?xml declaration at the start of the content. If detected, it uses the XML parser; otherwise, it uses the HTML parser.

    import SwiftSoup
    
    let xml = """
    <?xml version="1.0" encoding="UTF-8"?>
    <opml version="1.0">
      <body>
        <link>I'm link</link>
        <img>I'm img</img>
      </body>
    </opml>
    """
    
    let document = try SwiftSoup.parse(xml) // auto-detects XML
    print(try document.select("link").first()?.text()) // Output: I'm link
    print(try document.select("body > img").first()?.text()) // Output: I'm img
  4. Extract text and attributes from elements

    master

    Once an element is selected, use .text() to get the visible text content and .attr("attributeName") to retrieve the value of a specific HTML attribute.

    let html = "<a href='https://example.com'>Visit the site</a>"
    let document = try SwiftSoup.parse(html)
    let link = try document.select("a").first()
    
    if let link = link {
        print(try link.text()) // Output: Visit the site
        print(try link.attr("href")) // Output: https://example.com
    }
  5. Clean HTML for security using Whitelists

    master

    To prevent XSS or remove unwanted tags/attributes, use SwiftSoup.clean(dirtyHtml, whitelist).

    • Use Whitelist.basic() for a standard safe set of tags.
    • Create a custom Whitelist to explicitly allow specific tags, attributes, or CSS properties.
    // Using a predefined basic whitelist
    let dirtyHtml = "<script>alert('Hacked!')</script><b>Important text</b>"
    let cleanHtml = try SwiftSoup.clean(dirtyHtml, Whitelist.basic())
    print(cleanHtml) // Output: <b>Important text</b>
    
    // Using a custom whitelist
    let dirtyHtml = #"<p style="color:red; position:absolute">Styled text</p>"#
    let whitelist = try Whitelist()
        .addTags("p")
        .addAttributes("p", "style")
        .addCSSProperties("p", "color")
    let cleanHtml = try SwiftSoup.clean(dirtyHtml, whitelist)
    print(cleanHtml) // Output: <p style="color:red">Styled text</p>
  6. Parse HTML from a URL

    master

    To parse HTML directly from a URL, use SwiftSoup.parse(url). This is recommended over using String(contentsOf:) when Foundation cannot determine the page's text encoding, as it parses the raw response bytes.

    import SwiftSoup
    
    let url = URL(string: "https://example.com")!
    let document = try SwiftSoup.parse(url)
    print(try document.title())
  7. Parse an HTML Document

    master

    Use SwiftSoup.parse(_:) to parse an HTML string into a Document object. This method follows the WHATWG HTML5 specification.

    import SwiftSoup
    
    let html = """
    <html><head><title>Example</title></head>
    <body><p>Hello, SwiftSoup!</p></body></html>
    """
    
    let document: Document = try SwiftSoup.parse(html)
    print(try document.title()) // Output: Example
  8. Select elements using CSS selectors

    master

    Use document.select("selector") to find elements matching a CSS query. This returns a collection of elements that can be iterated over.

    let html = """
    <html><body>
    <p class='message'>SwiftSoup is powerful!</p>
    <p class='message'>Parsing HTML in Swift</p>
    </body></html>
    """
    
    let document = try SwiftSoup.parse(html)
    let messages = try document.select("p.message")
    
    for message in messages {
        print(try message.text())
    }
    // Output:
    // SwiftSoup is powerful!
    // Parsing HTML in Swift
  9. Modify the DOM

    master

    You can manipulate the document structure by selecting elements and using methods like .append("html") to add new content.

    var document = try SwiftSoup.parse("<div id='content'></div>")
    let div = try document.select("#content").first()
    try div?.append("<p>New content added!</p>")
    print(try document.html())
    // Output:
    // <html><head></head><body><div id="content"><p>New content added!</p></div></body></html>
  10. Optimize repeated CSS queries

    master

    SwiftSoup automatically caches parsed CSS queries via QueryParser.cache. You can manage this cache to improve performance.

    Alternatively, for maximum efficiency and thread safety, parse the query once into an Evaluator and reuse it. Evaluator instances are immutable and safe to store in static properties.

    // Manage the global cache
    QueryParser.cache = QueryParser.DefaultCache(limit: .unlimited)
    QueryParser.cache = QueryParser.DefaultCache(limit: .count(1000))
    
    // Use Evaluator for repeated queries
    let elements: Elements = ...
    let eval = try QueryParser.parse("div > p")
    for element in elements {
        print(try element.select(eval).text())
    }