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 }