All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.dellroad.hl7.XMLConverter Maven / Gradle / Ivy

The newest version!

/*
 * Copyright (C) 2008 Archie L. Cobbs. All rights reserved.
 */

package org.dellroad.hl7;

import java.io.EOFException;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.dellroad.hl7.io.HL7FileReader;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

/**
 * Converts {@link HL7Message}(s) to and from XML.
 *
 * 

* Example of what the XML looks like: *

 * <HL7>
 *  <MESSAGE>
 *    <MSH>
 *      <MSH.1>|</MSH.1>
 *      <MSH.2>^~\&amp;</MSH.2>
 *      <MSH.3>ST01</MSH.3>
 *      <MSH.4>B</MSH.4>
 *      <MSH.5>IM</MSH.5>
 *      <MSH.6>B</MSH.6>
 *      <MSH.7>20191203131805</MSH.7>
 *      <MSH.9>
 *        <MSH.9.1>ADT</MSH.9.1>
 *        <MSH.9.2>A04</MSH.9.2>
 *      </MSH.9>
 *      <MSH.10>99479783</MSH.10>
 *      <MSH.11>P</MSH.11>
 *      <MSH.12>2.2</MSH.12>
 *      <MSH.13>99479783</MSH.13>
 *      <MSH.15>AL</MSH.15>
 *      <MSH.22>2.2b</MSH.22>
 *    </MSH>
 *    <EVN>
 *      <EVN.1>A04</EVN.1>
 *      <EVN.2>20160815131805</EVN.2>
 *      <EVN.5>
 *        <EVN.5.1>DMB</EVN.5.1>
 *        <EVN.5.2>WASHINGTON</EVN.5.2>
 *        <EVN.5.3>GEORGE</EVN.5.3>
 *        <EVN.5.4>M</EVN.5.4>
 *      </EVN.5>
 *    </EVN>
 *    <PID>
 *      <PID.1>1</PID.1>
 *      <PID.2>344356467</PID.2>
 *      <PID.3>345345456</PID.3>
 *      <PID.4>123132423</PID.4>
 *      <PID.5>
 *        <PID.5.1>HAMILTON</PID.5.1>
 *        <PID.5.2>ALEXANDER</PID.5.2>
 *      </PID.5>
 *    ...
 * 
*/ public class XMLConverter { /** * HL7 message XML namespace. */ public static final String HL7_NAMESPACE_URI = null; /** * XML tag name used by {@link #toXML}. */ public static final String HL7_TAG = "HL7"; /** * XML tag name used for one XML-encoded message. */ public static final String MESSAGE_TAG = "MESSAGE"; protected final DocumentBuilderFactory documentBuilderFactory; /** * Default constructor. */ public XMLConverter() { this(DocumentBuilderFactory.newInstance()); this.documentBuilderFactory.setNamespaceAware(true); } /** * Constructor. * * @param documentBuilderFactory factory for creating new XML documents * @throws IllegalArgumentException if {@code documentBuilderFactory} is null */ public XMLConverter(DocumentBuilderFactory documentBuilderFactory) { if (documentBuilderFactory == null) throw new IllegalArgumentException("null documentBuilderFactory"); this.documentBuilderFactory = documentBuilderFactory; } /** * Create an empty XML document for HL7 messages. * * @return XML document consisting of one empty {@code <HL7/>} tag */ public Document createDocument() { DocumentBuilder documentBuilder; try { documentBuilder = this.documentBuilderFactory.newDocumentBuilder(); } catch (ParserConfigurationException e) { throw new RuntimeException(e); } Document document = documentBuilder.getDOMImplementation().createDocument(HL7_NAMESPACE_URI, HL7_TAG, null); document.setXmlStandalone(true); return document; } /** * Convert an HL7 message message to an XML document. The document * element will be <HL7> and contain one child which is the * XML encoding of the message. * * @param message HL7 message * @param omitEmpty Omit empty tags (other than the last one) * @return HL7 message encoded as an XML document */ public Document toXML(HL7Message message, boolean omitEmpty) { final Document doc = this.createDocument(); this.appendMessage(doc.getDocumentElement(), message, omitEmpty); return doc; } /** * Convert a message to XML and append it to the given element. * * @param parent an XML {@link Element} or {@link Document} node * @param message HL7 message to append * @param omitEmpty Omit empty tags (other than the last one) */ public void appendMessage(Node parent, HL7Message message, boolean omitEmpty) { final Element messageTag = parent.getOwnerDocument().createElementNS(HL7_NAMESPACE_URI, MESSAGE_TAG); for (HL7Segment segment : message.getSegments()) this.appendSegment(messageTag, segment, omitEmpty); parent.appendChild(messageTag); } /** * Convert a message to XML and append it to the given {@link XMLStreamWriter}. * * @param writer XML output * @param message HL7 message to append * @param omitEmpty Omit empty tags (other than the last one) * @throws XMLStreamException if an XML error occurs */ public void appendMessage(XMLStreamWriter writer, HL7Message message, boolean omitEmpty) throws XMLStreamException { writer.writeStartElement(MESSAGE_TAG); writer.setDefaultNamespace(HL7_NAMESPACE_URI); for (HL7Segment segment : message.getSegments()) this.appendSegment(writer, segment, omitEmpty); writer.writeEndElement(); } /** * Convert a segment to XML and append it to the given element. * * @param parent an XML {@link Element} or {@link Document} node * @param segment HL7 segment to append * @param omitEmpty Omit empty tags (other than the last one) */ public void appendSegment(Node parent, HL7Segment segment, boolean omitEmpty) { final String segName = segment.getName(); final Document doc = parent.getOwnerDocument(); final Element segXML = doc.createElementNS(HL7_NAMESPACE_URI, segName); final HL7Field[] fields = segment.getFields(); for (int i = 1; i < fields.length; i++) { final HL7Field field = fields[i]; if (omitEmpty && i < fields.length - 1 && field.isEmpty()) continue; final String fieldTag = segName + "." + i; for (String[][] repeat : field.getValue()) { final Element repeatXML = doc.createElementNS(HL7_NAMESPACE_URI, fieldTag); segXML.appendChild(repeatXML); if (repeat.length == 1 && repeat[0].length == 1) { if (repeat[0][0].length() > 0) repeatXML.appendChild(doc.createTextNode(repeat[0][0])); continue; } for (int j = 0; j < repeat.length; j++) { final String[] comp = repeat[j]; if (omitEmpty && j < repeat.length - 1 && comp.length == 1 && comp[0].length() == 0) continue; final String compTag = fieldTag + "." + (j + 1); final Element compXML = doc.createElementNS(HL7_NAMESPACE_URI, compTag); repeatXML.appendChild(compXML); if (comp.length == 1) { if (comp[0].length() > 0) compXML.appendChild(doc.createTextNode(comp[0])); continue; } for (int k = 0; k < comp.length; k++) { final String subcomp = comp[k]; if (omitEmpty && k < comp.length - 1 && subcomp.length() == 0) continue; final String subcompTag = compTag + "." + (k + 1); final Element subcompXML = doc.createElementNS(HL7_NAMESPACE_URI, subcompTag); if (subcomp.length() > 0) subcompXML.appendChild(doc.createTextNode(subcomp)); compXML.appendChild(subcompXML); } } } } parent.appendChild(segXML); } /** * Convert a segment to XML and write it to the given {@link XMLStreamWriter}. * * @param writer XML output * @param segment HL7 segment to append * @param omitEmpty Omit empty tags (other than the last one) * @throws XMLStreamException if an XML error occurs */ public void appendSegment(XMLStreamWriter writer, HL7Segment segment, boolean omitEmpty) throws XMLStreamException { final String segName = segment.getName(); final HL7Field[] fields = segment.getFields(); writer.writeStartElement(segName); writer.setDefaultNamespace(HL7_NAMESPACE_URI); for (int i = 1; i < fields.length; i++) { final HL7Field field = fields[i]; if (omitEmpty && i < fields.length - 1 && field.isEmpty()) continue; final String fieldTag = segName + "." + i; for (String[][] repeat : field.getValue()) { writer.writeStartElement(fieldTag); if (repeat.length == 1 && repeat[0].length == 1) { if (repeat[0][0].length() > 0) writer.writeCharacters(repeat[0][0]); writer.writeEndElement(); continue; } for (int j = 0; j < repeat.length; j++) { final String[] comp = repeat[j]; if (omitEmpty && j < repeat.length - 1 && comp.length == 1 && comp[0].length() == 0) continue; final String compTag = fieldTag + "." + (j + 1); writer.writeStartElement(compTag); if (comp.length == 1) { if (comp[0].length() > 0) writer.writeCharacters(comp[0]); writer.writeEndElement(); continue; } for (int k = 0; k < comp.length; k++) { final String subcomp = comp[k]; if (omitEmpty && k < comp.length - 1 && subcomp.length() == 0) continue; final String subcompTag = compTag + "." + (k + 1); writer.writeStartElement(subcompTag); if (subcomp.length() > 0) writer.writeCharacters(subcomp); writer.writeEndElement(); } writer.writeEndElement(); } writer.writeEndElement(); } } writer.writeEndElement(); } /** * Serialize the XML document and write it to the given output. * * @param doc XML document to output * @param out output desination * @throws IOException if an I/O error occurs */ public void stream(Document doc, OutputStream out) throws IOException { TransformerFactory transformFactory = TransformerFactory.newInstance(); try { transformFactory.setAttribute("indent-number", 2); } catch (IllegalArgumentException e) { // ignore } this.stream(transformFactory, doc, out); } /** * Serialize the XML document and write it to the given output. * * @param transformerFactory factory for XSL transformers * @param doc XML document to output * @param out output desination * @throws IOException if an I/O error occurs */ public void stream(TransformerFactory transformerFactory, Document doc, OutputStream out) throws IOException { // Create and configure Transformer final Transformer transformer; try { transformer = transformerFactory.newTransformer(); } catch (TransformerConfigurationException e) { throw new RuntimeException(e); } transformer.setOutputProperty(OutputKeys.METHOD, "xml"); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); // Transform DOM into serialized output stream. // Wrap output stream in a writer to work around this bug: // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6337981 final OutputStreamWriter writer = new OutputStreamWriter(out, "UTF-8"); try { transformer.transform(new DOMSource(doc), new StreamResult(writer)); } catch (TransformerException e) { if (e.getCause() instanceof IOException) throw (IOException)e.getCause(); throw new RuntimeException(e); } writer.flush(); } /** * Test routine. Reads HL7 messages in "file format" and outputs them in an XML document. * * @param args command line arguments * @throws Exception if an error occurs */ @SuppressWarnings("fallthrough") public static void main(String[] args) throws Exception { boolean verbose = false; if (args.length > 0 && args[0].equals("-v")) { verbose = true; final String[] args2 = new String[args.length - 1]; System.arraycopy(args, 1, args2, 0, args2.length); args = args2; } final InputStream in; switch (args.length) { case 1: in = new FileInputStream(args[0]); break; case 0: in = System.in; break; default: System.err.println("Usage: XMLConverter [-v] [filename]"); System.exit(1); throw new RuntimeException(); } try (HL7FileReader reader = new HL7FileReader(in)) { final XMLConverter xmlConverter = new XMLConverter(); final Document doc = xmlConverter.createDocument(); while (true) { try { xmlConverter.appendMessage(doc.getDocumentElement(), reader.readMessage(), !verbose); } catch (EOFException e) { break; } } xmlConverter.stream(doc, System.out); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy