Java tutorial
/* * Copyright (c) Mirth Corporation. All rights reserved. * * http://www.mirthcorp.com * * The software in this package is published under the terms of the MPL license a copy of which has * been included with this distribution in the LICENSE.txt file. */ package com.mirth.connect.plugins.datatypes.hl7v2; import java.io.BufferedReader; import java.io.IOException; import java.util.StringTokenizer; import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; import org.apache.xerces.parsers.SAXParser; import org.xml.sax.ContentHandler; import org.xml.sax.InputSource; import org.xml.sax.SAXException; public class ER7Reader extends SAXParser { private Logger logger = Logger.getLogger(this.getClass()); private boolean handleRepetitions = false; private boolean handleSubcomponents = false; private String segmentDelimiter; private static final char[] EMPTY_CHAR_ARRAY = "".toCharArray(); private static final String DEFAULT_FIELD_SEPARATOR = "|"; private static final String DEFAULT_COMPONENT_SEPARATOR = "^"; private static final String DEFAULT_REPETITION_SEPARATOR = "~"; private static final String DEFAULT_ESCAPE_CHARACTER = ""; private static final String DEFAULT_SUBCOMPONENT_TERMINATOR = ""; public static final String MESSAGE_ROOT_ID = "HL7Message"; public ER7Reader(boolean handleRepetitions, boolean handleSubcomponents, String segmentDelimiter) { this.handleRepetitions = handleRepetitions; this.handleSubcomponents = handleSubcomponents; this.segmentDelimiter = segmentDelimiter; } private String getMessageFromSource(InputSource source) throws IOException { BufferedReader reader = new BufferedReader(source.getCharacterStream()); StringBuilder builder = new StringBuilder(); int c; while ((c = reader.read()) != -1) { builder.append((char) c); } return builder.toString().trim(); } public void parse(InputSource source) throws SAXException, IOException { String message = getMessageFromSource(source); ContentHandler contentHandler = getContentHandler(); contentHandler.startDocument(); // first tokenize the segments if ((message == null) || (message.length() < 6)) { throw new SAXException("Unable to parse message. It is NULL or too short. " + message); } // usually | String fieldSeparator = DEFAULT_FIELD_SEPARATOR; String componentSeparator = DEFAULT_COMPONENT_SEPARATOR; String repetitionSeparator = DEFAULT_REPETITION_SEPARATOR; String escapeCharacter = DEFAULT_ESCAPE_CHARACTER; String subcomponentSeparator = DEFAULT_SUBCOMPONENT_TERMINATOR; // if we have a header, grab the actual separators from the message String firstSegment = message.substring(0, 3); if (firstSegment.equalsIgnoreCase("MSH") || firstSegment.equalsIgnoreCase("FHS") || firstSegment.equalsIgnoreCase("BHS")) { fieldSeparator = new String(new char[] { message.charAt(3) }); int nextDelimiter = message.indexOf(message.charAt(3), 4); if (nextDelimiter == -1) { // If the message is just MSH|^~\&, we still want to extract the encoding characters nextDelimiter = message.length(); } if (nextDelimiter > 4) { // usually ^ componentSeparator = new String(new char[] { message.charAt(4) }); } if (nextDelimiter > 5) { // usually ~ repetitionSeparator = new String(new char[] { message.charAt(5) }); } if (nextDelimiter > 6) { // usually \ escapeCharacter = new String(new char[] { message.charAt(6) }); } if (nextDelimiter > 7) { // usually & subcomponentSeparator = new String(new char[] { message.charAt(7) }); } } // replace the special case of ^~& with ^~\& (MIRTH-1544) if (message.length() >= 8 && "^~&|".equals(message.substring(4, 8))) { escapeCharacter = "\\"; subcomponentSeparator = "&"; repetitionSeparator = "~"; componentSeparator = "^"; } // tokenize the segments first String[] segments = StringUtils.split(message, segmentDelimiter); String documentHead = handleSegments("", contentHandler, fieldSeparator, componentSeparator, subcomponentSeparator, repetitionSeparator, escapeCharacter, segments); contentHandler.endElement("", documentHead, ""); contentHandler.endDocument(); } private String handleSegments(String documentHead, ContentHandler contentHandler, String fieldSeparator, String componentSeparator, String subcomponentSeparator, String repetitionSeparator, String escapeCharacter, String[] segments) throws SAXException { for (int segmentIndex = 0; segmentIndex < segments.length; segmentIndex++) { String segment = segments[segmentIndex]; logger.trace("handling segment: " + segment); // loop through each segment and pull out the fields StringTokenizer fieldTokenizer = new StringTokenizer(segment, fieldSeparator, true); if (fieldTokenizer.hasMoreTokens()) { // the XML element is named after the first field String segmentId = fieldTokenizer.nextToken().trim(); if (segmentIndex == 0) { documentHead = MESSAGE_ROOT_ID; contentHandler.startElement("", documentHead, "", null); } contentHandler.startElement("", segmentId, "", null); handleFieldOrRepetitions(contentHandler, fieldSeparator, componentSeparator, subcomponentSeparator, repetitionSeparator, escapeCharacter, segmentId, fieldTokenizer); contentHandler.endElement("", segmentId, ""); } else { throw new SAXException("Could not find fields in segment: " + segment); } } return documentHead; } private void handleFieldOrRepetitions(ContentHandler contentHandler, String fieldSeparator, String componentSeparator, String subcomponentSeparator, String repetitionSeparator, String escapeCharacter, String segmentId, StringTokenizer fieldTokenizer) throws SAXException { int fieldId = 0; boolean atLastField = false; while (fieldTokenizer.hasMoreTokens()) { boolean enteredHeader = false; /* * Go through each element and add as new child under the segment * element */ String field = fieldTokenizer.nextToken(); // the naming is SEG.<field#> if (field.equals(fieldSeparator)) { if (atLastField) { contentHandler.startElement("", segmentId + "." + fieldId, "", null); contentHandler.endElement("", segmentId + "." + fieldId, ""); } fieldId++; atLastField = true; } else { logger.trace("handling field or repetition: " + field); atLastField = false; // batch support if (segmentId.equals("MSH") || segmentId.equals("FHS") || segmentId.equals("BHS")) { enteredHeader = true; } if (enteredHeader && (fieldId == 1)) { contentHandler.startElement("", segmentId + "." + fieldId, "", null); contentHandler.characters(fieldSeparator.toCharArray(), 0, 1); contentHandler.endElement("", segmentId + "." + (fieldId), null); fieldId++; contentHandler.startElement("", segmentId + "." + fieldId, "", null); char[] specialCharacters; if (!subcomponentSeparator.isEmpty()) { specialCharacters = new char[] { componentSeparator.charAt(0), repetitionSeparator.charAt(0), escapeCharacter.charAt(0), subcomponentSeparator.charAt(0) }; } else if (!escapeCharacter.isEmpty()) { specialCharacters = new char[] { componentSeparator.charAt(0), repetitionSeparator.charAt(0), escapeCharacter.charAt(0), }; } else { specialCharacters = new char[] { componentSeparator.charAt(0), repetitionSeparator.charAt(0), }; } contentHandler.characters(specialCharacters, 0, specialCharacters.length); contentHandler.endElement("", segmentId + "." + (fieldId), null); } else if (enteredHeader && (fieldId == 2)) { // do nothing } else { if (handleRepetitions) { handleFieldRepetitions(contentHandler, componentSeparator, repetitionSeparator, subcomponentSeparator, segmentId, fieldId, field); } else { handleField(contentHandler, componentSeparator, subcomponentSeparator, segmentId, fieldId, field); } } } } if (atLastField) { contentHandler.startElement("", segmentId + "." + fieldId, "", null); contentHandler.endElement("", segmentId + "." + fieldId, ""); } } private void handleFieldRepetitions(ContentHandler contentHandler, String componentSeparator, String repetitionSeparator, String subcomponentSeparator, String segmentId, int fieldId, String field) throws SAXException { StringTokenizer fieldRepetitionTokenizer = new StringTokenizer(field, repetitionSeparator, true); boolean atLastRepetition = true; while (fieldRepetitionTokenizer.hasMoreTokens()) { field = fieldRepetitionTokenizer.nextToken(); if (field.equals(repetitionSeparator)) { // check for ~~ if (atLastRepetition) { contentHandler.startElement("", segmentId + "." + fieldId, "", null); contentHandler.characters(EMPTY_CHAR_ARRAY, 0, 0); contentHandler.endElement("", segmentId + "." + fieldId, ""); } atLastRepetition = true; } else { logger.trace("handling repetition: " + field); atLastRepetition = false; handleField(contentHandler, componentSeparator, subcomponentSeparator, segmentId, fieldId, field); } } if (atLastRepetition) { contentHandler.startElement("", segmentId + "." + fieldId, "", null); contentHandler.characters(EMPTY_CHAR_ARRAY, 0, 0); contentHandler.endElement("", segmentId + "." + fieldId, ""); } } private void handleField(ContentHandler contentHandler, String componentSeparator, String subcomponentSeparator, String segmentId, int fieldId, String field) throws SAXException { if ((field.indexOf(componentSeparator) > -1) || (handleSubcomponents && (field.indexOf(subcomponentSeparator) > -1))) { contentHandler.startElement("", segmentId + "." + fieldId, "", null); StringTokenizer componentTokenizer = new StringTokenizer(field, componentSeparator, true); handleComponents(contentHandler, componentSeparator, subcomponentSeparator, segmentId, fieldId, 1, componentTokenizer); contentHandler.endElement("", segmentId + "." + fieldId, null); } else { logger.trace("handling field: " + field); contentHandler.startElement("", segmentId + "." + fieldId, "", null); contentHandler.startElement("", segmentId + "." + fieldId + ".1", "", null); contentHandler.characters(field.toCharArray(), 0, field.length()); contentHandler.endElement("", segmentId + "." + fieldId + ".1", null); contentHandler.endElement("", segmentId + "." + fieldId, null); } } private void handleComponents(ContentHandler contentHandler, String componentSeparator, String subcomponentSeparator, String segmentId, int fieldId, int componentId, StringTokenizer componentTokenizer) throws SAXException { boolean atLastComponent = true; while (componentTokenizer.hasMoreTokens()) { String component = componentTokenizer.nextToken(); if (component.equals(componentSeparator)) { if (atLastComponent) { contentHandler.startElement("", segmentId + "." + fieldId + "." + componentId, "", null); contentHandler.characters(EMPTY_CHAR_ARRAY, 0, 0); contentHandler.endElement("", segmentId + "." + fieldId + "." + componentId, ""); } componentId++; atLastComponent = true; } else { atLastComponent = false; handleComponent(contentHandler, subcomponentSeparator, segmentId, fieldId, componentId, component); } } if (atLastComponent) { contentHandler.startElement("", segmentId + "." + fieldId + "." + componentId, "", null); contentHandler.characters(EMPTY_CHAR_ARRAY, 0, 0); contentHandler.endElement("", segmentId + "." + fieldId + "." + componentId, ""); } } private void handleComponent(ContentHandler contentHandler, String subcomponentSeparator, String segmentId, int fieldId, int componentId, String component) throws SAXException { if (handleSubcomponents && !subcomponentSeparator.isEmpty() && (component.indexOf(subcomponentSeparator) > -1)) { contentHandler.startElement("", segmentId + "." + fieldId + "." + componentId, "", null); // check if we have subcomponents, if so add them StringTokenizer subcomponentTokenizer = new StringTokenizer(component, subcomponentSeparator, true); handleSubcomponents(contentHandler, subcomponentSeparator, segmentId, fieldId, componentId, 1, subcomponentTokenizer); contentHandler.endElement("", segmentId + "." + fieldId + "." + componentId, null); } else { logger.trace("handling component: " + component); // the naming is SEG.<field#>.<component#> contentHandler.startElement("", segmentId + "." + fieldId + "." + componentId, "", null); contentHandler.characters(component.toCharArray(), 0, component.length()); contentHandler.endElement("", segmentId + "." + fieldId + "." + componentId, ""); } } private void handleSubcomponents(ContentHandler contentHandler, String subcomponentSeparator, String segmentId, int fieldId, int componentId, int subcomponentId, StringTokenizer subcomponentTokenizer) throws SAXException { boolean atLastSubcomponent = true; while (subcomponentTokenizer.hasMoreTokens()) { String subcomponent = subcomponentTokenizer.nextToken(); if (subcomponent.equals(subcomponentSeparator)) { if (atLastSubcomponent) { contentHandler.startElement("", segmentId + "." + fieldId + "." + componentId + "." + subcomponentId, "", null); contentHandler.characters(EMPTY_CHAR_ARRAY, 0, 0); contentHandler.endElement("", segmentId + "." + fieldId + "." + componentId + "." + subcomponentId, ""); } subcomponentId++; atLastSubcomponent = true; } else { logger.trace("handling subcomponent: " + subcomponentId); atLastSubcomponent = false; // the naming is SEG.<field#>.<component#>.<subcomponent#> contentHandler.startElement("", segmentId + "." + fieldId + "." + componentId + "." + subcomponentId, "", null); contentHandler.characters(subcomponent.toCharArray(), 0, subcomponent.length()); contentHandler.endElement("", segmentId + "." + fieldId + "." + componentId + "." + subcomponentId, ""); } } if (atLastSubcomponent) { contentHandler.startElement("", segmentId + "." + fieldId + "." + componentId + "." + subcomponentId, "", null); contentHandler.characters(EMPTY_CHAR_ARRAY, 0, 0); contentHandler.endElement("", segmentId + "." + fieldId + "." + componentId + "." + subcomponentId, ""); } } }