
org.dellroad.hl7.XMLConverter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hl7lib Show documentation
Show all versions of hl7lib Show documentation
Lightweight Java library for HL7 messages
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>^~\&</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