SwiftSoup/Example/Pods/Fuzi/Sources/Element.swift

176 lines
5.6 KiB
Swift

// Element.swift
// Copyright (c) 2015 Ce Zheng
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
import libxml2
/// Represents an element in `XMLDocument` or `HTMLDocument`
open class XMLElement: XMLNode {
/// The element's namespace.
open fileprivate(set) lazy var namespace: String? = {
return ^-^(self.cNode.pointee.ns != nil ?self.cNode.pointee.ns.pointee.prefix :nil)
}()
/// The element's tag.
open fileprivate(set) lazy var tag: String? = {
return ^-^self.cNode.pointee.name
}()
// MARK: - Accessing Attributes
/// All attributes for the element.
open fileprivate(set) lazy var attributes: [String : String] = {
var attributes = [String: String]()
var attribute = self.cNode.pointee.properties
while attribute != nil {
if let key = ^-^attribute?.pointee.name, let value = self.attr(key) {
attributes[key] = value
}
attribute = attribute?.pointee.next
}
return attributes
}()
/**
Returns the value for the attribute with the specified key.
- parameter name: The attribute name.
- parameter ns: The namespace, or `nil` by default if not using a namespace
- returns: The attribute value, or `nil` if the attribute is not defined.
*/
open func attr(_ name: String, namespace ns: String? = nil) -> String? {
var value: String? = nil
let xmlValue: UnsafeMutablePointer<xmlChar>?
if let ns = ns {
xmlValue = xmlGetNsProp(cNode, name, ns)
} else {
xmlValue = xmlGetProp(cNode, name)
}
if let xmlValue = xmlValue {
value = ^-^xmlValue
xmlFree(xmlValue)
}
return value
}
// MARK: - Accessing Children
/// The element's children elements.
open var children: [XMLElement] {
return LinkedCNodes(head: cNode.pointee.children).flatMap {
XMLElement(cNode: $0, document: self.document)
}
}
/**
Get the element's child nodes of specified types
- parameter types: type of nodes that should be fetched (e.g. .Element, .Text, .Comment)
- returns: all children of specified types
*/
open func childNodes(ofTypes types: [XMLNodeType]) -> [XMLNode] {
return LinkedCNodes(head: cNode.pointee.children, types: types).flatMap { node in
switch node.pointee.type {
case XMLNodeType.Element:
return XMLElement(cNode: node, document: self.document)
default:
return XMLNode(cNode: node, document: self.document)
}
}
}
/**
Returns the first child element with a tag, or `nil` if no such element exists.
- parameter tag: The tag name.
- parameter ns: The namespace, or `nil` by default if not using a namespace
- returns: The child element.
*/
open func firstChild(tag: String, inNamespace ns: String? = nil) -> XMLElement? {
var nodePtr = cNode.pointee.children
while let cNode = nodePtr {
if cXMLNode(nodePtr, matchesTag: tag, inNamespace: ns) {
return XMLElement(cNode: cNode, document: self.document)
}
nodePtr = cNode.pointee.next
}
return nil
}
/**
Returns all children elements with the specified tag.
- parameter tag: The tag name.
- parameter ns: The namepsace, or `nil` by default if not using a namespace
- returns: The children elements.
*/
open func children(tag: String, inNamespace ns: String? = nil) -> [XMLElement] {
return LinkedCNodes(head: cNode.pointee.children).flatMap {
cXMLNode($0, matchesTag: tag, inNamespace: ns)
? XMLElement(cNode: $0, document: self.document) : nil
}
}
// MARK: - Accessing Content
/// Whether the element has a value.
open var isBlank: Bool {
return stringValue.isEmpty
}
/// A number representation of the element's value, which is generated from the document's `numberFormatter` property.
open fileprivate(set) lazy var numberValue: NSNumber? = {
return self.document.numberFormatter.number(from: self.stringValue)
}()
/// A date representation of the element's value, which is generated from the document's `dateFormatter` property.
open fileprivate(set) lazy var dateValue: Date? = {
return self.document.dateFormatter.date(from: self.stringValue)
}()
/**
Returns the child element at the specified index.
- parameter idx: The index.
- returns: The child element.
*/
open subscript (idx: Int) -> XMLElement? {
return children[idx]
}
/**
Returns the value for the attribute with the specified key.
- parameter name: The attribute name.
- returns: The attribute value, or `nil` if the attribute is not defined.
*/
open subscript (name: String) -> String? {
return attr(name)
}
}