Intro
ERP
系统中有一种常见信息交换格式为 .edi
,常见的 X12
标准里也会有 .edi
身影。本文不对系统及场景的讨论,在大多 edi 博客是软件广告的情况下,给实际开发者们一个能用的方向,用 java
来 解析 edi
中的内容,并将 object 生成 edi
文件 。
Core
主要是使用 smooks 这个库作为主核心,编写配置规则,然后配合少量 java 代码
// 以下为 gradle 依赖,maven 请自己修改
dependencies {
// edi parse
implementation 'org.smooks.cartridges.edi:smooks-edi-cartridge:2.0.0-RC1'
// class to xml
implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.13.4'
}
0xA 解析 edi
- 0xA1 edi 文件 结构分析
- 0xA2 编写2个配置文件 xml dfdl.xsd 文件
- 0xA3 完整 demo 基于
EDI 850 订单
0xA1 结构分析
头,尾 基本都是固定格式。主体为自定义,所以中心将会放在这里,需要注意的是中间部分有
重复结构
即为循环
0xA2 配置文件
主要为两个文件 /edi/x850-decode.xml
和 /edi/x850-mapping.dfdl.xsd
,一个用于基本定义,一个用于结构解析。
x850-decode.xml
<?xml version="1.0"?>
<smooks-resource-list
xmlns="https://www.smooks.org/xsd/smooks-2.0.xsd"
xmlns:edi="https://www.smooks.org/xsd/smooks/edi-2.0.xsd">
<edi:parser schemaURI="/edi/x850-mapping.dfdl.xsd"
segmentTerminator="~%NL;" dataElementSeparator="*" validationMode="Full"/>
</smooks-resource-list>
x850-mapping.dfdl.xsd
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:dfdl="http://www.ogf.org/dfdl/dfdl-1.0/"
xmlns:ibmEdiFmt="http://www.ibm.com/dfdl/EDI/Format"
xmlns:ibmSchExtn="http://www.ibm.com/schema/extensions">
<xsd:import namespace="http://www.ibm.com/dfdl/EDI/Format"
schemaLocation="/EDIFACT-Common/IBM_EDI_Format.dfdl.xsd"/>
<xsd:annotation>
<xsd:appinfo source="http://www.ogf.org/dfdl/">
<dfdl:format ref="ibmEdiFmt:EDIFormat"/>
</xsd:appinfo>
</xsd:annotation>
<xsd:element ibmSchExtn:docRoot="true" name="x850">
<xsd:complexType>
<xsd:sequence>
<xsd:sequence dfdl:initiatedContent="yes">
<xsd:element dfdl:initiator="ISA" dfdl:ref="ibmEdiFmt:EDISegmentFormat" name="interchange-header">
<xsd:complexType>
<xsd:sequence dfdl:ref="ibmEdiFmt:EDISegmentSequenceFormat">
<xsd:element name="auth-qual" type="xsd:string"/>
<xsd:element name="auth-id" type="xsd:string"/>
<xsd:element name="security-qual" type="xsd:string"/>
<xsd:element name="security-id" type="xsd:string"/>
<xsd:element name="sender-qual" type="xsd:string"/>
<xsd:element name="sender-id" type="xsd:string"/>
<xsd:element name="receiver-qual" type="xsd:string"/>
<xsd:element name="receiver-id" type="xsd:string"/>
<xsd:element name="date" type="xsd:string"/>
<xsd:element name="time" type="xsd:string"/>
<xsd:element name="standard" type="len1-1"/>
<xsd:element name="version" type="xsd:string"/>
<xsd:element name="interchange-control-number" type="xsd:string"/>
<xsd:element name="ack" type="len1-1"/>
<xsd:element name="test" type="len1-1"/>
<xsd:element name="s-delimiter" type="len1-1"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element dfdl:initiator="GS" dfdl:ref="ibmEdiFmt:EDISegmentFormat" name="group-header">
<xsd:complexType>
<xsd:sequence dfdl:ref="ibmEdiFmt:EDISegmentSequenceFormat">
<xsd:element name="code" type="xsd:string"/>
<xsd:element name="sender" type="xsd:string"/>
<xsd:element name="receiver" type="xsd:string"/>
<xsd:element name="date" type="xsd:string"/>
<xsd:element name="time" type="xsd:string"/>
<xsd:element name="group-control-number" type="xsd:string"/>
<xsd:element name="standard" type="xsd:string"/>
<xsd:element name="version" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element dfdl:initiator="ST" dfdl:ref="ibmEdiFmt:EDISegmentFormat"
name="transaction-set-header">
<xsd:complexType>
<xsd:sequence dfdl:ref="ibmEdiFmt:EDISegmentSequenceFormat">
<xsd:element name="code" type="xsd:string"/>
<xsd:element name="transaction-set-control-number" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
<xsd:element dfdl:initiator="BEG" dfdl:ref="ibmEdiFmt:EDISegmentFormat" name="beg">
<xsd:complexType>
<xsd:sequence dfdl:ref="ibmEdiFmt:EDISegmentSequenceFormat">
<xsd:element name="original" type="xsd:string"/>
<xsd:element name="type" type="xsd:string"/>
<xsd:element name="sn" type="xsd:string"/>
<xsd:element name="empty1" type="xsd:string"/>
<xsd:element name="data-ymd" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element dfdl:initiator="REF" dfdl:ref="ibmEdiFmt:EDISegmentFormat" name="ref">
<xsd:complexType>
<xsd:sequence dfdl:ref="ibmEdiFmt:EDISegmentSequenceFormat">
<xsd:element name="vendor-point" type="xsd:string"/>
<xsd:element name="vendor-name" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element dfdl:initiator="DTM" dfdl:ref="ibmEdiFmt:EDISegmentFormat" name="latest-arrival-date">
<xsd:complexType>
<xsd:sequence dfdl:ref="ibmEdiFmt:EDISegmentSequenceFormat">
<xsd:element name="type" type="xsd:string"/>
<xsd:element name="ymd" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element dfdl:initiator="DTM" dfdl:ref="ibmEdiFmt:EDISegmentFormat" name="requested-arrival-date">
<xsd:complexType>
<xsd:sequence dfdl:ref="ibmEdiFmt:EDISegmentSequenceFormat">
<xsd:element name="type" type="xsd:string"/>
<xsd:element name="ymd" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element dfdl:initiator="MSG" dfdl:ref="ibmEdiFmt:EDISegmentFormat" name="msg">
<xsd:complexType>
<xsd:sequence dfdl:ref="ibmEdiFmt:EDISegmentSequenceFormat">
<xsd:element name="messsage" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element dfdl:initiator="N1" dfdl:ref="ibmEdiFmt:EDISegmentFormat" name="n1">
<xsd:complexType>
<xsd:sequence dfdl:ref="ibmEdiFmt:EDISegmentSequenceFormat">
<xsd:element name="entity-ic" type="xsd:string"/>
<xsd:element name="name" type="xsd:string"/>
<xsd:element name="id-code-qualifier" type="xsd:string"/>
<xsd:element name="id-code" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="products">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="product" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element dfdl:initiator="CTT" dfdl:ref="ibmEdiFmt:EDISegmentFormat" name="transaction-totals">
<xsd:complexType>
<xsd:sequence dfdl:ref="ibmEdiFmt:EDISegmentSequenceFormat">
<xsd:element name="number-of-line-items" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element dfdl:initiator="SE" dfdl:ref="ibmEdiFmt:EDISegmentFormat" name="transaction-set-trailer">
<xsd:complexType>
<xsd:sequence dfdl:ref="ibmEdiFmt:EDISegmentSequenceFormat">
<xsd:element name="number-of-included-segments" type="xsd:string"/>
<xsd:element name="transaction-set-control-number" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element dfdl:initiator="GE" dfdl:ref="ibmEdiFmt:EDISegmentFormat" name="functional-group-trailer">
<xsd:complexType>
<xsd:sequence dfdl:ref="ibmEdiFmt:EDISegmentSequenceFormat">
<xsd:element name="number-of-transaction-sets" type="xsd:string"/>
<xsd:element name="group-control-number" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element dfdl:initiator="IEA" dfdl:ref="ibmEdiFmt:EDISegmentFormat"
name="interchange-control-trailer">
<xsd:complexType>
<xsd:sequence dfdl:ref="ibmEdiFmt:EDISegmentSequenceFormat">
<xsd:element name="number-of-function-groups-included" type="xsd:string"/>
<xsd:element name="interchange-control-number" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="product">
<xsd:complexType>
<xsd:sequence>
<xsd:element dfdl:initiator="PO1" dfdl:ref="ibmEdiFmt:EDISegmentFormat" name="info">
<xsd:complexType>
<xsd:sequence dfdl:ref="ibmEdiFmt:EDISegmentSequenceFormat">
<xsd:element name="assigned-identification" type="xsd:string"/>
<xsd:element name="quantity" type="xsd:string"/>
<xsd:element name="each" type="xsd:string"/>
<xsd:element name="price" type="xsd:string"/>
<xsd:element name="we" type="xsd:string"/>
<xsd:element name="purchaser-item" type="xsd:string"/>
<xsd:element name="purchaser-item-code" type="xsd:string"/>
<xsd:element name="vendor-sn-point" type="xsd:string"/>
<xsd:element name="vendor-sn" type="xsd:string"/>
<xsd:element name="vendor-color-point" type="xsd:string"/>
<xsd:element name="vendor-color" type="xsd:string"/>
<xsd:element name="item-size-point" type="xsd:string"/>
<xsd:element name="item-size" type="xsd:string"/>
<xsd:element name="upc-point" type="xsd:string"/>
<xsd:element name="upc" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="details">
<xsd:complexType>
<xsd:sequence>
<xsd:element dfdl:initiator="PID" dfdl:ref="ibmEdiFmt:EDISegmentFormat"
name="attr" maxOccurs="unbounded">
<xsd:complexType>
<xsd:sequence dfdl:ref="ibmEdiFmt:EDISegmentSequenceFormat">
<xsd:element name="f" type="xsd:string"/>
<xsd:element name="type" type="xsd:string"/>
<xsd:element name="empty1" type="xsd:string"/>
<xsd:element name="empty2" type="xsd:string"/>
<xsd:element name="value" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:simpleType name="len1-1">
<xsd:restriction base="xsd:string">
<xsd:minLength value="1"/>
<xsd:maxLength value="1"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
pojo
package com.wolanx.proxy.edierp.manager;
import java.util.List;
import lombok.Data;
public class X850DTO {
// head
public Object interchangeHeader;
public Object groupHeader;
public Object transactionSetHeader;
// tail
public Object transactionTotals;
public Object transactionSetTrailer;
public Object functionalGroupTrailer;
public Object interchangeControlTrailer;
public Beg beg;
public Ref ref;
public Dtm latestArrivalDate;
public Dtm requestedArrivalDate;
public Object msg;
public Object n1;
public List<PO1> products;
@Data
public static class Beg {
String original;
String type;
String sn;
String empty1;
String dataYmd;
}
@Data
public static class Ref {
String vendorPoint;
String vendorName;
}
@Data
public static class Dtm {
String type;
String ymd;
}
@Data
public static class PO1 {
PO1Info info;
List<PO1Detail> details;
}
@Data
public static class PO1Info {
String assignedIdentification;
int quantity;
String each;
float price;
String we;
String purchaserItem;
String purchaserItemCode; // 69480-BLK-7
String vendorSnPoint;
String vendorSn;
String vendorColorPoint;
String vendorColor;
String itemSizePoint;
String itemSize;
String upcPoint;
String upc;
}
@Data
public static class PO1Detail {
String f;
String type;
String empty1;
String empty2;
String value;
}
}
0xA3 java parse demo
@Slf4j
public class X850Test {
@Test
void ediToXml() throws IOException, SAXException {
String edi = """
ISA*00* *00* *ZZ*ASD *ZZ*ASD *220831*0832*U*00400*000000112*0*P*>~
GS*PO*MINNETONKA*ASD*20201001*1400*367*X*004010~
ST*850*0001~
BEG*00*SA*EZAGYQ7654321**20220730~
REF*VR*ASD~
DTM*001*20221025~
DTM*010*20220916~
MSG*Pack in solid size cases of 6.~
N1*ST*ASD ZXC INC.*92*0001~
PO1*1*12*EA*11.80*WE*PI*799910-WTP-5*VA*ICW30132*VE*WTP*IZ*5*UP*887449518835~
PID*F*91***5~
PID*F*08***Silvie~
PID*F*35***White Tropical Print~
PO1*1*18*EA*11.80*WE*PI*799910-WTP-6*VA*ICW30132*VE*WTP*IZ*6*UP*887449518842~
PID*F*91***6~
PID*F*08***Silvie~
PID*F*35***White Tropical Print~
CTT*9~
SE*126*0001~
GE*1*367~
IEA*1*000000112~
""";
Smooks ediToXml = new Smooks("/edi/x850-decode.xml");
StringResult result = new StringResult();
ediToXml.filterSource(new StreamSource(new ByteArrayInputStream(edi.getBytes())), result);
String xmlResult = result.getResult();
System.out.println(xmlResult); // 你会得到一大段 xml:<x850><interchange-header>....省略一万字</x850>
}
@Test
void xmlToObject {
// xml 转 对象
// 默认会了,篇幅过长,需要的联系作者
}
}
0xB 生成 edi
- 0xB1 编写 xml dfdl.xsd 文件
- 0xB2 pojo 定义
- 0xB3 完整 demo 基于
EDI 856 运输
0xB1 编写配置文件
/edi/x856-encode.xml
<?xml version="1.0"?>
<smooks-resource-list
xmlns="https://www.smooks.org/xsd/smooks-2.0.xsd"
xmlns:edi="https://www.smooks.org/xsd/smooks/edi-2.0.xsd">
<edi:unparser unparseOnNode="*" schemaURI="/edi/x856-mapping.dfdl.xsd"
segmentTerminator="~%NL;" dataElementSeparator="*" validationMode="Full"/>
</smooks-resource-list>
/edi/x856-mapping.dfdl.xsd
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:dfdl="http://www.ogf.org/dfdl/dfdl-1.0/"
xmlns:ibmEdiFmt="http://www.ibm.com/dfdl/EDI/Format"
xmlns:ibmSchExtn="http://www.ibm.com/schema/extensions">
<xsd:import namespace="http://www.ibm.com/dfdl/EDI/Format"
schemaLocation="/EDIFACT-Common/IBM_EDI_Format.dfdl.xsd"/>
<xsd:annotation>
<xsd:appinfo source="http://www.ogf.org/dfdl/">
<dfdl:format ref="ibmEdiFmt:EDIFormat"/>
</xsd:appinfo>
</xsd:annotation>
<xsd:element ibmSchExtn:docRoot="true" name="x856">
<xsd:complexType>
<xsd:sequence>
<xsd:sequence dfdl:initiatedContent="yes">
<xsd:element dfdl:initiator="ISA" dfdl:ref="ibmEdiFmt:EDISegmentFormat" name="interchange-header">
<xsd:complexType>
<xsd:sequence dfdl:ref="ibmEdiFmt:EDISegmentSequenceFormat">
<xsd:element name="auth-qual" type="xsd:string"/>
<xsd:element name="auth-id" type="xsd:string"/>
<xsd:element name="security-qual" type="xsd:string"/>
<xsd:element name="security-id" type="xsd:string"/>
<xsd:element name="sender-qual" type="xsd:string"/>
<xsd:element name="sender-id" type="xsd:string"/>
<xsd:element name="receiver-qual" type="xsd:string"/>
<xsd:element name="receiver-id" type="xsd:string"/>
<xsd:element name="date" type="xsd:string"/>
<xsd:element name="time" type="xsd:string"/>
<xsd:element name="standard" type="len1-1"/>
<xsd:element name="version" type="xsd:string"/>
<xsd:element name="interchange-control-number" type="xsd:string"/>
<xsd:element name="ack" type="len1-1"/>
<xsd:element name="test" type="len1-1"/>
<xsd:element name="s-delimiter" type="len1-1"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element dfdl:initiator="GS" dfdl:ref="ibmEdiFmt:EDISegmentFormat" name="group-header">
<xsd:complexType>
<xsd:sequence dfdl:ref="ibmEdiFmt:EDISegmentSequenceFormat">
<xsd:element name="code" type="xsd:string"/>
<xsd:element name="sender" type="xsd:string"/>
<xsd:element name="receiver" type="xsd:string"/>
<xsd:element name="date" type="xsd:string"/>
<xsd:element name="time" type="xsd:string"/>
<xsd:element name="group-control-number" type="xsd:string"/>
<xsd:element name="standard" type="xsd:string"/>
<xsd:element name="version" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element dfdl:initiator="ST" dfdl:ref="ibmEdiFmt:EDISegmentFormat"
name="transaction-set-header">
<xsd:complexType>
<xsd:sequence dfdl:ref="ibmEdiFmt:EDISegmentSequenceFormat">
<xsd:element name="code" type="xsd:string"/>
<xsd:element name="transaction-set-control-number" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
<xsd:element dfdl:initiator="CTT" dfdl:ref="ibmEdiFmt:EDISegmentFormat" name="transaction-totals">
<xsd:complexType>
<xsd:sequence dfdl:ref="ibmEdiFmt:EDISegmentSequenceFormat">
<xsd:element name="number-of-line-items" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element dfdl:initiator="SE" dfdl:ref="ibmEdiFmt:EDISegmentFormat" name="transaction-set-trailer">
<xsd:complexType>
<xsd:sequence dfdl:ref="ibmEdiFmt:EDISegmentSequenceFormat">
<xsd:element name="number-of-included-segments" type="xsd:string"/>
<xsd:element name="transaction-set-control-number" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element dfdl:initiator="GE" dfdl:ref="ibmEdiFmt:EDISegmentFormat" name="functional-group-trailer">
<xsd:complexType>
<xsd:sequence dfdl:ref="ibmEdiFmt:EDISegmentSequenceFormat">
<xsd:element name="number-of-transaction-sets" type="xsd:string"/>
<xsd:element name="group-control-number" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element dfdl:initiator="IEA" dfdl:ref="ibmEdiFmt:EDISegmentFormat"
name="interchange-control-trailer">
<xsd:complexType>
<xsd:sequence dfdl:ref="ibmEdiFmt:EDISegmentSequenceFormat">
<xsd:element name="number-of-function-groups-included" type="xsd:string"/>
<xsd:element name="interchange-control-number" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:simpleType name="len1-1">
<xsd:restriction base="xsd:string">
<xsd:minLength value="1"/>
<xsd:maxLength value="1"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
0xB2 pojo 定义
package com.wolanx.proxy.edierp.manager;
import java.util.List;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.Data;
@JacksonXmlRootElement(localName = "x856")
public class X856DTO {
// head
public Object interchangeHeader;
public Object groupHeader;
public Object transactionSetHeader;
// tail
public Object transactionTotals;
public Object transactionSetTrailer;
public Object functionalGroupTrailer;
public Object interchangeControlTrailer;
// public Beg beg;
// public Ref ref;
// public Dtm latestArrivalDate;
// public Dtm requestedArrivalDate;
// public Object msg;
// public Object n1;
public List<PO1> products;
@Data
public static class Beg {
String original;
String type;
String sn;
String empty1;
String dataYmd;
}
@Data
public static class Ref {
String vendorPoint;
String vendorName;
}
@Data
public static class Dtm {
String type;
String ymd;
}
@Data
public static class PO1 {
PO1Info info;
List<PO1Detail> details;
}
@Data
public static class PO1Info {
String assignedIdentification;
int quantity;
String each;
float price;
String we;
String purchaserItem;
String purchaserItemCode;
String vendorSnPoint;
String vendorSn;
String vendorColorPoint;
String vendorColor;
String itemSizePoint;
String itemSize;
String upcPoint;
String upc;
}
@Data
public static class PO1Detail {
String f;
String type;
String empty1;
String empty2;
String value;
}
}
0xB3 完整 demo
public class X856Test {
@Test
void objectToXml{
// 对象 转 xml
// 默认会了,篇幅过长,需要的联系作者
}
@Test
void xmlToEdi() throws IOException, SAXException {
String xmlResult = FileUtils.readFileToString(ResourceUtils.getFile("classpath:edi-data/x856.xml"), StandardCharsets.UTF_8);
// Convert XML -> EDI
Smooks xmlToEdi = new Smooks("/edi/x856-encode.xml");
xmlToEdi.setFilterSettings(FilterSettings.newSaxNgSettings().setDefaultSerializationOn(false));
byte[] xmlInput = xmlResult.getBytes();
StringResult ediResult = new StringResult();
xmlToEdi.filterSource(new StreamSource(new ByteArrayInputStream(xmlInput)), ediResult);
System.out.println();
System.out.println();
System.out.printf(ediResult.getResult());
}
}
总结
edi
文件本质是压缩后的 简略信息
,抛弃了格式定义,将内容合并串行化,所以解析的时候还原成对应的配置,就能配套读取。
demo 引进门,修改靠个人
。如果还是有问题,可以联系 up。