1 /** 2 License: 3 Boost Software License - Version 1.0 - August 17th, 2003 4 5 Permission is hereby granted, free of charge, to any person or organization 6 obtaining a copy of the software and accompanying documentation covered by 7 this license (the "Software") to use, reproduce, display, distribute, 8 execute, and transmit the Software, and to prepare derivative works of the 9 Software, and to permit third-parties to whom the Software is furnished to 10 do so, all subject to the following: 11 12 The copyright notices in the Software and this entire statement, including 13 the above license grant, this restriction and the following disclaimer, 14 must be included in all copies of the Software, in whole or in part, and 15 all derivative works of the Software, unless such copies or derivative 16 works are solely in the form of machine-executable object code generated by 17 a source language processor. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 22 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 23 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 24 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 DEALINGS IN THE SOFTWARE. 26 27 Authors: 28 aermicioi 29 **/ 30 module aermicioi.aedi_property_reader.xml.xml_factory; 31 32 import aermicioi.aedi_property_reader.convertor_factory; 33 import aermicioi.aedi.factory; 34 import aermicioi.aedi.storage.locator; 35 import aermicioi.aedi.storage.wrapper; 36 import aermicioi.aedi.storage.decorator; 37 import aermicioi.aedi.exception; 38 import std.traits; 39 import std.xml; 40 41 /** 42 A convertor factory that uses custom fromXml family of functions to convert xml Element into To types. 43 44 Params: 45 FromType = original representation form of data to be converted. 46 ToType = type of component that is built based on FromType data. 47 **/ 48 class XmlConvertorFactory(To, From : Element = Element) : ConvertorFactory!(Element, To) { 49 50 private { 51 52 Locator!() locator_; 53 Element convertible_; 54 } 55 56 public { 57 58 @property { 59 /** 60 Set convertible 61 62 Params: 63 convertible = data that the factory should convert into ToType component 64 Returns: 65 XmlConvertorFactory!(To, From) 66 **/ 67 XmlConvertorFactory!(To, From) convertible(Element convertible) @safe nothrow { 68 this.convertible_ = convertible; 69 70 return this; 71 } 72 73 /** 74 Get convertible data 75 76 Returns: 77 FromType 78 **/ 79 Element convertible() @safe nothrow { 80 return this.convertible_; 81 } 82 83 /** 84 Get the type info of T that is created. 85 86 Returns: 87 TypeInfo object of created component. 88 **/ 89 TypeInfo type() { 90 return typeid(To); 91 } 92 93 /** 94 Set a locator to object. 95 96 Params: 97 locator = the locator that is set to oject. 98 99 Returns: 100 LocatorAware. 101 **/ 102 XmlConvertorFactory!(To, From) locator(Locator!() locator) @safe nothrow { 103 this.locator_ = locator; 104 105 return this; 106 } 107 } 108 109 /** 110 Instantiates component of type To. 111 112 Returns: 113 To instantiated component. 114 **/ 115 To factory() { 116 return fromXml!To(this.convertible()); 117 } 118 } 119 } 120 121 package { 122 import std.conv : to, ConvException; 123 124 /** 125 Convert xml Element into T scalar/array/assocarray value. 126 127 As converting value only text of xml element is taken into consideration. 128 129 Params: 130 value = storage where to put converted xml Element 131 xml = the data that is to be converted. 132 Throws: 133 InvalidCastException when the type of value does not match stored data. 134 Returns: 135 value 136 **/ 137 auto ref T fromXml(T)(auto ref T value, auto ref Element xml) 138 if (isNumeric!T) { 139 import std.string : strip; 140 141 try { 142 143 value = xml.text.strip.to!T; 144 } catch (ConvException e) { 145 throw new InvalidCastException( 146 "Could not convert xml " ~ 147 xml.toString() ~ 148 " value to type " ~ 149 fullyQualifiedName!T, 150 e 151 ); 152 } 153 154 return value; 155 } 156 157 /** 158 ditto 159 **/ 160 auto ref T fromXml(T)(auto ref T value, auto ref Element xml) 161 if (isSomeString!T) { 162 163 try { 164 165 value = xml.text.to!T; 166 } catch (ConvException e) { 167 throw new InvalidCastException( 168 "Could not convert xml " ~ 169 xml.toString() ~ 170 " value to type " ~ 171 fullyQualifiedName!T, 172 e 173 ); 174 } 175 return value; 176 } 177 178 /** 179 ditto 180 **/ 181 auto ref T fromXml(T : Z[], Z)(auto ref T value, auto ref Element xml) 182 if (!isSomeString!T) { 183 184 foreach (index, ref el; value) { 185 el.fromXml(xml.elements[index]); 186 } 187 188 return value; 189 } 190 191 /** 192 ditto 193 **/ 194 auto ref T fromXml(T : Z[string], Z)(auto ref T value, auto ref Element xml) { 195 196 foreach (ref el; xml.elements) { 197 198 value[el.tag.name] = el.fromXml!Z; 199 } 200 201 return value; 202 } 203 204 /** 205 ditto 206 **/ 207 T fromXml(T)(auto ref Element xml) 208 if (isNumeric!T) { 209 210 T value; 211 value.fromXml!T(xml); 212 213 return value; 214 } 215 216 /** 217 ditto 218 **/ 219 T fromXml(T)(auto ref Element xml) 220 if (isSomeString!T) { 221 222 T value; 223 value.fromXml(xml); 224 225 return value; 226 } 227 228 /** 229 ditto 230 **/ 231 T fromXml(T : Z[], Z)(auto ref Element xml) 232 if (!isSomeString!T) { 233 234 T array = new Z[xml.elements.length]; 235 array.fromXml(xml); 236 237 return array; 238 } 239 240 /** 241 ditto 242 **/ 243 T fromXml(T : Z[string], Z)(auto ref Element xml) { 244 245 T assoc; 246 assoc.fromXml(xml); 247 248 return assoc; 249 } 250 }