001/* ***** BEGIN LICENSE BLOCK ***** 002 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 003 * 004 * The contents of this file are subject to the Mozilla Public License Version 005 * 1.1 (the "License"); you may not use this file except in compliance with 006 * the License. You may obtain a copy of the License at 007 * http://www.mozilla.org/MPL/ 008 * 009 * Software distributed under the License is distributed on an "AS IS" basis, 010 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 011 * for the specific language governing rights and limitations under the 012 * License. 013 * 014 * The Original Code is part of dcm4che, an implementation of DICOM(TM) in 015 * Java(TM), hosted at https://github.com/gunterze/dcm4che. 016 * 017 * The Initial Developer of the Original Code is 018 * Agfa Healthcare. 019 * Portions created by the Initial Developer are Copyright (C) 2012 020 * the Initial Developer. All Rights Reserved. 021 * 022 * Contributor(s): 023 * See @authors listed below 024 * 025 * Alternatively, the contents of this file may be used under the terms of 026 * either the GNU General Public License Version 2 or later (the "GPL"), or 027 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 028 * in which case the provisions of the GPL or the LGPL are applicable instead 029 * of those above. If you wish to allow use of your version of this file only 030 * under the terms of either the GPL or the LGPL, and not to allow others to 031 * use your version of this file under the terms of the MPL, indicate your 032 * decision by deleting the provisions above and replace them with the notice 033 * and other provisions required by the GPL or the LGPL. If you do not delete 034 * the provisions above, a recipient may use your version of this file under 035 * the terms of any one of the MPL, the GPL or the LGPL. 036 * 037 * ***** END LICENSE BLOCK ***** */ 038 039package org.dcm4che3.hl7; 040 041import java.io.IOException; 042import java.io.Writer; 043 044import org.xml.sax.Attributes; 045import org.xml.sax.SAXException; 046import org.xml.sax.helpers.DefaultHandler; 047 048/** 049 * @author Gunter Zeilinger <gunterze@gmail.com> 050 * 051 */ 052public class HL7ContentHandler extends DefaultHandler { 053 054 private final Writer writer; 055 private char[] delimiters = Delimiter.DEFAULT.toCharArray(); 056 private final char[] escape = { '\\', 0, '\\' }; 057 private boolean ignoreCharacters = true; 058 059 public HL7ContentHandler(Writer writer) { 060 this.writer = writer; 061 } 062 063 @Override 064 public void startElement(String uri, String localName, String qName, 065 Attributes atts) throws SAXException { 066 try { 067 switch (qName.charAt(0)) { 068 case 'f': 069 if (qName.equals("field")) { 070 writer.write(delimiters[0]); 071 ignoreCharacters = false; 072 return; 073 } 074 break; 075 case 'c': 076 if (qName.equals("component")) { 077 writer.write(delimiters[1]); 078 ignoreCharacters = false; 079 return; 080 } 081 break; 082 case 'r': 083 if (qName.equals("repeat")) { 084 writer.write(delimiters[2]); 085 ignoreCharacters = false; 086 return; 087 } 088 break; 089 case 'e': 090 if (qName.equals("escape")) { 091 writer.write(delimiters[3]); 092 ignoreCharacters = false; 093 return; 094 } 095 break; 096 case 's': 097 if (qName.equals("subcomponent")) { 098 writer.write(delimiters[4]); 099 ignoreCharacters = false; 100 return; 101 } 102 break; 103 case 'M': 104 if (qName.equals("MSH")) { 105 startHeaderSegment(qName, atts); 106 return; 107 } 108 break; 109 case 'B': 110 if (qName.equals("BHS")) { 111 startHeaderSegment(qName, atts); 112 return; 113 } 114 break; 115 case 'F': 116 if (qName.equals("FHS")) { 117 startHeaderSegment(qName, atts); 118 return; 119 } 120 break; 121 case 'h': 122 if (qName.equals("hl7")) 123 return; 124 } 125 writer.write(qName); 126 } catch (Exception e) { 127 throw new SAXException(e); 128 } 129 } 130 131 private void startHeaderSegment(String seg, Attributes atts) throws IOException { 132 Delimiter[] values = Delimiter.values(); 133 for (int i = 0; i < values.length; i++) { 134 String value = atts.getValue(values[i].attribute()); 135 if (value != null) 136 delimiters[i] = value.charAt(0); 137 } 138 this.escape[0] = this.escape[2] = delimiters[3]; 139 writer.write(seg); 140 writer.write(delimiters); 141 } 142 143 @Override 144 public void endElement(String uri, String localName, String qName) 145 throws SAXException { 146 ignoreCharacters = true; 147 try { 148 switch (qName.charAt(0)) { 149 case 'f': 150 if (qName.equals("field")) return; 151 break; 152 case 'c': 153 if (qName.equals("component")) return; 154 break; 155 case 'r': 156 if (qName.equals("repeat")) return; 157 break; 158 case 'e': 159 if (qName.equals("escape")) { 160 writer.write(delimiters[3]); 161 ignoreCharacters = false; 162 return; 163 } 164 break; 165 case 's': 166 if (qName.equals("subcomponent")) return; 167 break; 168 case 'h': 169 if (qName.equals("hl7")) { 170 writer.flush(); 171 return; 172 } 173 } 174 writer.write('\r'); 175 } catch (Exception e) { 176 throw new SAXException(e); 177 } 178 } 179 180 @Override 181 public void characters(char[] cbuf, int start, int length) 182 throws SAXException { 183 if (ignoreCharacters) 184 return; 185 186 try { 187 int off = start; 188 int end = start + length; 189 char c; 190 char[] delims = delimiters; 191 for (int i = start; i < end; i++) { 192 c = cbuf[i]; 193 for (int j = 0; j < delims.length; j++) { 194 if (c == delims[j]) { 195 writer.write(cbuf, off, i - off); 196 off = i + 1; 197 escape(j); 198 break; 199 } 200 } 201 } 202 writer.write(cbuf, off, end - off); 203 } catch (Exception e) { 204 throw new SAXException(e); 205 } 206 } 207 208 private void escape(int delimIndex) throws IOException { 209 escape[1] = Delimiter.ESCAPE.charAt(delimIndex); 210 writer.write(escape); 211 } 212}