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
28 package ca.uhn.hl7v2.conf.parser;
29
30 import java.io.BufferedReader;
31 import java.io.File;
32 import java.io.FileNotFoundException;
33 import java.io.FileReader;
34 import java.io.IOException;
35 import java.io.InputStream;
36
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39 import org.w3c.dom.DOMError;
40 import org.w3c.dom.DOMErrorHandler;
41 import org.w3c.dom.Document;
42 import org.w3c.dom.Element;
43 import org.w3c.dom.Node;
44 import org.w3c.dom.NodeList;
45
46 import ca.uhn.hl7v2.conf.ProfileException;
47 import ca.uhn.hl7v2.conf.spec.MetaData;
48 import ca.uhn.hl7v2.conf.spec.RuntimeProfile;
49 import ca.uhn.hl7v2.conf.spec.message.AbstractComponent;
50 import ca.uhn.hl7v2.conf.spec.message.AbstractSegmentContainer;
51 import ca.uhn.hl7v2.conf.spec.message.Component;
52 import ca.uhn.hl7v2.conf.spec.message.DataValue;
53 import ca.uhn.hl7v2.conf.spec.message.Field;
54 import ca.uhn.hl7v2.conf.spec.message.ProfileStructure;
55 import ca.uhn.hl7v2.conf.spec.message.Seg;
56 import ca.uhn.hl7v2.conf.spec.message.SegGroup;
57 import ca.uhn.hl7v2.conf.spec.message.StaticDef;
58 import ca.uhn.hl7v2.conf.spec.message.SubComponent;
59 import ca.uhn.hl7v2.util.XMLUtils;
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89 public class ProfileParser {
90
91 private static final String PROFILE_XSD = "ca/uhn/hl7v2/conf/parser/message_profile.xsd";
92
93 private static final Logger log = LoggerFactory.getLogger(ProfileParser.class);
94
95 private final boolean alwaysValidate;
96 private final DOMErrorHandler errorHandler;
97
98
99
100
101
102
103
104 public ProfileParser(boolean alwaysValidate) {
105
106 this.alwaysValidate = alwaysValidate;
107 this.errorHandler = error -> {
108 if (error.getSeverity() == DOMError.SEVERITY_WARNING) {
109 log.warn("Warning: {}", error.getMessage());
110 } else {
111 throw new RuntimeException((Exception) error.getRelatedException());
112 }
113 return true;
114 };
115 }
116
117
118
119
120
121
122
123
124
125
126
127
128
129 public RuntimeProfile parseClasspath(String classPath) throws ProfileException, IOException {
130
131 InputStream stream = Thread.currentThread().getContextClassLoader()
132 .getResourceAsStream(classPath);
133 if (stream == null) {
134 throw new FileNotFoundException(classPath);
135 }
136
137 StringBuilder profileString = new StringBuilder();
138 byte[] buffer = new byte[1000];
139 int bytesRead;
140 while ((bytesRead = stream.read(buffer)) > 0) {
141 profileString.append(new String(buffer, 0, bytesRead));
142 }
143
144 RuntimeProfile profile = new RuntimeProfile();
145 Document doc = parseIntoDOM(profileString.toString());
146
147 Element root = doc.getDocumentElement();
148 profile.setHL7Version(root.getAttribute("HL7Version"));
149
150
151 NodeList nl = root.getElementsByTagName("HL7v2xStaticDef");
152 Element staticDef = (Element) nl.item(0);
153 StaticDef sd = parseStaticProfile(staticDef);
154 profile.setMessage(sd);
155 return profile;
156 }
157
158
159
160
161 public RuntimeProfile parse(String profileString) throws ProfileException {
162 RuntimeProfile profile = new RuntimeProfile();
163 Document doc = parseIntoDOM(profileString);
164
165 Element root = doc.getDocumentElement();
166 profile.setHL7Version(root.getAttribute("HL7Version"));
167
168 NodeList metadataList = root.getElementsByTagName("MetaData");
169 if (metadataList.getLength() > 0) {
170 Element metadata = (Element) metadataList.item(0);
171 String name = metadata.getAttribute("Name");
172 profile.setName(name);
173 }
174
175
176 NodeList nl = root.getElementsByTagName("HL7v2xStaticDef");
177 Element staticDef = (Element) nl.item(0);
178 StaticDef sd = parseStaticProfile(staticDef);
179 profile.setMessage(sd);
180 return profile;
181 }
182
183 private StaticDef parseStaticProfile(Element elem) throws ProfileException {
184 StaticDef message = new StaticDef();
185 message.setMsgType(elem.getAttribute("MsgType"));
186 message.setEventType(elem.getAttribute("EventType"));
187 message.setMsgStructID(elem.getAttribute("MsgStructID"));
188 message.setOrderControl(elem.getAttribute("OrderControl"));
189 message.setEventDesc(elem.getAttribute("EventDesc"));
190 message.setIdentifier(elem.getAttribute("Identifier"));
191 message.setRole(elem.getAttribute("Role"));
192
193 Element md = getFirstElementByTagName("MetaData", elem);
194 if (md != null)
195 message.setMetaData(parseMetaData(md));
196
197 message.setImpNote(getValueOfFirstElement("ImpNote", elem));
198 message.setDescription(getValueOfFirstElement("Description", elem));
199 message.setReference(getValueOfFirstElement("Reference", elem));
200
201 parseChildren(message, elem);
202 return message;
203 }
204
205
206 private MetaData parseMetaData(Element elem) {
207 log.debug("ProfileParser.parseMetaData() has been called ... note that this method does nothing.");
208 return null;
209 }
210
211
212
213
214 private void parseChildren(AbstractSegmentContainer parent, Element elem)
215 throws ProfileException {
216 int childIndex = 1;
217 NodeList children = elem.getChildNodes();
218 for (int i = 0; i < children.getLength(); i++) {
219 Node n = children.item(i);
220 if (n.getNodeType() == Node.ELEMENT_NODE) {
221 Element child = (Element) n;
222 if (child.getNodeName().equalsIgnoreCase("SegGroup")) {
223 SegGroup group = parseSegmentGroupProfile(child);
224 parent.setChild(childIndex++, group);
225 } else if (child.getNodeName().equalsIgnoreCase("Segment")) {
226 Seg segment = parseSegmentProfile(child);
227 parent.setChild(childIndex++, segment);
228 }
229 }
230 }
231 }
232
233
234 private SegGroup parseSegmentGroupProfile(Element elem) throws ProfileException {
235 SegGroup group = new SegGroup();
236 log.debug("Parsing segment group profile: " + elem.getAttribute("Name"));
237
238 parseProfileStuctureData(group, elem);
239
240 parseChildren(group, elem);
241 return group;
242 }
243
244
245 private Seg parseSegmentProfile(Element elem) throws ProfileException {
246 Seg segment = new Seg();
247 log.debug("Parsing segment profile: " + elem.getAttribute("Name"));
248
249 parseProfileStuctureData(segment, elem);
250
251 int childIndex = 1;
252 NodeList children = elem.getChildNodes();
253 for (int i = 0; i < children.getLength(); i++) {
254 Node n = children.item(i);
255 if (n.getNodeType() == Node.ELEMENT_NODE) {
256 Element child = (Element) n;
257 if (child.getNodeName().equalsIgnoreCase("Field")) {
258 Field field = parseFieldProfile(child);
259 segment.setField(childIndex++, field);
260 }
261 }
262 }
263
264 return segment;
265 }
266
267
268 private void parseProfileStuctureData(ProfileStructure struct, Element elem)
269 throws ProfileException {
270 struct.setName(elem.getAttribute("Name"));
271 struct.setLongName(elem.getAttribute("LongName"));
272 struct.setUsage(elem.getAttribute("Usage"));
273 String min = elem.getAttribute("Min");
274 String max = elem.getAttribute("Max");
275 try {
276 struct.setMin(Short.parseShort(min));
277 if (max.indexOf('*') >= 0) {
278 struct.setMax((short) -1);
279 } else {
280 struct.setMax(Short.parseShort(max));
281 }
282 } catch (NumberFormatException e) {
283 throw new ProfileException("Min and max must be short integers: " + min + ", " + max, e);
284 }
285
286 struct.setImpNote(getValueOfFirstElement("ImpNote", elem));
287 struct.setDescription(getValueOfFirstElement("Description", elem));
288 struct.setReference(getValueOfFirstElement("Reference", elem));
289 struct.setPredicate(getValueOfFirstElement("Predicate", elem));
290 }
291
292
293 private Field parseFieldProfile(Element elem) throws ProfileException {
294 Field field = new Field();
295 log.debug(" Parsing field profile: " + elem.getAttribute("Name"));
296
297 field.setUsage(elem.getAttribute("Usage"));
298 String itemNo = elem.getAttribute("ItemNo");
299 String min = elem.getAttribute("Min");
300 String max = elem.getAttribute("Max");
301
302 try {
303 if (itemNo.length() > 0) {
304 field.setItemNo(Short.parseShort(itemNo));
305 }
306 } catch (NumberFormatException e) {
307 throw new ProfileException("Invalid ItemNo: " + itemNo + "( for name "
308 + elem.getAttribute("Name") + ")", e);
309 }
310
311 try {
312 field.setMin(Short.parseShort(min));
313 if (max.indexOf('*') >= 0) {
314 field.setMax((short) -1);
315 } else {
316 field.setMax(Short.parseShort(max));
317 }
318 } catch (NumberFormatException e) {
319 throw new ProfileException("Min and max must be short integers: " + min + ", " + max, e);
320 }
321
322 parseAbstractComponentData(field, elem);
323
324 int childIndex = 1;
325 NodeList children = elem.getChildNodes();
326 for (int i = 0; i < children.getLength(); i++) {
327 Node n = children.item(i);
328 if (n.getNodeType() == Node.ELEMENT_NODE) {
329 Element child = (Element) n;
330 if (child.getNodeName().equalsIgnoreCase("Component")) {
331 Component comp = (Component) parseComponentProfile(child, false);
332 field.setComponent(childIndex++, comp);
333 }
334 }
335 }
336
337 return field;
338 }
339
340
341 private AbstractComponent<?> parseComponentProfile(Element elem, boolean isSubComponent)
342 throws ProfileException {
343 AbstractComponent<?> comp;
344 if (isSubComponent) {
345 log.debug(" Parsing subcomp profile: " + elem.getAttribute("Name"));
346 comp = new SubComponent();
347 } else {
348 log.debug(" Parsing comp profile: " + elem.getAttribute("Name"));
349 comp = new Component();
350
351 int childIndex = 1;
352 NodeList children = elem.getChildNodes();
353 for (int i = 0; i < children.getLength(); i++) {
354 Node n = children.item(i);
355 if (n.getNodeType() == Node.ELEMENT_NODE) {
356 Element child = (Element) n;
357 if (child.getNodeName().equalsIgnoreCase("SubComponent")) {
358 SubComponent subcomp = (SubComponent) parseComponentProfile(child, true);
359 ((Component) comp).setSubComponent(childIndex++, subcomp);
360 }
361 }
362 }
363 }
364
365 parseAbstractComponentData(comp, elem);
366
367 return comp;
368 }
369
370
371
372
373 private void parseAbstractComponentData(AbstractComponent<?> comp, Element elem)
374 throws ProfileException {
375 comp.setName(elem.getAttribute("Name"));
376 comp.setUsage(elem.getAttribute("Usage"));
377 comp.setDatatype(elem.getAttribute("Datatype"));
378 String length = elem.getAttribute("Length");
379 if (length != null && length.length() > 0) {
380 try {
381 comp.setLength(Long.parseLong(length));
382 } catch (NumberFormatException e) {
383 throw new ProfileException("Length must be a long integer: " + length, e);
384 }
385 }
386 comp.setConstantValue(elem.getAttribute("ConstantValue"));
387 String table = elem.getAttribute("Table");
388 if (table != null && table.length() > 0) {
389 try {
390 comp.setTable(table);
391 } catch (NumberFormatException e) {
392 throw new ProfileException("Table must be a short integer: " + table, e);
393 }
394 }
395
396 comp.setImpNote(getValueOfFirstElement("ImpNote", elem));
397 comp.setDescription(getValueOfFirstElement("Description", elem));
398 comp.setReference(getValueOfFirstElement("Reference", elem));
399 comp.setPredicate(getValueOfFirstElement("Predicate", elem));
400
401 int dataValIndex = 0;
402 NodeList children = elem.getChildNodes();
403 for (int i = 0; i < children.getLength(); i++) {
404 Node n = children.item(i);
405 if (n.getNodeType() == Node.ELEMENT_NODE) {
406 Element child = (Element) n;
407 if (child.getNodeName().equalsIgnoreCase("DataValues")) {
408 DataValue val = new DataValue();
409 val.setExValue(child.getAttribute("ExValue"));
410 comp.setDataValues(dataValIndex++, val);
411 }
412 }
413 }
414
415 }
416
417
418 private Document parseIntoDOM(String profileString) throws ProfileException {
419 try {
420 Document doc = XMLUtils.parse(profileString, true);
421 if (alwaysValidate)
422 XMLUtils.validate(doc, PROFILE_XSD, errorHandler);
423 return doc;
424 } catch (Exception e) {
425 throw new ProfileException("Exception parsing message profile: " + e.getMessage(), e);
426 }
427 }
428
429
430
431
432
433 private Element getFirstElementByTagName(String name, Element parent) {
434 NodeList nl = parent.getElementsByTagName(name);
435 Element ret = null;
436 if (nl.getLength() > 0) {
437 ret = (Element) nl.item(0);
438 }
439 return ret;
440 }
441
442
443
444
445 private String getValueOfFirstElement(String name, Element parent) throws ProfileException {
446 Element el = getFirstElementByTagName(name, parent);
447 String val = null;
448 if (el != null) {
449 try {
450 Node n = el.getFirstChild();
451 if (n.getNodeType() == Node.TEXT_NODE) {
452 val = n.getNodeValue();
453 }
454 } catch (Exception e) {
455 throw new ProfileException("Unable to get value of node " + name, e);
456 }
457 }
458 return val;
459 }
460
461 public static void main(String[] args) {
462
463 if (args.length != 1) {
464 System.out.println("Usage: ProfileParser profile_file");
465 System.exit(1);
466 }
467
468 try {
469
470
471 File f = new File(args[0]);
472 @SuppressWarnings("resource")
473 BufferedReader in = new BufferedReader(new FileReader(f));
474 char[] cbuf = new char[(int) f.length()];
475 in.read(cbuf, 0, (int) f.length());
476 String xml = String.valueOf(cbuf);
477
478
479 ProfileParser pp = new ProfileParser(true);
480 pp.parse(xml);
481 } catch (Exception e) {
482 e.printStackTrace();
483 }
484 }
485
486 }