Document.swift 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. /**
  2. * https://github.com/tadija/AEXML
  3. * Copyright (c) Marko Tadić 2014-2019
  4. * Licensed under the MIT license. See LICENSE file.
  5. */
  6. import Foundation
  7. #if canImport(FoundationXML)
  8. import FoundationXML
  9. #endif
  10. /**
  11. This class is inherited from `Element` and has a few addons to represent ** Document**.
  12. XML Parsing is also done with this object.
  13. */
  14. open class Document: Element {
  15. // MARK: - Properties
  16. /// Root (the first child element) element of XML Document **(Empty element with error if not exists)**.
  17. open var root: Element {
  18. if let element = children.first { return element }
  19. let element = Element(name: "Error")
  20. element.error = XMLError.rootElementMissing
  21. return element
  22. }
  23. public let options: Options
  24. // MARK: - Lifecycle
  25. /**
  26. Designated initializer - Creates and returns new XML Document object.
  27. - parameter root: Root XML element for XML Document (defaults to `nil`).
  28. - parameter options: Options for XML Document header and parser settings (defaults to `XMLOptions()`).
  29. - returns: Initialized XML Document object.
  30. */
  31. public init(root: Element? = nil, options: Options = .init()) {
  32. self.options = options
  33. let name = String(describing: Document.self)
  34. super.init(name: name)
  35. // document has no parent element
  36. parent = nil
  37. // add root element to document (if any)
  38. if let root = root {
  39. addChild(root)
  40. }
  41. }
  42. /**
  43. Convenience initializer - used for parsing XML data (by calling `loadXMLData:` internally).
  44. - parameter xmlData: XML data to parse.
  45. - parameter options: Options for XML Document header and parser settings (defaults to `XMLOptions()`).
  46. - returns: Initialized XML Document object containing parsed data. Throws error if data could not be parsed.
  47. */
  48. public convenience init(xml: Data, options: Options = .init()) throws {
  49. self.init(options: options)
  50. try load(xml)
  51. }
  52. /**
  53. Convenience initializer - used for parsing XML string (by calling `init(xmlData:options:)` internally).
  54. - parameter xmlString: XML string to parse.
  55. - parameter encoding: String encoding for creating `Data` from `xmlString` (defaults to `String.Encoding.utf8`)
  56. - parameter options: Options for XML Document header and parser settings (defaults to `XMLOptions()`).
  57. - returns: Initialized XML Document object containing parsed data. Throws error if data could not be parsed.
  58. */
  59. public convenience init(xml: String,
  60. encoding: String.Encoding = .utf8,
  61. options: Options = Options()) throws {
  62. guard let data = xml.data(using: encoding) else { throw XMLError.parsingFailed }
  63. try self.init(xml: data, options: options)
  64. }
  65. // MARK: - Parse XML
  66. /**
  67. Creates instance of `Parser` (private class which is simple wrapper around `Parser`)
  68. and starts parsing the given XML data. Throws error if data could not be parsed.
  69. - parameter data: XML which should be parsed.
  70. */
  71. open func load(_ data: Data) throws {
  72. children.removeAll(keepingCapacity: false)
  73. let parser = Parser(document: self, data: data)
  74. try parser.parse()
  75. }
  76. // MARK: - Override
  77. /// Override of `xml` property of `Element` - it just inserts XML Document header at the beginning.
  78. override open var xml: String {
  79. "\(options.documentHeader.xml)\n\(root.xml)"
  80. }
  81. }