You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用SWXMLHash构建深层XML结构体?并解析Reddit RSS图片地址

Reddit RSS XML Parsing: Extracting Image Src & Deep Structs with SWXMLHash

Hey there! Since you already have a working setup with Alamofire and your APIUsable protocol, let's break down your two main goals: grabbing the src attribute from <img> inside the <content> node, and building nested structs with SWXMLHash for deep XML hierarchies.

1. Extracting the <img> src from the <content> Node

First, let's address the image source extraction. Reddit's RSS <content> node usually contains HTML wrapped in CDATA, so we need to:

  • Pull the raw HTML string from the <content> node
  • Parse that HTML to find the <img> tag and its src attribute

Step 1: Get the Content HTML with SWXMLHash

Assuming you have your base entry struct, first extract the content text:

import SWXMLHash

struct RedditEntry: XMLIndexerDeserializable {
    let title: String
    let contentHtml: String
    
    static func deserialize(_ node: XMLIndexer) throws -> RedditEntry {
        return try RedditEntry(
            title: node["title"].value(),
            contentHtml: node["content"].value()
        )
    }
}

Step 2: Parse HTML to Extract Image Src

You can use a simple regex to pull the src value from the content HTML, or use a lightweight HTML parser for more robustness. Here's both approaches:

Regex Approach (Quick & Simple)

extension RedditEntry {
    var postImageSrc: String? {
        // Regex pattern to match img tags and capture src attribute
        let pattern = #"<img[^>]+src="([^"]+)""#
        guard let regex = try? NSRegularExpression(pattern: pattern, options: .caseInsensitive),
              let match = regex.firstMatch(in: contentHtml, range: NSRange(contentHtml.startIndex..., in: contentHtml)) else {
            return nil
        }
        
        let srcRange = Range(match.range(at: 1), in: contentHtml)!
        return String(contentHtml[srcRange])
    }
}

HTML Parser Approach (More Reliable)

If you want to avoid regex edge cases, use a library like SwiftSoup:

import SwiftSoup

extension RedditEntry {
    var postImageSrc: String? {
        do {
            let doc = try SwiftSoup.parse(contentHtml)
            if let img = try doc.select("img").first() {
                return try img.attr("src")
            }
        } catch {
            print("HTML parsing error: \(error)")
        }
        return nil
    }
}

2. Building Deep Nested Structs with SWXMLHash

SWXMLHash makes mapping complex XML hierarchies to nested Swift structs straightforward by conforming to XMLIndexerDeserializable. Let's build out a full example matching Reddit's RSS structure, including nested nodes like <author> or <category>.

Example Deep Struct Setup

// Top-level RSS feed struct
struct RedditFeed: XMLIndexerDeserializable {
    let entries: [RedditEntry]
    
    static func deserialize(_ node: XMLIndexer) throws -> RedditFeed {
        return try RedditFeed(
            entries: node["entry"].value()
        )
    }
}

// Individual entry with nested author and categories
struct RedditEntry: XMLIndexerDeserializable {
    let title: String
    let contentHtml: String
    let author: RedditAuthor
    let categories: [RedditCategory]
    
    static func deserialize(_ node: XMLIndexer) throws -> RedditEntry {
        return try RedditEntry(
            title: node["title"].value(),
            contentHtml: node["content"].value(),
            author: node["author"].value(),
            categories: node["category"].value()
        )
    }
}

// Nested author struct
struct RedditAuthor: XMLIndexerDeserializable {
    let name: String
    let uri: String
    
    static func deserialize(_ node: XMLIndexer) throws -> RedditAuthor {
        return try RedditAuthor(
            name: node["name"].value(),
            uri: node["uri"].value()
        )
    }
}

// Nested category struct (handles XML attributes)
struct RedditCategory: XMLIndexerDeserializable {
    let term: String
    
    static func deserialize(_ node: XMLIndexer) throws -> RedditCategory {
        // Access XML attributes with the `@` prefix
        return try RedditCategory(
            term: node.attributes["term"].value()
        )
    }
}

Key Notes for Deep Structs:

  • Nested Nodes: When a node has child elements (like <author> containing <name> and <uri>), create a separate struct for the child and call node["childNode"].value() to deserialize it.
  • Attributes: For XML attributes (e.g., <category term="funny">), use node.attributes["attributeName"].value() to access the value.
  • Arrays: If multiple nodes exist (like multiple <category> entries), declare the property as an array—SWXMLHash will automatically deserialize all matching nodes.

Integrating with Your Alamofire & APIUsable Setup

Assuming your APIUsable protocol handles network calls, parse the response like this:

// Example API struct conforming to APIUsable
struct RedditHotAPI: APIUsable {
    var baseURL: String { "https://www.reddit.com" }
    var path: String { "/hot/.rss" }
    var method: HTTPMethod { .get }
    
    func parseResponse(data: Data) throws -> RedditFeed {
        let xml = SWXMLHash.parse(data)
        return try xml["feed"].value()
    }
}

// Usage
Alamofire.request(RedditHotAPI()).responseData { response in
    switch response.result {
    case .success(let data):
        do {
            let feed = try RedditHotAPI().parseResponse(data: data)
            // Access entries and their image src
            for entry in feed.entries {
                print("Post title: \(entry.title)")
                print("Image src: \(entry.postImageSrc ?? "No image")")
            }
        } catch {
            print("Parsing error: \(error)")
        }
    case .failure(let error):
        print("Network error: \(error)")
    }
}

That should cover both extracting the image source and building out deep structs with SWXMLHash. Adjust any part to fit your specific APIUsable implementation if needed!

内容的提问来源于stack exchange,提问作者BeauZ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 08:33:35