Skip to content

Instantly share code, notes, and snippets.

@aaronanderson
Created February 23, 2020 05:22
Show Gist options
  • Save aaronanderson/f59341a152e25fdd64f8104184b168a0 to your computer and use it in GitHub Desktop.
Save aaronanderson/f59341a152e25fdd64f8104184b168a0 to your computer and use it in GitHub Desktop.
StaEDI - EDI X12 832 to XML and back to EDI
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Arrays;
import java.util.Base64;
import java.util.stream.Collectors;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.commons.io.IOUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import com.capeclear.xml.utils.XmlUtils;
import io.xlate.edi.schema.Schema;
import io.xlate.edi.schema.SchemaFactory;
import io.xlate.edi.stream.EDIInputFactory;
import io.xlate.edi.stream.EDIStreamReader;
public class EDIToXML {
public static void processFile(InputStream in, InputStream sin, OutputStream out) throws Exception {
//Schema controlSchema = adjustControlSchema();
Schema transactionSchema = null;
if (sin != null) {
SchemaFactory schemaFactory = SchemaFactory.newFactory();
transactionSchema = schemaFactory.createSchema(sin);
}
EDIInputFactory factory = EDIInputFactory.newFactory();
EDIStreamReader reader = factory.createEDIStreamReader(in);
XMLStreamWriter xtw = XmlUtils.getXMLOutputFactory().createXMLStreamWriter(out, "utf-8");
String segmentID = null;
int segmentCounter = 1;
xtw.writeStartDocument("UTF-8", "1.0");
while (reader.hasNext()) {
switch (reader.next()) {
case START_INTERCHANGE:
//reader.setControlSchema(controlSchema);
String standard = reader.getStandard();
String[] version = reader.getVersion();
xtw.writeStartElement("INTERCHANGE");
xtw.writeAttribute("standard", standard);
xtw.writeAttribute("version", Arrays.stream(version).collect(Collectors.joining(".")));
break;
case END_INTERCHANGE:
xtw.writeEndElement();
break;
case START_TRANSACTION:
if (transactionSchema != null) {
reader.setTransactionSchema(transactionSchema);
}
xtw.writeStartElement("TRANSACTION");
break;
case END_TRANSACTION:
xtw.writeEndElement();
break;
case START_LOOP:
String loopID = reader.getText();
xtw.writeStartElement(loopID);
xtw.writeAttribute("type", "loop");
break;
case END_LOOP:
xtw.writeEndElement();
break;
case START_SEGMENT:
segmentID = reader.getText();
xtw.writeStartElement(segmentID);
xtw.writeAttribute("type", "segment");
break;
case END_SEGMENT:
xtw.writeEndElement();
segmentCounter = 1;
break;
case START_GROUP:
String groupID = reader.getText();
xtw.writeStartElement(groupID);
xtw.writeAttribute("type", "group");
break;
case END_GROUP:
xtw.writeEndElement();
break;
case START_COMPOSITE:
String compositeID = reader.getText();
xtw.writeStartElement(compositeID);
xtw.writeAttribute("type", "composite");
break;
case END_COMPOSITE:
xtw.writeEndElement();
break;
case ELEMENT_DATA:
String elementData = reader.getText();
xtw.writeStartElement(String.format("%s%02d", segmentID, segmentCounter++));
xtw.writeCharacters(elementData);
xtw.writeEndElement();
break;
case ELEMENT_DATA_BINARY:
try (InputStream bin = reader.getBinaryData();) {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
IOUtils.copy(bin, bout);
byte[] elementBinaryData = Base64.getEncoder().encode(bout.toByteArray());
xtw.writeStartElement("ELEMENT_BINARY");
xtw.writeCharacters(new String(elementBinaryData, "UTF-8"));
xtw.writeEndElement();
}
break;
case ELEMENT_DATA_ERROR:
throw new Exception(formatError("Element Data", reader));
case ELEMENT_OCCURRENCE_ERROR:
throw new Exception(formatError("Element Occurance", reader));
case SEGMENT_ERROR:
throw new Exception(formatError("Segment", reader));
}
}
xtw.writeEndDocument();
xtw.flush();
xtw.close();
reader.close();
}
public static String formatError(String errorType, EDIStreamReader reader) {
StringBuilder sb = new StringBuilder();
sb.append(errorType).append(" ").append("Error: ").append(reader.getErrorType());
sb.append(" Segment Position: ").append(reader.getLocation().getSegmentPosition());
sb.append(" LineNumber: ").append(reader.getLocation().getLineNumber());
sb.append(" Column Number: ").append(reader.getLocation().getColumnNumber());
return sb.toString();
}
//The default control schema can be adjusted in case the target files are not fully conformant, i.e. the number of records exceed the control total limits.
public static Schema adjustControlSchema() throws Exception {
try (InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("X12/v00200.xml");) {
DocumentBuilderFactory factory = XmlUtils.getNonDeferredFactory();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(is);
NodeList nodeList = doc.getDocumentElement().getElementsByTagName("elementType");
for (int i = 0; i < nodeList.getLength(); i++) {
Element type = (Element) nodeList.item(i);
if ("E97".equals(type.getAttribute("name"))) {
type.setAttribute("maxLength", "10");
}
}
ByteArrayOutputStream bos = new ByteArrayOutputStream();
TransformerFactory tf = XmlUtils.getTransformerFactory();
Transformer trans = tf.newTransformer();
trans.transform(new DOMSource(doc), new StreamResult(bos));
SchemaFactory schemaFactory = SchemaFactory.newFactory();
return schemaFactory.createSchema(new ByteArrayInputStream(bos.toByteArray()));
}
}
public static void main(String[] args) {
Path schema = Paths.get("ws\\WSAR-INF\\schema_832.xml");
Path edi = Paths.get("ws\\WSAR-INF\\sample_832.edi");
Path result = Paths.get("ws\\test\\sample_832.xml");
try (InputStream sin = Files.newInputStream(schema); InputStream in = Files.newInputStream(edi); OutputStream out = Files.newOutputStream(result, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);) {
processFile(in, sin, out);
} catch (Throwable t) {
t.printStackTrace();
}
}
}
ISA*00* *00* *ZZ*555555555 *ZZ*4444444444 *190425*0312*U*00401*000124307*0*P*>~GS*SC*555555555*4444444444*20190425*0312*74307*X*004010~ST*832*743070001~BCT*PC*********04~DTM*007*20190425~N1*VN*EDI Supplier*91*555555555~N3*6110 Stoneridge Mall Road~N4*Pleasanton*NY*94588~N1*BY*Workday Company*91*4444444444~N3*123 YOUR STREET~N4*Dallas*TX*75001~LIN*1*UP*777777777777*ND*66666666666*VC*2222222~G53*001~DTM*092*20180701~DTM*093*20200630~REF*ACC*00~REF*CT*4444*CONTRACT A~REF*PRT*PD*EDI Supplier Distribution Item~PID*F*RX*DE*00*SALINE SOLN 500 ML~PID*F*12***B~PO4*1*500*EA~CTP**INV*10.00~CTP**MSR*25.00~N1*MF*SOME PHARMA INC~LIN*2*UP*999999999999*ND*88888888888*VC*333333333~G53*001~REF*ACC*07~REF*PRT*PD*EDI Supplier Distribution Item~PID*F*OTC***DSTL SPRWTR LIQD 4X1000ML~PID*F*12***B~PO4*4*1000*CA~CTP**INV*4.0~CTP**MSR*2.00~N1*MF*ANOTHER PHARMA INC~CTT*2~SE*537*743070001~GE*1*74307~IEA*1*000124307~
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<schema xmlns="http://xlate.io/EDISchema/v2">
<transaction>
<sequence>
<segment ref="BCT" minOccurs="1" />
<segment ref="DTM" minOccurs="1" />
<loop code="LOOP_N1" maxOccurs="3"><!-- 2 -->
<sequence>
<segment ref="N1" />
<segment ref="N3" />
<segment ref="N4" />
</sequence>
</loop>
<loop code="LOOP_LIN" maxOccurs="9999999">
<sequence>
<segment ref="LIN" minOccurs="0" maxOccurs="1" />
<segment ref="G53" minOccurs="0" maxOccurs="1" />
<segment ref="DTM" minOccurs="0" maxOccurs="2" />
<segment ref="REF" minOccurs="0" maxOccurs="3" />
<segment ref="PID" minOccurs="0" maxOccurs="200" />
<segment ref="PO4" minOccurs="0" maxOccurs="1" />
<segment ref="CTP" minOccurs="0" maxOccurs="2" />
<segment ref="N1" minOccurs="0" maxOccurs="1" />
</sequence>
</loop>
<segment ref="CTT" minOccurs="1" />
</sequence>
</transaction>
<elementType name="BCT01" base="string" minLength="0" maxLength="2" />
<elementType name="BCT02" base="string" />
<elementType name="BCT03" base="string" />
<elementType name="BCT04" base="string" />
<elementType name="BCT05" base="string" />
<elementType name="BCT06" base="string" />
<elementType name="BCT07" base="string" />
<elementType name="BCT08" base="string" />
<elementType name="BCT09" base="string" />
<elementType name="BCT10" base="string" minLength="2" maxLength="2" />
<elementType name="DTM01" base="string" minLength="3" maxLength="3" />
<elementType name="DTM02" base="string" minLength="8" maxLength="8" />
<elementType name="N101" base="string" minLength="2" maxLength="3" />
<elementType name="N102" base="string" minLength="2" maxLength="80" />
<elementType name="N103" base="string" minLength="1" maxLength="2" />
<elementType name="N104" base="string" minLength="2" maxLength="80" />
<elementType name="N301" base="string" minLength="1" maxLength="55" />
<elementType name="N401" base="string" minLength="2" maxLength="30" />
<elementType name="N402" base="string" minLength="2" maxLength="2" />
<elementType name="N403" base="string" minLength="3" maxLength="15" />
<elementType name="LIN01" base="string" minLength="1" maxLength="20" />
<elementType name="LIN02" base="string" minLength="2" maxLength="2" />
<elementType name="LIN03" base="string" minLength="1" maxLength="48" />
<elementType name="LIN04" base="string" minLength="2" maxLength="2" />
<elementType name="LIN05" base="string" minLength="1" maxLength="48" />
<elementType name="LIN06" base="string" minLength="2" maxLength="2" />
<elementType name="LIN07" base="string" minLength="1" maxLength="48" />
<elementType name="G5301" base="string" minLength="3" maxLength="3" />
<elementType name="REF01" base="string" minLength="2" maxLength="3" />
<elementType name="REF02" base="string" minLength="1" maxLength="30" />
<elementType name="REF03" base="string" minLength="1" maxLength="80" />
<elementType name="PID01" base="string" minLength="1" maxLength="1" />
<elementType name="PID02" base="string" minLength="2" maxLength="3" />
<elementType name="PID03" base="string" minLength="2" maxLength="2" />
<elementType name="PID04" base="string" minLength="1" maxLength="12" />
<elementType name="PID05" base="string" minLength="1" maxLength="80" />
<elementType name="PO401" base="string" minLength="1" maxLength="6" />
<elementType name="PO402" base="string" minLength="1" maxLength="8" />
<elementType name="PO403" base="string" minLength="2" maxLength="2" />
<elementType name="CTP01" base="string" minLength="0" maxLength="3" />
<elementType name="CTP02" base="string" minLength="3" maxLength="3" />
<elementType name="CTP03" base="string" minLength="1" maxLength="17" />
<elementType name="CTT01" base="numeric" minLength="1" maxLength="10" />
<segmentType name="BCT">
<sequence>
<element ref="BCT01" minOccurs="1" />
<element ref="BCT02" minOccurs="0" />
<element ref="BCT03" minOccurs="0" />
<element ref="BCT04" minOccurs="0" />
<element ref="BCT05" minOccurs="0" />
<element ref="BCT06" minOccurs="0" />
<element ref="BCT07" minOccurs="0" />
<element ref="BCT08" minOccurs="0" />
<element ref="BCT09" minOccurs="0" />
<element ref="BCT10" minOccurs="0" />
</sequence>
</segmentType>
<segmentType name="DTM">
<sequence>
<element ref="DTM01" minOccurs="1" />
<element ref="DTM02" minOccurs="0" />
</sequence>
</segmentType>
<segmentType name="N1">
<sequence>
<element ref="N101" minOccurs="1" />
<element ref="N102" minOccurs="0" />
<element ref="N103" minOccurs="0" />
<element ref="N104" minOccurs="0" />
</sequence>
</segmentType>
<segmentType name="N3">
<sequence>
<element ref="N301" minOccurs="1" />
</sequence>
</segmentType>
<segmentType name="N4">
<sequence>
<element ref="N401" minOccurs="0" />
<element ref="N402" minOccurs="0" />
<element ref="N403" minOccurs="0" />
</sequence>
</segmentType>
<segmentType name="LIN">
<sequence>
<element ref="LIN01" minOccurs="0" />
<element ref="LIN02" minOccurs="1" />
<element ref="LIN03" minOccurs="1" />
<element ref="LIN04" minOccurs="0" />
<element ref="LIN05" minOccurs="0" />
<element ref="LIN06" minOccurs="0" />
<element ref="LIN07" minOccurs="0" />
</sequence>
</segmentType>
<segmentType name="G53">
<sequence>
<element ref="G5301" minOccurs="1" />
</sequence>
</segmentType>
<segmentType name="REF">
<sequence>
<element ref="REF01" minOccurs="1" />
<element ref="REF02" minOccurs="0" />
<element ref="REF03" minOccurs="0" />
</sequence>
</segmentType>
<segmentType name="PID">
<sequence>
<element ref="PID01" minOccurs="1" />
<element ref="PID02" minOccurs="0" />
<element ref="PID03" minOccurs="0" />
<element ref="PID04" minOccurs="0" />
<element ref="PID05" minOccurs="0" />
</sequence>
</segmentType>
<segmentType name="PO4">
<sequence>
<element ref="PO401" minOccurs="0" />
<element ref="PO402" minOccurs="0" />
<element ref="PO403" minOccurs="0" />
</sequence>
</segmentType>
<segmentType name="CTP">
<sequence>
<element ref="CTP01" minOccurs="0" />
<element ref="CTP02" minOccurs="0" />
<element ref="CTP03" minOccurs="0" />
</sequence>
</segmentType>
<segmentType name="CTT">
<sequence>
<element ref="CTT01" minOccurs="1" />
</sequence>
</segmentType>
</schema>
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.LinkedList;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamReader;
import com.capeclear.xml.utils.XmlUtils;
import io.xlate.edi.schema.Schema;
import io.xlate.edi.schema.SchemaFactory;
import io.xlate.edi.stream.EDIOutputFactory;
import io.xlate.edi.stream.EDIStreamConstants;
import io.xlate.edi.stream.EDIStreamWriter;
public class XMLToEDI {
public static final String EDI_TRANSACTION_SCHEMA = "edi-transaction.schema";
public static void processFile(InputStream in, InputStream sin, OutputStream out) throws Exception {
EDIOutputFactory factory = EDIOutputFactory.newFactory();
factory.setProperty(EDIStreamConstants.Delimiters.SEGMENT, '~');
EDIStreamWriter writer = factory.createEDIStreamWriter(out);
if (sin != null) {
SchemaFactory schemaFactory = SchemaFactory.newFactory();
Schema transactionSchema = schemaFactory.createSchema(sin);
writer.setTransactionSchema(transactionSchema);
}
XMLStreamReader reader = XmlUtils.getXMLInputFactory().createXMLStreamReader(in);
LinkedList<String> segmentStack = new LinkedList<>();
while (reader.hasNext()) {
switch (reader.next()) {
//TODO handle element component and binary
case XMLStreamConstants.START_ELEMENT:
String startElementName = reader.getLocalName();
String type = reader.getAttributeValue(null, "type");
if ("INTERCHANGE".equals(startElementName)) {
writer.startInterchange();
} else if ("segment".equals(type)) {
writer.writeStartSegment(startElementName);
segmentStack.push(startElementName);
} else if ("TRANSACTION".equals(startElementName) || type != null) {
//skip
} else {
writer.writeElement(reader.getElementText());
}
break;
case XMLStreamConstants.END_ELEMENT:
String endElementName = reader.getLocalName();
if ("INTERCHANGE".equals(endElementName)) {
writer.endInterchange();
} else if (endElementName.equals(segmentStack.peek())) {
writer.writeEndSegment();
segmentStack.pop();
}
break;
}
}
writer.flush();
writer.close();
reader.close();
}
public static void main(String[] args) {
Path schema = Paths.get("ws\\WSAR-INF\\schema_832.xml");
Path xml = Paths.get("ws\\test\\sample_832.xml");
Path result = Paths.get("ws\\test\\sample_832_out.edi");
try (InputStream sin = Files.newInputStream(schema); InputStream in = Files.newInputStream(xml); OutputStream out = Files.newOutputStream(result, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);) {
processFile(in, sin, out);
} catch (Throwable t) {
t.printStackTrace();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment