1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package com.rapiddweller.platform.xml;
28
29 import com.rapiddweller.benerator.engine.BeneratorContext;
30 import com.rapiddweller.benerator.storage.AbstractStorageSystem;
31 import com.rapiddweller.common.CollectionUtil;
32 import com.rapiddweller.common.Context;
33 import com.rapiddweller.common.NullSafeComparator;
34 import com.rapiddweller.common.collection.OrderedNameMap;
35 import com.rapiddweller.common.context.ContextAware;
36 import com.rapiddweller.common.xml.XMLUtil;
37 import com.rapiddweller.common.xml.XPathUtil;
38 import com.rapiddweller.format.DataSource;
39 import com.rapiddweller.format.util.DataSourceFromIterable;
40 import com.rapiddweller.model.data.ComplexTypeDescriptor;
41 import com.rapiddweller.model.data.Entity;
42 import com.rapiddweller.model.data.TypeDescriptor;
43 import com.rapiddweller.script.PrimitiveType;
44 import org.apache.logging.log4j.LogManager;
45 import org.apache.logging.log4j.Logger;
46 import org.w3c.dom.Document;
47 import org.w3c.dom.Element;
48 import org.w3c.dom.Node;
49 import org.w3c.dom.NodeList;
50
51 import javax.xml.xpath.XPathExpressionException;
52 import java.io.File;
53 import java.io.FileNotFoundException;
54 import java.io.IOException;
55 import java.util.ArrayList;
56 import java.util.List;
57
58
59
60
61
62
63
64
65
66 public class DOMTree extends AbstractStorageSystem implements ContextAware {
67
68 private static final Logger LOGGER = LogManager.getLogger(DOMTree.class);
69
70 private String id;
71 private String inputUri;
72 private String outputUri;
73 private boolean namespaceAware;
74
75 private Context context;
76 private Document document;
77 private final OrderedNameMap<ComplexTypeDescriptor> types;
78
79
80
81
82
83 public DOMTree() {
84 this(null, null);
85 }
86
87
88
89
90
91
92
93 public DOMTree(String inOutUri, BeneratorContext context) {
94 this.id = inOutUri;
95 this.inputUri = inOutUri;
96 this.outputUri = inOutUri;
97 this.namespaceAware = true;
98 this.document = null;
99 this.types = OrderedNameMap.createCaseInsensitiveMap();
100 setContext(context);
101 }
102
103 private static String normalizeEncoding(String encoding) {
104 if (encoding.startsWith("UTF-16")) {
105 encoding = "UTF-16";
106 }
107 return encoding;
108 }
109
110 @Override
111 public String getId() {
112 return id;
113 }
114
115
116
117
118
119
120 public void setId(String id) {
121 this.id = id;
122 }
123
124
125
126
127
128
129 public String getInputUri() {
130 return inputUri;
131 }
132
133
134
135
136
137
138 public void setInputUri(String inputUri) {
139 this.inputUri = inputUri;
140 }
141
142
143
144
145
146
147 public String getOutputUri() {
148 return outputUri;
149 }
150
151
152
153
154
155
156 public void setOutputUri(String outputUri) {
157 this.outputUri = outputUri;
158 }
159
160
161
162
163
164
165 public boolean isNamespaceAware() {
166 return namespaceAware;
167 }
168
169
170
171
172
173
174 public void setNamespaceAware(boolean namespaceAware) {
175 this.namespaceAware = namespaceAware;
176 }
177
178 @Override
179 public void setContext(Context context) {
180 this.context = context;
181 if (context instanceof BeneratorContext) {
182 setDataModel(((BeneratorContext) context).getDataModel());
183 }
184 }
185
186 @Override
187 public DataSource<Entity> queryEntities(String type, String selector,
188 Context context) {
189 beInitialized();
190 LOGGER.debug("queryEntities({}, {}, context)", type, selector);
191 try {
192 NodeList nodes = XPathUtil.queryNodes(document, selector);
193 LOGGER.debug("queryEntities() found {} results", nodes.getLength());
194 List<Entity> list = new ArrayList<>(nodes.getLength());
195 for (int i = 0; i < nodes.getLength(); i++) {
196 Element element = (Element) nodes.item(i);
197 Entity entity =
198 XMLPlatformUtil.convertElement2Entity(element, this);
199 list.add(entity);
200 }
201 return new DataSourceFromIterable<>(list, Entity.class);
202 } catch (XPathExpressionException e) {
203 throw new RuntimeException(
204 "Error querying " + (type != null ? type : "") +
205 " elements with xpath: " + selector, e);
206 }
207 }
208
209 @Override
210 public DataSource<?> queryEntityIds(String type, String selector,
211 Context context) {
212 throw new UnsupportedOperationException(getClass().getSimpleName() +
213 " does not support queries for entity ids");
214 }
215
216 @Override
217 public DataSource<?> query(String selector, boolean simplify,
218 Context context) {
219 beInitialized();
220 LOGGER.debug("query({}, {}, context)", selector, simplify);
221 try {
222 NodeList nodes = XPathUtil.queryNodes(document, selector);
223 LOGGER.debug("query() found {} results", nodes.getLength());
224 List<Object> list = new ArrayList<>(nodes.getLength());
225 for (int i = 0; i < nodes.getLength(); i++) {
226 Node node = nodes.item(i);
227 list.add(node.getTextContent());
228 }
229 return new DataSourceFromIterable<>(list, Object.class);
230 } catch (XPathExpressionException e) {
231 throw new RuntimeException(
232 "Error querying items with xpath: " + selector, e);
233 }
234 }
235
236 @Override
237 public void store(Entity entity) {
238 throw new UnsupportedOperationException(getClass().getSimpleName() +
239 " does not support storing entities");
240 }
241
242 @Override
243 public void update(Entity entity) {
244 beInitialized();
245 if (entity instanceof XmlEntity) {
246 XMLPlatformUtil.mapEntityToElement(entity,
247 ((XmlEntity) entity).getSourceElement());
248 } else {
249 throw new UnsupportedOperationException(getClass().getSimpleName() +
250 " cannot update entities from other sources");
251 }
252 }
253
254 @Override
255 public void flush() {
256
257 }
258
259 @Override
260 public void close() {
261 if (document != null) {
262 save();
263 } else {
264
265 }
266 }
267
268 @Override
269 public TypeDescriptor[] getTypeDescriptors() {
270 return CollectionUtil.toArray(types.values(), TypeDescriptor.class);
271 }
272
273 @Override
274 public TypeDescriptor getTypeDescriptor(String typeName) {
275 if (PrimitiveType.getInstance(typeName) != null) {
276 return null;
277 }
278 ComplexTypeDescriptor type = types.get(typeName);
279 if (type == null) {
280 type = new ComplexTypeDescriptor(typeName, this);
281 types.put(typeName, type);
282 }
283 return type;
284 }
285
286
287
288
289
290
291
292 public void save() {
293 try {
294 String encoding = normalizeEncoding(document.getInputEncoding());
295 File uri = new File(resolveUri(outputUri));
296 XMLUtil.saveDocument(document, uri, encoding);
297 } catch (FileNotFoundException e) {
298 throw new RuntimeException("Error writing DOMTree to " + outputUri,
299 e);
300 }
301 }
302
303 private void beInitialized() {
304 if (this.document == null) {
305 init();
306 }
307 }
308
309 private void init() {
310 try {
311 this.document =
312 XMLUtil.parse(resolveUri(inputUri), namespaceAware, null,
313 null, null);
314 System.out.println(
315 this.document.getDocumentElement().getNamespaceURI());
316 } catch (IOException e) {
317 throw new RuntimeException("Error parsing " + inputUri, e);
318 }
319 }
320
321 private String resolveUri(String uri) {
322 return (context instanceof BeneratorContext ?
323 ((BeneratorContext) context).resolveRelativeUri(uri) : uri);
324 }
325
326 @Override
327 public String toString() {
328 return getClass().getSimpleName() + "[" + inputUri +
329 (NullSafeComparator.equals(inputUri, outputUri) ? "" :
330 " -> " + outputUri) + "]";
331 }
332
333 }