Document.swift 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  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. guard let rootElement = children.first else {
  19. let errorElement = Element(name: "Error")
  20. errorElement.error = XMLError.rootElementMissing
  21. return errorElement
  22. }
  23. return rootElement
  24. }
  25. public let options: Options
  26. // MARK: - Lifecycle
  27. /**
  28. Designated initializer - Creates and returns new XML Document object.
  29. - parameter root: Root XML element for XML Document (defaults to `nil`).
  30. - parameter options: Options for XML Document header and parser settings (defaults to `XMLOptions()`).
  31. - returns: Initialized XML Document object.
  32. */
  33. public init(root: Element? = nil, options: Options = Options()) {
  34. self.options = options
  35. let documentName = String(describing: Document.self)
  36. super.init(name: documentName)
  37. // document has no parent element
  38. parent = nil
  39. // add root element to document (if any)
  40. if let rootElement = root {
  41. addChild(rootElement)
  42. }
  43. }
  44. /**
  45. Convenience initializer - used for parsing XML data (by calling `loadXMLData:` internally).
  46. - parameter xmlData: XML data to parse.
  47. - parameter options: Options for XML Document header and parser settings (defaults to `XMLOptions()`).
  48. - returns: Initialized XML Document object containing parsed data. Throws error if data could not be parsed.
  49. */
  50. public convenience init(xml: Data, options: Options = Options()) throws {
  51. self.init(options: options)
  52. try load(xml)
  53. }
  54. /**
  55. Convenience initializer - used for parsing XML string (by calling `init(xmlData:options:)` internally).
  56. - parameter xmlString: XML string to parse.
  57. - parameter encoding: String encoding for creating `Data` from `xmlString` (defaults to `String.Encoding.utf8`)
  58. - parameter options: Options for XML Document header and parser settings (defaults to `XMLOptions()`).
  59. - returns: Initialized XML Document object containing parsed data. Throws error if data could not be parsed.
  60. */
  61. public convenience init(xml: String,
  62. encoding: String.Encoding = String.Encoding.utf8,
  63. options: Options = Options()) throws {
  64. guard let data = xml.data(using: encoding) else { throw XMLError.parsingFailed }
  65. try self.init(xml: data, options: options)
  66. }
  67. // MARK: - Parse XML
  68. /**
  69. Creates instance of `Parser` (private class which is simple wrapper around `Parser`)
  70. and starts parsing the given XML data. Throws error if data could not be parsed.
  71. - parameter data: XML which should be parsed.
  72. */
  73. open func load(_ data: Data) throws {
  74. children.removeAll(keepingCapacity: false)
  75. let xmlParser = Parser(document: self, data: data)
  76. try xmlParser.parse()
  77. }
  78. // MARK: - Override
  79. /// Override of `xml` property of `Element` - it just inserts XML Document header at the beginning.
  80. override open var xml: String {
  81. var xml = "\(options.documentHeader.xmlString)\n"
  82. xml += root.xml
  83. return xml
  84. }
  85. }