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;
31 
32 import aermicioi.aedi : qualifier, component, lref;
33 import aermicioi.aedi.storage.storage;
34 import aermicioi.aedi.storage.locator;
35 import aermicioi.aedi_property_reader.xml.accessor;
36 import aermicioi.aedi_property_reader.xml.convertor;
37 import aermicioi.aedi_property_reader.convertor.accessor;
38 import aermicioi.aedi_property_reader.convertor.convertor;
39 import aermicioi.aedi_property_reader.convertor.chaining_convertor : ByTypePricingStrategy;
40 import aermicioi.aedi_property_reader.convertor.type_guesser;
41 import aermicioi.aedi_property_reader.core.document;
42 import aermicioi.aedi_property_reader.core.core;
43 import aermicioi.aedi_property_reader.convertor.std_conv;
44 import aermicioi.aedi_property_reader.xml.type_guesser;
45 import std.experimental.allocator;
46 import std.experimental.logger;
47 import std.xml;
48 import std.traits;
49 
50 auto XmlConvertors(
51     XmlConvertor xmlConvertor,
52     CombinedConvertor combined,
53 ) {
54     combined.add(xmlConvertor);
55 };
56 
57 auto XmlArrayConvertors(
58     CombinedConvertor convertor,
59     ByTypePricingStrategy byTypePricingStrategy
60 ) {
61     import std.meta : AliasSeq;
62 
63     static foreach (FromType; AliasSeq!(Element[])) {
64         byTypePricingStrategy.add(typeid(FromType), 900);
65         static foreach (ToType; AliasSeq!(ScalarArrayConvertibleTypes, StringArrayConvertibleTypes)) {
66             byTypePricingStrategy.add(typeid(ToType), 900);
67             convertor.add(new RangeToArrayConvertor!(ToType, FromType)(convertor));
68         }
69     }
70 };
71 
72 alias XmlDocumentContainer = PolicyDocument!(
73     Element,
74     Element,
75     WithContainerScanning!(
76         aermicioi.aedi_property_reader.core.config,
77     )(),
78     WithInitializer!(
79         StdConvStringPrebuiltConvertorsFactory
80     )(),
81     WithConvertorAggregation!CombinedConvertor(),
82     WithContainerScanning!(
83         aermicioi.aedi_property_reader.xml.type_guesser,
84         aermicioi.aedi_property_reader.xml.accessor,
85         aermicioi.aedi_property_reader.xml.inspector,
86         aermicioi.aedi_property_reader.xml.convertor,
87         aermicioi.aedi_property_reader.xml.xml
88     )(),
89     WithLocatorForUnregisteredComponents("xml-document-locator"),
90     WithInitializer!(
91         XmlConvertors
92     )(),
93     WithInitializer!(
94         XmlArrayConvertors
95     )(),
96     WithDefaultRegisterers
97 );
98 
99 /**
100 Create a convertor container with data source being xml document.
101 
102 Params:
103     value = source of data for container to use to construct components.
104     accessor = property accessing logic
105     guesser = type guesser based on held xml value
106     allocator = allocator used to allocate converted values
107 Returns:
108     XmlConvertorContainer
109 **/
110 auto xml(Element value) {
111 
112     XmlDocumentContainer container = XmlDocumentContainer(value);
113 
114     return container;
115 }
116 
117 /**
118 ditto
119 **/
120 auto xml() {
121 
122     return new Document("<root><root>").xml();
123 }
124 
125 
126 /**
127 Create a convertor container with data source being xml document.
128 
129 Params:
130     pathOrData = path to a xml file or xml data itself
131     returnEmpty = wheter to return or not a locator with empty data source
132 Returns:
133     XmlConvertorContainer
134 **/
135 auto xml(string pathOrData, bool returnEmpty = true) {
136     import std.experimental.logger : trace;
137     import std.file : exists, readText;
138     debug(trace) trace("Loading xml document from ", pathOrData);
139 
140     try {
141         debug(trace) trace("Attempting to parse ", pathOrData, " as xml");
142 
143         check(pathOrData);
144 
145         debug(trace) trace("Parsed as xml");
146         return xml(new Document(pathOrData));
147     } catch (CheckException e) {
148 
149         debug(trace) trace(pathOrData, " is does not contain valid xml due to: ", e);
150     }
151 
152     debug(trace) trace("Attempting to parse ", pathOrData, " as xml file");
153     if (pathOrData.exists) {
154 
155         pathOrData = pathOrData.readText();
156 
157         try {
158             check(pathOrData);
159 
160             debug(trace) trace("Parsed as xml");
161             return xml(new Document(pathOrData));
162         } catch(CheckException e) {
163 
164             debug(trace) trace(pathOrData, " does not contain valid xml due to: ", e);
165             if (returnEmpty) {
166                 debug(trace) trace("Returning empty document");
167                 return xml();
168             }
169 
170             throw new Exception(
171                 "Could not create xml convertor container from file or content passed in pathOrData: " ~ pathOrData, e
172             );
173         }
174     }
175 
176     if (returnEmpty) {
177         return xml();
178     }
179 
180     throw new Exception(
181         "Could not create xml convertor container from file or content passed in pathOrData: " ~ pathOrData
182     );
183 }