在Swift中使用libxml2

//
//  main.swift
//  C150805_libxml2r2
//  http://git.oschina.net/yao_yu/Swift2015/tree/master/C150805_libxml2r2?dir=1&filepath=C150805_libxml2r2&oid=f80a7498226526b991e7913298c15cd38480aea5&sha=c073af33d0534a10098bb8fcc0706c2fd489dc3f
//
//  Created by yao_yu on 15/8/5.
//  Copyright © 2015年 yao_yu. All rights reserved.
//

import Foundation

/* ---------- 扩展 ---------- */

extension NSString{
    convenience init?(urlString:String, encoding:NSStringEncoding) {
        let url = NSURL(string: urlString)
        do {
            try self.init(contentsOfURL: url!, encoding: encoding)
        } catch {}
    }
}

extension String {
     init?(XMLChar char: UnsafePointer<xmlChar>){
        self.init()
        if char != nil {
            self = String.fromCString(UnsafePointer<CChar>(char))!
        }
    }
}

/* ---------- XML节点 ---------- */

class XMLNode {
    var xmlDoc:xmlDocPtr = nil
    var xmlNode:xmlNodePtr = nil

    init(node:xmlNodePtr, document:xmlDocPtr) {
        self.xmlNode = node
        self.xmlDoc = document
    }

    convenience init(document:xmlDocPtr) {
        self.init(node:xmlDocGetRootElement(document), document:document)
    }

    lazy var rawContent:String? = {
       return XMLNodeGetContent(self.xmlNode)
//        return XMLNodeGetString(self.xmlDoc, xmlNode: self.xmlNode)
    }()

    lazy var children:[XMLNode] = {
        return self.xmlNodes2XMLNodes(XMLNodeGetChildren(self.xmlNode))
        }()

    lazy var attributes: [String: String] = {
        return XMLNodeGetAttributes(self.xmlNode)
    }()

    subscript(key:String) -> String? {
        return attributes[key]
    }

    private func xmlNodes2XMLNodes(nodes:[xmlNodePtr]) -> [XMLNode] {
        var xmlNodes = [XMLNode]()
        for node in nodes{
            xmlNodes.append(XMLNode(node: node, document: xmlDoc))
        }
        return xmlNodes

        //下面的代码引发:Command failed due to signal: Abort trap: 6
        //return nodes.map{[unowned self] in XMLNode(node:$0, document:self.xmlDoc)}
    }
}

extension XMLNode {
    func xPath(xpath: String) -> [XMLNode] {
        return xmlNodes2XMLNodes(XMLFindXPath(self.xmlDoc, xPath: xpath))
    }
}

/* ---------- libxml2读取工具函数 ---------- */

func XMLNodeGetString(doc:xmlDocPtr, xmlNode:xmlNodePtr) -> String? {
    let contentChars = xmlNodeListGetString(doc, xmlNode, 1)
    if contentChars == nil { return nil }
    let contentString = String(XMLChar: contentChars)
    free(contentChars)
    assert(contentString != nil, "XMLNodeGetString: 值转换不成功")
    return contentString
}

func XMLNodeGetContent(xmlNode:xmlNodePtr) -> String? {
    let contentChars = xmlNodeGetContent(xmlNode)
    if contentChars == nil { return nil }
    let contentString = String(XMLChar: contentChars)
    free(contentChars)
    assert(contentString != nil, "XMLNodeGetContent: 值转换不成功")
    return contentString
}

func XMLNodeGetChildren(xmlNode: xmlNodePtr) -> [xmlNodePtr] {
    var children = [xmlNodePtr]()

    for var childNodePointer = xmlNode.memory.children;
        childNodePointer != nil;
        childNodePointer = childNodePointer.memory.next
    {
        if xmlNodeIsText(childNodePointer) == 0 {
            children.append(childNodePointer)
        }
    }

    return children
}

func XMLNodeGetAttributes(xmlNode: xmlNodePtr) -> [String: String] {
    var result:[String: String] = [String: String]()
    for var attribute: xmlAttrPtr = xmlNode.memory.properties;
        attribute != nil;
        attribute = attribute.memory.next
    {
        if let key:String = String(XMLChar: attribute.memory.name) {
            if let value:String = XMLNodeGetContent(attribute.memory.children) {
                result[key] = value
            } else {
                result[key] = ""
            }
        } else {
            print((">>>>>>>>>>>>>>>>>>>>>>>>错误:", String(XMLChar: attribute.memory.name)))
        }
    }
    return result
}

