| 1 | |
package ca.uhn.hl7v2.preparser; |
| 2 | |
|
| 3 | |
import java.util.ArrayList; |
| 4 | |
import java.util.Iterator; |
| 5 | |
import java.util.List; |
| 6 | |
import java.util.Map; |
| 7 | |
import java.util.Properties; |
| 8 | |
import java.util.SortedMap; |
| 9 | |
import java.util.StringTokenizer; |
| 10 | |
import java.util.TreeMap; |
| 11 | |
|
| 12 | |
import ca.uhn.hl7v2.parser.EncodingCharacters; |
| 13 | |
|
| 14 | |
|
| 15 | |
|
| 16 | |
|
| 17 | |
|
| 18 | |
|
| 19 | |
|
| 20 | |
|
| 21 | |
|
| 22 | |
|
| 23 | |
|
| 24 | |
|
| 25 | |
|
| 26 | |
|
| 27 | |
|
| 28 | |
|
| 29 | |
|
| 30 | |
|
| 31 | |
|
| 32 | |
|
| 33 | |
|
| 34 | |
|
| 35 | |
public class ER7 { |
| 36 | |
|
| 37 | 0 | private ER7() {} |
| 38 | |
|
| 39 | |
|
| 40 | |
|
| 41 | |
|
| 42 | |
static final String segmentSeparators = "\r\n\f"; |
| 43 | |
|
| 44 | |
|
| 45 | |
|
| 46 | |
|
| 47 | |
public static boolean parseMessage( Properties props, |
| 48 | |
List<DatumPath> msgMask, String message) |
| 49 | |
{ |
| 50 | 385 | boolean ok = false; |
| 51 | 385 | if(message != null) { |
| 52 | 385 | if(props == null) |
| 53 | 0 | props = new Properties(); |
| 54 | |
|
| 55 | 385 | StringTokenizer messageTokenizer |
| 56 | |
= new StringTokenizer(message, segmentSeparators); |
| 57 | 385 | if(messageTokenizer.hasMoreTokens()) { |
| 58 | 385 | String firstSegment = messageTokenizer.nextToken(); |
| 59 | 385 | EncodingCharacters encodingChars = new EncodingCharacters('0', "0000"); |
| 60 | 385 | if(parseMSHSegmentWhole(props, msgMask, encodingChars, firstSegment)) { |
| 61 | 380 | ok = true; |
| 62 | 380 | SortedMap<String, Integer> segmentId2nextRepIdx = new TreeMap<String, Integer>(); |
| 63 | 380 | segmentId2nextRepIdx.put(new String("MSH"), 1); |
| 64 | |
|
| 65 | 810 | while(messageTokenizer.hasMoreTokens()) { |
| 66 | 860 | parseSegmentWhole(props, segmentId2nextRepIdx, |
| 67 | 430 | msgMask, encodingChars, messageTokenizer.nextToken()); |
| 68 | |
} |
| 69 | |
} |
| 70 | |
} |
| 71 | |
} |
| 72 | 385 | return ok; |
| 73 | |
} |
| 74 | |
|
| 75 | |
|
| 76 | |
|
| 77 | |
|
| 78 | |
protected static boolean parseMSHSegmentWhole( Properties props, |
| 79 | |
List<DatumPath> msgMask, EncodingCharacters encodingChars, |
| 80 | |
String segment) |
| 81 | |
{ |
| 82 | 385 | boolean ret = false; |
| 83 | |
try { |
| 84 | 385 | ER7SegmentHandler handler = new ER7SegmentHandler(); |
| 85 | 385 | handler.m_props = props; |
| 86 | 385 | handler.m_encodingChars = encodingChars; |
| 87 | 385 | handler.m_segmentId = "MSH"; |
| 88 | 385 | handler.m_segmentRepIdx = 0; |
| 89 | 385 | if(msgMask != null) |
| 90 | 385 | handler.m_msgMask = msgMask; |
| 91 | |
else { |
| 92 | 0 | handler.m_msgMask = new ArrayList<DatumPath>(); |
| 93 | 0 | handler.m_msgMask.add(new DatumPath()); |
| 94 | |
|
| 95 | |
} |
| 96 | |
|
| 97 | 385 | encodingChars.setFieldSeparator(segment.charAt(3)); |
| 98 | 385 | List<Integer> nodeKey = new ArrayList<Integer>(); |
| 99 | 385 | nodeKey.add(new Integer(0)); |
| 100 | 385 | handler.putDatum(nodeKey, String.valueOf(encodingChars.getFieldSeparator())); |
| 101 | 385 | encodingChars.setComponentSeparator(segment.charAt(4)); |
| 102 | 385 | encodingChars.setRepetitionSeparator(segment.charAt(5)); |
| 103 | 385 | encodingChars.setEscapeCharacter(segment.charAt(6)); |
| 104 | 385 | encodingChars.setSubcomponentSeparator(segment.charAt(7)); |
| 105 | 385 | nodeKey.set(0, new Integer(1)); |
| 106 | 385 | handler.putDatum(nodeKey, encodingChars.toString()); |
| 107 | |
|
| 108 | 385 | if(segment.charAt(8) == encodingChars.getFieldSeparator()) { |
| 109 | 380 | ret = true; |
| 110 | |
|
| 111 | |
|
| 112 | 380 | nodeKey.clear(); |
| 113 | 380 | nodeKey.add(new Integer(2)); |
| 114 | 380 | parseSegmentGuts(handler, segment.substring(9), nodeKey); |
| 115 | |
} |
| 116 | |
} |
| 117 | 0 | catch(IndexOutOfBoundsException e) {} |
| 118 | 385 | catch(NullPointerException e) {} |
| 119 | |
|
| 120 | 385 | return ret; |
| 121 | |
} |
| 122 | |
|
| 123 | |
|
| 124 | |
|
| 125 | |
|
| 126 | |
protected static void parseSegmentWhole( Properties props, |
| 127 | |
Map<String, Integer> segmentId2nextRepIdx, |
| 128 | |
List<DatumPath> msgMask, EncodingCharacters encodingChars, |
| 129 | |
String segment) |
| 130 | |
{ |
| 131 | |
try { |
| 132 | 430 | String segmentId = segment.substring(0, 3); |
| 133 | |
|
| 134 | 430 | int currentSegmentRepIdx = 0; |
| 135 | 430 | if(segmentId2nextRepIdx.containsKey(segmentId)) |
| 136 | 40 | currentSegmentRepIdx = ((Integer)segmentId2nextRepIdx.get(segmentId)).intValue(); |
| 137 | |
else |
| 138 | 390 | currentSegmentRepIdx = 0; |
| 139 | 430 | segmentId2nextRepIdx.put(segmentId, new Integer(currentSegmentRepIdx+1)); |
| 140 | |
|
| 141 | |
|
| 142 | |
|
| 143 | 430 | boolean parseThisSegment = false; |
| 144 | 430 | DatumPath segmentIdAsDatumPath = new DatumPath().add(segmentId); |
| 145 | 430 | for(Iterator<DatumPath> maskIt = msgMask.iterator(); !parseThisSegment && maskIt.hasNext(); ) |
| 146 | 685 | parseThisSegment = segmentIdAsDatumPath.startsWith(maskIt.next()); |
| 147 | 430 | for(Iterator<DatumPath> maskIt = msgMask.iterator(); !parseThisSegment && maskIt.hasNext(); ) |
| 148 | 645 | parseThisSegment = maskIt.next().startsWith(segmentIdAsDatumPath); |
| 149 | |
|
| 150 | 430 | if(parseThisSegment && (segment.charAt(3) == encodingChars.getFieldSeparator())) { |
| 151 | 160 | ER7SegmentHandler handler = new ER7SegmentHandler(); |
| 152 | 160 | handler.m_props = props; |
| 153 | 160 | handler.m_encodingChars = encodingChars; |
| 154 | 160 | handler.m_segmentId = segmentId; |
| 155 | 160 | handler.m_msgMask = msgMask; |
| 156 | 160 | handler.m_segmentRepIdx = currentSegmentRepIdx; |
| 157 | |
|
| 158 | 160 | List<Integer> nodeKey = new ArrayList<Integer>(); |
| 159 | 160 | nodeKey.add(new Integer(0)); |
| 160 | 160 | parseSegmentGuts(handler, segment.substring(4), nodeKey); |
| 161 | |
} |
| 162 | |
} |
| 163 | 0 | catch(NullPointerException e) {} |
| 164 | 430 | catch(IndexOutOfBoundsException e) {} |
| 165 | 430 | } |
| 166 | |
|
| 167 | |
static protected interface Handler |
| 168 | |
{ |
| 169 | |
public int specDepth(); |
| 170 | |
public char delim(int level); |
| 171 | |
|
| 172 | |
public void putDatum(List<Integer> nodeKey, String value); |
| 173 | |
} |
| 174 | |
|
| 175 | 545 | static protected class ER7SegmentHandler implements Handler |
| 176 | |
{ |
| 177 | |
Properties m_props; |
| 178 | |
|
| 179 | |
EncodingCharacters m_encodingChars; |
| 180 | |
|
| 181 | |
String m_segmentId; |
| 182 | |
int m_segmentRepIdx; |
| 183 | |
|
| 184 | |
List<DatumPath> m_msgMask; |
| 185 | |
|
| 186 | 15240 | public int specDepth() {return 4;} |
| 187 | |
|
| 188 | |
public char delim(int level) |
| 189 | |
{ |
| 190 | 11400 | if(level == 0) |
| 191 | 540 | return m_encodingChars.getFieldSeparator(); |
| 192 | 10860 | else if(level == 1) |
| 193 | 3230 | return m_encodingChars.getRepetitionSeparator(); |
| 194 | 7630 | else if(level == 2) |
| 195 | 3280 | return m_encodingChars.getComponentSeparator(); |
| 196 | 4350 | else if(level == 3) |
| 197 | 4350 | return m_encodingChars.getSubcomponentSeparator(); |
| 198 | 0 | else if(level == 4) |
| 199 | 0 | return m_encodingChars.getTruncationCharacter(); |
| 200 | |
else |
| 201 | 0 | throw new java.lang.Error(); |
| 202 | |
} |
| 203 | |
|
| 204 | |
public void putDatum(List<Integer> valNodeKey, String value) |
| 205 | |
{ |
| 206 | |
|
| 207 | 5150 | DatumPath valDatumPath = new DatumPath(); |
| 208 | 5150 | valDatumPath.add(m_segmentId).add(m_segmentRepIdx); |
| 209 | 23440 | for(int i=0; i<valNodeKey.size(); ++i) { |
| 210 | |
|
| 211 | 18290 | int itval = ((Integer)valNodeKey.get(i)).intValue(); |
| 212 | 18290 | valDatumPath.add(new Integer(i == 1 ? itval : itval+1)); |
| 213 | |
} |
| 214 | |
|
| 215 | |
|
| 216 | 5150 | boolean valDatumPathPassesMask = false; |
| 217 | 5150 | for(Iterator<DatumPath> maskIt = m_msgMask.iterator(); |
| 218 | 13250 | !valDatumPathPassesMask && maskIt.hasNext(); ) |
| 219 | |
{ |
| 220 | 8100 | valDatumPathPassesMask = valDatumPath.startsWith(maskIt.next()); |
| 221 | |
} |
| 222 | |
|
| 223 | 5150 | if(valDatumPathPassesMask) |
| 224 | 330 | m_props.setProperty(valDatumPath.toString(), value); |
| 225 | 5150 | } |
| 226 | |
} |
| 227 | |
|
| 228 | |
|
| 229 | |
|
| 230 | |
|
| 231 | |
|
| 232 | |
|
| 233 | |
|
| 234 | |
|
| 235 | |
|
| 236 | |
|
| 237 | |
|
| 238 | |
|
| 239 | |
protected static void parseSegmentGuts( Handler handler, |
| 240 | |
String guts, List<Integer> nodeKey) |
| 241 | |
{ |
| 242 | 11400 | char thisDepthsDelim = handler.delim(nodeKey.size()-1); |
| 243 | |
|
| 244 | |
|
| 245 | 11400 | StringTokenizer gutsTokenizer |
| 246 | 11400 | = new StringTokenizer(guts, String.valueOf(thisDepthsDelim), true); |
| 247 | 34560 | while(gutsTokenizer.hasMoreTokens()) { |
| 248 | 23160 | String gutsToken = gutsTokenizer.nextToken(); |
| 249 | |
|
| 250 | 23160 | if(gutsToken.charAt(0) == thisDepthsDelim) { |
| 251 | |
|
| 252 | |
|
| 253 | 7920 | int oldvalue = ((Integer)nodeKey.get(nodeKey.size()-1)).intValue(); |
| 254 | 7920 | nodeKey.set(nodeKey.size()-1, new Integer(oldvalue + gutsToken.length())); |
| 255 | 7920 | } |
| 256 | |
else { |
| 257 | 15240 | if(nodeKey.size() < handler.specDepth()) { |
| 258 | 10860 | nodeKey.add(new Integer(0)); |
| 259 | 10860 | parseSegmentGuts(handler, gutsToken, nodeKey); |
| 260 | 10860 | nodeKey.remove(nodeKey.size()-1); |
| 261 | |
} |
| 262 | |
else |
| 263 | 4380 | handler.putDatum(nodeKey, gutsToken); |
| 264 | |
} |
| 265 | 23160 | } |
| 266 | |
|
| 267 | 11400 | } |
| 268 | |
|
| 269 | |
public static void main(String args[]) |
| 270 | |
{ |
| 271 | 0 | if(args.length >= 1) { |
| 272 | |
|
| 273 | 0 | System.out.println(args[0]); |
| 274 | |
|
| 275 | 0 | Properties props = new Properties(); |
| 276 | |
|
| 277 | 0 | List<DatumPath> msgMask = new ArrayList<DatumPath>(); |
| 278 | 0 | msgMask.add(new DatumPath()); |
| 279 | |
|
| 280 | 0 | System.err.println("ER7.parseMessage returned " + parseMessage(props, msgMask, args[0])); |
| 281 | 0 | props.list(System.out); |
| 282 | |
} |
| 283 | 0 | } |
| 284 | |
|
| 285 | |
} |
| 286 | |
|