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 ca.uhn.hl7v2.sourcegen;
28
29 import java.io.*;
30 import java.net.URL;
31 import java.nio.charset.StandardCharsets;
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.Iterator;
35 import java.util.List;
36
37 import ca.uhn.hl7v2.Version;
38 import ca.uhn.hl7v2.parser.DefaultModelClassFactory;
39 import ca.uhn.hl7v2.sourcegen.util.VelocityFactory;
40 import com.sun.xml.xsom.*;
41 import com.sun.xml.xsom.parser.XSOMParser;
42 import org.apache.velocity.Template;
43 import org.apache.velocity.VelocityContext;
44 import org.apache.velocity.context.Context;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47
48
49
50
51
52
53
54
55
56
57 public class XsdSegmentGenerator {
58
59 private static final Logger LOG = LoggerFactory.getLogger(XsdSegmentGenerator.class);
60 private static final String[] EXCLUDE_SEGMENTS = {"anyHL7Segment", "anyZSegment"};
61
62 public static final String URN_HL7_ORG_V2XML = "urn:hl7-org:v2xml";
63
64 private final String templatePackage;
65 private final String targetDirectory;
66
67 public XsdSegmentGenerator(String dir, String templatePackage) throws IOException {
68 File f = new File(dir);
69 if (!f.isDirectory())
70 throw new IOException("Can't create file in " + dir + " - it is not a directory.");
71 this.targetDirectory = dir;
72 this.templatePackage = templatePackage.replace(".", "/");
73 }
74
75 public void parse(Version version) throws Exception {
76 XSOMParser parser = new XSOMParser();
77 String dir = String.format("/hl7v2xsd/%s/segments.xsd", version.getVersion());
78 URL url = getClass().getResource(dir);
79 parser.parse(url);
80 XSSchemaSet result = parser.getResult();
81 Iterator<XSSchema> iter = result.iterateSchema();
82 while (iter.hasNext()) {
83 XSSchema schema = iter.next();
84 if (URN_HL7_ORG_V2XML.equals(schema.getTargetNamespace())) {
85 parseSegments(schema, version);
86 }
87 }
88 }
89
90
91
92
93
94
95
96
97 private void parseSegments(XSSchema schema, Version version) throws Exception {
98
99 Template template = VelocityFactory.getClasspathTemplateInstance(templatePackage + "/segment.vsm");
100 String basePackageName = DefaultModelClassFactory.getVersionPackageName(version.getVersion());
101 String[] datatypePackages = { basePackageName + "datatype" };
102
103 Iterator<XSElementDecl> segmentDecls = schema.iterateElementDecls();
104 while (segmentDecls.hasNext()) {
105 XSElementDecl segmentDecl = segmentDecls.next();
106 String segmentName = segmentDecl.getName();
107 if (isRealSegment(segmentName)) {
108
109 List<SegmentElement> segmentsElements = new ArrayList<>();
110 XSComplexType complexType = segmentDecl.getType().asComplexType();
111
112 XSParticle[] children = complexType
113 .getContentType()
114 .asParticle()
115 .getTerm()
116 .asModelGroup()
117 .getChildren();
118 LOG.debug("Creating segment {}, having {} children", segmentName, children.length);
119 for (int i = 0; i < children.length; i++) {
120
121 if (!children[i].getTerm().isWildcard()) {
122 XSAttGroupDecl attrGroup = children[i]
123 .getTerm()
124 .asElementDecl()
125 .getType()
126 .asComplexType()
127 .getAttGroups().iterator().next();
128 LOG.debug("Field {}", attrGroup.getName());
129 String fieldType = attrGroup.getAttributeUse("", "Type").getFixedValue().toString();
130 String fieldDescription = attrGroup.getAttributeUse("", "LongName").getFixedValue().toString();
131 XSAttributeUse fieldLength = attrGroup.getAttributeUse("", "maxLength");
132 int maxLength = 0;
133 if (fieldLength != null)
134 maxLength = Integer.parseInt(fieldLength.getFixedValue().toString());
135 XSAttributeUse fieldTable = attrGroup.getAttributeUse("", "Table");
136 int table = 0;
137 if (fieldTable != null)
138 table = Integer.parseInt(fieldTable.getFixedValue().toString().substring(3));
139 SegmentElementement.html#SegmentElement">SegmentElement se = new SegmentElement(segmentName, version.getVersion(), i);
140 se.field = i;
141 if (children[i].getMaxOccurs().intValue() == XSParticle.UNBOUNDED) {
142 se.rep = "Y";
143 se.repetitions = 0;
144 } else {
145 se.rep = "N";
146 se.repetitions = 1;
147 }
148 se.opt = children[i].getMinOccurs().intValue() > 0 ? "R" : "O";
149 se.desc = fieldDescription;
150 se.table = table;
151 se.type = fieldType;
152 fixType(i + 1, version, se);
153 se.length = maxLength;
154 segmentsElements.add(se);
155 }
156 }
157
158 writeSegment(template, basePackageName, datatypePackages,
159 segmentName, segmentName, version, segmentsElements);
160 }
161
162 }
163
164 }
165
166 private void writeSegment(Template template, String basePackageName, String[] datatypePackages,
167 String segmentName, String segmentDescription, Version version,
168 List<SegmentElement> segmentsElements) throws Exception {
169 String source = make(template, basePackageName, datatypePackages,
170 segmentName, segmentDescription, version.getVersion(), segmentsElements);
171 if (source != null) {
172 writeFile(source, segmentName, version);
173 }
174 }
175
176
177
178
179
180
181
182
183
184 private static void fixType(int index, Version version, SegmentElement se) {
185
186 if (se.type.equals("NUL") || se.type.equals("-")) {
187 se.type = "NULLDT";
188
189
190 } else if (version == Version.V23 && se.type.equals("MRG") && index == 7) {
191 se.type = "XPN";
192
193
194 } else if (version == Version.V23 && se.type.equals("ORC") && index == 14) {
195 se.type = "XTN";
196
197
198 } else if (version == Version.V23 && se.type.equals("PID") && index == 5) {
199 se.rep = "Y";
200 se.repetitions = -1;
201 }
202 }
203
204 private boolean isRealSegment(String dataTypeName) {
205 return Arrays.binarySearch(EXCLUDE_SEGMENTS, dataTypeName) < 0 &&
206 dataTypeName.indexOf('.') < 0;
207 }
208
209 private void writeFile(String source, String segmentName, Version version) throws IOException {
210
211 String dirName = String.format("%s/ca/uhn/hl7v2/model/%s/segment/", targetDirectory, version.getPackageVersion());
212 File dir = new File(dirName);
213 if (!dir.exists()) {
214 dir.mkdirs();
215 }
216 String targetFile = String.format("%s/%s.java", dirName, segmentName);
217
218 try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(targetFile, false), StandardCharsets.UTF_8))) {
219 writer.write(source);
220 writer.flush();
221 }
222 }
223
224 private String make(Template template, String normalBasePackageName, String[] datatypePackages,
225 String segmentName, String description, String version, List<SegmentElement> elements) {
226 StringWriter out = new StringWriter();
227 Context ctx = new VelocityContext();
228 ctx.put("segmentName", segmentName);
229 ctx.put("typeDescription", description);
230 ctx.put("basePackageName", normalBasePackageName);
231 ctx.put("elements", elements);
232 ctx.put("datatypePackages", datatypePackages);
233 ctx.put("hl7VersionInQuotes", '"' + version + '"');
234
235 template.merge(ctx, out);
236 return out.toString();
237 }
238
239
240 public static void main(String... args) {
241 try {
242 XsdSegmentGeneratortor.html#XsdSegmentGenerator">XsdSegmentGenerator xdtg = new XsdSegmentGenerator("C:/temp", "/ca.uhn.hl7v2.sourcegen.templates");
243 long start = System.currentTimeMillis();
244
245
246
247
248 xdtg.parse(Version.V25);
249 System.out.println("Done in " + (System.currentTimeMillis() - start) + " ms.");
250 } catch (Exception e) {
251 e.printStackTrace();
252 }
253 }
254
255 }