1 /**
2 * Copyright © DiamondMVC 2019
3 * License: MIT (https://github.com/DiamondMVC/Diamond/blob/master/LICENSE)
4 * Author: Jacob Jensen (bausshf)
5 */
6 module diamond.xml.xmldocument;
7 
8 import diamond.xml.xmlexception;
9 import diamond.dom.domdocument;
10 import diamond.dom.domnode;
11 import diamond.dom.domparsersettings;
12 import diamond.xml.xmlnode;
13 
14 /// An XML document.
15 final class XmlDocument : DomDocument
16 {
17   private:
18   /// The version of the xml document.
19   string _xmlVersion;
20   /// The encoding of the xml document.
21   string _encoding;
22   /// The root node of the document.
23   XmlNode _root;
24 
25   public:
26   final:
27   /**
28   * Creates a new xml document.
29   * Params:
30   *   parserSettings = The settings used for parsing the document.
31   */
32   this(DomParserSettings parserSettings) @safe
33   {
34     super(parserSettings);
35   }
36 
37   /**
38   * Parses the elements from the dom to the document.
39   * Params:
40   *   elements = The parsed dom elements.
41   */
42   override void parseElements(DomNode[] elements) @safe
43   {
44     if (!elements || elements.length != 2)
45     {
46       throw new XmlException("No xml header found or no root element found.");
47     }
48 
49     auto header = elements[0];
50     _root = elements[1];
51 
52     auto versionAttribute = header.getAttribute("version");
53     auto encodingAttribute = header.getAttribute("encoding");
54 
55     import std..string : strip;
56 
57     _xmlVersion = versionAttribute ? versionAttribute.value.strip() : null;
58     _encoding = encodingAttribute ? encodingAttribute.value.strip() : "UTF-8";
59   }
60 
61   @property
62   {
63     /// Gets the version of the xml document.
64     string xmlVersion() @safe { return _xmlVersion; }
65 
66     /// Sets the version of the xml document.
67     void xmlVersion(string newXmlVersion) @safe
68     {
69       _xmlVersion = newXmlVersion;
70 
71       if (!_xmlVersion || !_xmlVersion.length)
72       {
73         throw new XmlException("No xml version found.");
74       }
75     }
76 
77     /// Gets the encoding of the xml document.
78     string encoding() @safe { return _encoding; }
79 
80     /// Sets the encoding of the xml document.
81     void encoding(string newEncoding) @safe
82     {
83       _encoding = newEncoding;
84 
85       if (!_encoding || !_encoding.length)
86       {
87         throw new XmlException("Empty encoding specified.");
88       }
89     }
90 
91     /// Gets the root of the xml document.
92     XmlNode root() @safe { return _root; }
93 
94     /// Sets the root node of the xml document.
95     void root(XmlNode newRoot) @safe
96     {
97       _root = newRoot;
98     }
99   }
100 
101   /// XML documents cannot be repaired.
102   override void repairDocument() @safe
103   {
104     throw new XmlException("Cannot repair XML documents.");
105   }
106 
107   /**
108   * Converts the xml document to a properly formatted xml document-string.
109   * Returns:
110   *   A string equivalent to the properly formatted xml document-string.
111   */
112   override string toString() @safe
113   {
114     import std..string : format;
115 
116     return "<?xml version=\"%s\" encoding=\"%s\"?>\r\n%s".format(_xmlVersion, _encoding && _encoding.length ? _encoding : "UTF-8", _root ? _root.toString() : "");
117   }
118 }