SwiftSoup/Sources/TreeBuilder.swift

99 lines
3.1 KiB
Swift

//
// TreeBuilder.swift
// SwiftSoup
//
// Created by Nabil Chatbi on 24/10/16.
// Copyright © 2016 Nabil Chatbi.. All rights reserved.
//
import Foundation
public class TreeBuilder {
public var reader: CharacterReader
var tokeniser: Tokeniser
public var doc: Document // current doc we are building into
public var stack: Array<Element> // the stack of open elements
public var baseUri: String // current base uri, for creating new elements
public var currentToken: Token? // currentToken is used only for error tracking.
public var errors: ParseErrorList // null when not tracking errors
public var settings: ParseSettings
private let start: Token.StartTag = Token.StartTag() // start tag to process
private let end: Token.EndTag = Token.EndTag()
public func defaultSettings() -> ParseSettings {preconditionFailure("This method must be overridden")}
public init() {
doc = Document("")
reader = CharacterReader("")
tokeniser = Tokeniser(reader, nil)
stack = Array<Element>()
baseUri = ""
errors = ParseErrorList(0, 0)
settings = ParseSettings(false, false)
}
public func initialiseParse(_ input: String, _ baseUri: String, _ errors: ParseErrorList, _ settings: ParseSettings) {
doc = Document(baseUri)
self.settings = settings
reader = CharacterReader(input)
self.errors = errors
tokeniser = Tokeniser(reader, errors)
stack = Array<Element>()
self.baseUri = baseUri
}
func parse(_ input: String, _ baseUri: String, _ errors: ParseErrorList, _ settings: ParseSettings)throws->Document {
initialiseParse(input, baseUri, errors, settings)
try runParser()
return doc
}
public func runParser()throws {
while (true) {
let token: Token = try tokeniser.read()
try process(token)
token.reset()
if (token.type == Token.TokenType.EOF) {
break
}
}
}
@discardableResult
public func process(_ token: Token)throws->Bool {preconditionFailure("This method must be overridden")}
@discardableResult
public func processStartTag(_ name: String)throws->Bool {
if (currentToken === start) { // don't recycle an in-use token
return try process(Token.StartTag().name(name))
}
return try process(start.reset().name(name))
}
@discardableResult
public func processStartTag(_ name: String, _ attrs: Attributes)throws->Bool {
if (currentToken === start) { // don't recycle an in-use token
return try process(Token.StartTag().nameAttr(name, attrs))
}
start.reset()
start.nameAttr(name, attrs)
return try process(start)
}
@discardableResult
public func processEndTag(_ name: String)throws->Bool {
if (currentToken === end) { // don't recycle an in-use token
return try process(Token.EndTag().name(name))
}
return try process(end.reset().name(name))
}
public func currentElement() -> Element? {
let size: Int = stack.count
return size > 0 ? stack[size-1] : nil
}
}