func XMLNodeGetAttribute(xmlNode: xmlNodePtr, key: String) -> String? {
    for var attribute: xmlAttrPtr = xmlNode.memory.properties;
        attribute != nil;
        attribute = attribute.memory.next
    {
        if key == String(XMLChar: attribute.memory.name) {
            return XMLNodeGetContent(attribute.memory.children)
        }
    }
    return nil
}

func XMLFindXPath(xmlDoc:xmlDocPtr, xPath: String) -> [xmlNodePtr] {
    let xPathContext = xmlXPathNewContext(xmlDoc)
    if xPathContext == nil {
        return []
    }

    xPathContext.memory.node = nil

    let xPathObject = xmlXPathEvalExpression(UnsafePointer<xmlChar>(xPath.cStringUsingEncoding(NSUTF8StringEncoding)!), xPathContext)
    xmlXPathFreeContext(xPathContext)
    if xPathObject == nil {
        return []
    }

    let nodeSet = xPathObject.memory.nodesetval
    if nodeSet == nil || nodeSet.memory.nodeNr == 0 || nodeSet.memory.nodeTab == nil {
        xmlXPathFreeObject(xPathObject)
        return []
    }

    var resultNodes = [xmlNodePtr]()
    for i in 0 ..< Int(nodeSet.memory.nodeNr) {
        resultNodes.append(nodeSet.memory.nodeTab[i])
    }

    xmlXPathFreeObject(xPathObject)

    return resultNodes
}

func XMLReadNSData(data:NSData?, encoding:NSStringEncoding = NSUTF8StringEncoding, isXML:Bool = false) -> xmlDocPtr?  {
    if let data = data {
        let cBuffer = UnsafePointer<CChar>(data.bytes)
        let cSize = CInt(data.length)
        //
//        let cfEncoding = CFStringConvertNSStringEncodingToEncoding(encoding)
//        let cfEncodingAsString:CFStringRef = CFStringConvertEncodingToIANACharSetName(cfEncoding)
//        let cEncoding:UnsafePointer<CChar> = CFStringGetCStringPtr(cfEncodingAsString, CFStringEncoding(0))

        if isXML {
            let options = CInt(XML_PARSE_RECOVER.rawValue)
            return xmlReadMemory(cBuffer, cSize, nil, nil, options)
        } else {
            let options = CInt(HTML_PARSE_RECOVER.rawValue | HTML_PARSE_NOWARNING.rawValue | HTML_PARSE_NOERROR.rawValue)
            return htmlReadMemory(cBuffer, cSize, nil, nil, options)
        }
    }
    return nil
}

let GB18030_2000_Encoding = CFStringConvertEncodingToNSStringEncoding(CFStringEncoding(CFStringEncodings.GB_18030_2000.rawValue))

/* ---------- 测试代码 ---------- */

class CElapseTime {
    var startTime:NSDate
    var prompt:String
    var unsed:Bool = false

    init(prompt:String) {
        self.startTime = NSDate()
        self.prompt = prompt
    }

    var newprompt:String {
        return "\(prompt)耗时:\(NSDate().timeIntervalSinceDate(startTime))"
    }
}

func testParseSina() {

    var sURL:String
    var encoding:UInt

    (sURL,encoding) = ("http://www.baidu.com", NSUTF8StringEncoding)
    print("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\(sURL)")

    var timer = CElapseTime(prompt: "读取网页")
    //let sContent = NSString(urlString:sURL, encoding: encoding)
    var sContent:NSString? = nil
    do{
        try sContent = NSString(contentsOfFile: "/Volumes/Data/Document/Test/sample.txt", encoding: NSUTF8StringEncoding)
    } catch {

    }
    print(timer.newprompt)
    let sTimer1 = timer.newprompt
    timer = CElapseTime(prompt: "数据解析")

    if let doc = XMLReadNSData(sContent?.dataUsingEncoding(NSUTF8StringEncoding)){
        let rootNode = XMLNode(document: doc)
        let findNodes = rootNode.xPath("//div")
        for childNode in findNodes {
            autoreleasepool{
                let _ = (childNode.attributes, childNode.rawContent)
            }
//            if let content = childNode.rawContent {
//                print(content)
//            }
        }
        print(findNodes.count)
    }
    print(sTimer1)
    print(timer.newprompt)
}

testParseSina()
时间: 2024-10-31 09:23:56

在Swift中使用libxml2的相关文章

Swift 中的Range和NSRange不同

Swift中的Ranges和Objective-C中的NSRange有很大的不同,我发现在处理Swift中Ranges相关的问题的时候,总是要花费比我想象的更多的时间.不过,现在回过头来看看,发现Swift中的Ranges的使用还是比较合理的,但是想要正确的使用Ranges真的需要一些特别的技巧. 看一个例子,下面这段代码展示的是截取以指定的字符开头和以指定的字符结尾的子字符串: ? 1 2 3 4 5 6 var str = "Hello, playground"   let ran

Swift 中的基础语法(二)

1.Swift 中的函数 /// 函数的定义 /// /// - Parameters: /// - x: 形参 /// - y: 形参 /// - Returns: 返回值 func sum(x: Int, y: Int) -> Int { return x + y } print(sum(x: 10, y: 20))   /* 外部参数就是在形参前面加了一个字 外部参数不会影响函数内部的细节 外部参数会让外部调用看起来更加直观 外部参数如果使用了'_',在外部调用函数时,会忽略形参的名字 &qu

Swift中的错误处理

前言 任何代码都会发生错误,这些错误有些是可以补救的,有些则只能让程序崩溃.良好的错误处理能够让你的代码健壮性提高,提高程序的稳定性. 本文的Swift版本:Swift 3 Objective C 返回nil 如果出错了,就返回空是Objective C中的一种常见的处理方式.因为在Objective C中,向nil发送消息是安全的.比如: - (instancetype)init { self = [super init]; if (self) { } //如果初始化失败,会返回nil ret

swift中代理的使用

下面以自定义的UITableViewCell的代理为例,记录一下swift中代理的使用 controller中的代码如 1 // 2 // ViewController.swift 3 // simpleDemo 4 // 5 // Created by liubo on 16/7/25. 6 // Copyright © 2016年 liubo. All rights reserved. 7 // 8 9 import UIKit 10 11 class ViewController: UIV

SWIFT中的repeat...while

SWIFT中的repeat...while类似于JAVA\.NET中的 do while.大同小异只是把do换成了repeat var index = 10 repeat{ print(index) index-- } while(index>0)

Swift中的结构体,类,协议,扩展和闭包的用法以及? 和 !的区别

// MARK: - 1.结构体 //1.声明一个结构体 struct Rect {    // 声明结构体变量的属性(存储属性)    var x:Float    var y:Float    var width:Float    var height:Float    // 声明结构体属性,要使用static    static var description:String?        // 声明一个计算属性(是用来专门计算结构体变量属性的setter,和getter方法,其本身没有存

Swift中编写单例的正确方式

Swift中编写单例的正确方式 2015-12-07 10:23 编辑: yunpeng.hu 分类:Swift 来源:CocoaChina翻译活动 14 10647 Objective-CSwift单例 招聘信息: Cocos2d-x 工程师 cocos2dx手游客户端主程 wp开发 iOS开发工程师 iOS软件工程师 iOS研发工程师 iOS讲师 iOS开发工程师 iOS高级开发工程师 iOS 高级软件工程师 iOS高级开发工程师 本文由CocoaChina译者leon(社区ID)翻译自kr

[Swift中错误]missing argument label &#39;greeting:&#39; in call

Swift 中出现这个问题:从第二个参数起,自动加上lable func sayHello(name:String? ,greeting:String)->String { let result = greeting + "," + (name ?? "Guest") + "!" return result } var nickname:String? nickname = "yc" //“Goodmorning前面应该

在Swift中使用遗留的C API

Swift的类型系统的设计目的在于简化我们的生活,为此它强制用户遵守严格的代码规范来达到这一点.毫无疑问这是一件大好事,它鼓励程序员们编写 更好更正确的代码.然而,当Swift与历史遗留的代码库.特别是C语言库进行交互时,问题出现了.我们需要面对的现实是许多C语言库滥用类型,以至于它 们对Swift的编译器并不友好.苹果的Swift团队的确花了不少功夫来支持C的一些基础特性,比如C字符串.但当在Swift中使用历史遗留的C语言 库时,我们还是会面临一些问题.下面我们就来解决这些问题. 在开始之前