Skip to content

Commit

Permalink
Merge 5eb5703 into 56d30af
Browse files Browse the repository at this point in the history
  • Loading branch information
MikeEdgar committed May 19, 2020
2 parents 56d30af + 5eb5703 commit dc9d01e
Show file tree
Hide file tree
Showing 7 changed files with 570 additions and 26 deletions.
98 changes: 81 additions & 17 deletions src/main/java/io/xlate/edi/internal/schema/SchemaReaderBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static io.xlate.edi.internal.schema.StaEDISchemaFactory.schemaException;
import static io.xlate.edi.internal.schema.StaEDISchemaFactory.unexpectedElement;
import static io.xlate.edi.internal.schema.StaEDISchemaFactory.unexpectedEvent;
import static java.util.stream.Collectors.toList;

import java.util.ArrayList;
import java.util.Arrays;
Expand All @@ -15,23 +16,47 @@
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.IntStream;

import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;

import io.xlate.edi.schema.EDIComplexType;
import io.xlate.edi.schema.EDIReference;
import io.xlate.edi.schema.EDISchemaException;
import io.xlate.edi.schema.EDISimpleType;
import io.xlate.edi.schema.EDISimpleType.Base;
import io.xlate.edi.schema.EDISyntaxRule;
import io.xlate.edi.schema.EDIType;
import io.xlate.edi.schema.EDIType.Type;

abstract class SchemaReaderBase implements SchemaReader {

static final String REFERR_UNDECLARED = "Type %s references undeclared %s with ref='%s'";
static final String REFERR_ILLEGAL = "Type '%s' must not be referenced as '%s' in definition of type '%s'";

static final EDIReference ANY_ELEMENT_REF_OPT = new Reference(StaEDISchema.ANY_ELEMENT_ID, "element", 0, 1);
static final EDIReference ANY_COMPOSITE_REF_OPT = new Reference(StaEDISchema.ANY_COMPOSITE_ID, "composite", 0, 99);

static final EDIReference ANY_ELEMENT_REF_REQ = new Reference(StaEDISchema.ANY_ELEMENT_ID, "element", 1, 1);
static final EDIReference ANY_COMPOSITE_REF_REQ = new Reference(StaEDISchema.ANY_COMPOSITE_ID, "composite", 1, 99);

static final EDISimpleType ANY_ELEMENT = new ElementType(StaEDISchema.ANY_ELEMENT_ID,
Base.STRING,
0,
0,
99_999,
Collections.emptySet());

static final EDIComplexType ANY_COMPOSITE = new StructureType(StaEDISchema.ANY_COMPOSITE_ID,
Type.COMPOSITE,
"ANY",
IntStream.rangeClosed(0, 99).mapToObj(i -> ANY_ELEMENT_REF_OPT)
.collect(toList()),
Collections.emptyList());

final String xmlns;

final QName qnSchema;
Expand All @@ -48,6 +73,7 @@ abstract class SchemaReaderBase implements SchemaReader {
final QName qnSequence;
final QName qnEnumeration;
final QName qnValue;
final QName qnAny;

final QName qnCompositeType;
final QName qnElementType;
Expand Down Expand Up @@ -75,6 +101,7 @@ public SchemaReaderBase(String xmlns, XMLStreamReader reader) {
qnSequence = new QName(xmlns, "sequence");
qnEnumeration = new QName(xmlns, "enumeration");
qnValue = new QName(xmlns, "value");
qnAny = new QName(xmlns, "any");

qnCompositeType = new QName(xmlns, "compositeType");
qnElementType = new QName(xmlns, "elementType");
Expand Down Expand Up @@ -115,6 +142,9 @@ public String getTransactionName() {
public Map<String, EDIType> readTypes() throws EDISchemaException {
Map<String, EDIType> types = new HashMap<>(100);

types.put(StaEDISchema.ANY_ELEMENT_ID, ANY_ELEMENT);
types.put(StaEDISchema.ANY_COMPOSITE_ID, ANY_COMPOSITE);

try {
if (isInterchangeSchema(reader)) {
readInterchange(reader, types);
Expand Down Expand Up @@ -181,7 +211,7 @@ void readInterchange(XMLStreamReader reader, Map<String, EDIType> types) throws
refs.add(headerRef);

while (qnSegment.equals(element)) {
refs.add(readReference(reader, types));
addReferences(reader, EDIType.Type.SEGMENT, refs, readReference(reader, types));
reader.nextTag(); // Advance to end element
reader.nextTag(); // Advance to next start element
element = reader.getName();
Expand All @@ -203,18 +233,19 @@ void readInterchange(XMLStreamReader reader, Map<String, EDIType> types) throws
refs.add(trailerRef);

StructureType interchange = new StructureType(qnInterchange.toString(),
EDIType.Type.INTERCHANGE,
"INTERCHANGE",
refs,
Collections.emptyList());
EDIType.Type.INTERCHANGE,
"INTERCHANGE",
refs,
Collections.emptyList());

types.put(interchange.getId(), interchange);
}

Reference readControlStructure(XMLStreamReader reader,
QName element,
QName subelement,
Map<String, EDIType> types) throws XMLStreamException {
Map<String, EDIType> types)
throws XMLStreamException {
int minOccurs = 0;
int maxOccurs = 99999;
String use = parseAttribute(reader, "use", String::valueOf, "optional");
Expand Down Expand Up @@ -250,10 +281,10 @@ Reference readControlStructure(XMLStreamReader reader,
refs.add(trailerRef);

StructureType struct = new StructureType(element.toString(),
complex.get(element),
complex.get(element).toString(),
refs,
Collections.emptyList());
complex.get(element),
complex.get(element).toString(),
refs,
Collections.emptyList());

types.put(struct.getId(), struct);

Expand Down Expand Up @@ -326,8 +357,9 @@ void nameCheck(String name, Map<String, EDIType> types, XMLStreamReader reader)
}

StructureType readComplexType(XMLStreamReader reader,
QName complexType,
Map<String, EDIType> types) throws XMLStreamException {
QName complexType,
Map<String, EDIType> types)
throws XMLStreamException {

final EDIType.Type type = complex.get(complexType);
final String id;
Expand All @@ -354,7 +386,7 @@ StructureType readComplexType(XMLStreamReader reader,

readDescription(reader);
requireElementStart(qnSequence, reader);
readReferences(reader, types, refs);
readReferences(reader, types, type, refs);

int event = reader.nextTag();

Expand All @@ -374,14 +406,15 @@ StructureType readComplexType(XMLStreamReader reader,
}

void readReferences(XMLStreamReader reader,
Map<String, EDIType> types,
List<EDIReference> refs) {
Map<String, EDIType> types,
EDIType.Type parentType,
List<EDIReference> refs) {

try {
while (reader.hasNext()) {
switch (reader.next()) {
case XMLStreamConstants.START_ELEMENT:
refs.add(readReference(reader, types));
addReferences(reader, parentType, refs, readReference(reader, types));
break;

case XMLStreamConstants.END_ELEMENT:
Expand All @@ -400,11 +433,42 @@ void readReferences(XMLStreamReader reader,
}
}

void addReferences(XMLStreamReader reader, EDIType.Type parentType, List<EDIReference> refs, Reference reference) {
if ("ANY".equals(reference.getRefId())) {
final EDIReference optRef;
final EDIReference reqRef;

switch (parentType) {
case SEGMENT:
optRef = ANY_COMPOSITE_REF_OPT;
reqRef = ANY_COMPOSITE_REF_REQ;
break;
case COMPOSITE:
optRef = ANY_ELEMENT_REF_OPT;
reqRef = ANY_ELEMENT_REF_REQ;
break;
default:
throw schemaException("Element " + qnAny + " may only be present for segmentType and compositeType", reader);
}

final int min = reference.getMinOccurs();
final int max = reference.getMaxOccurs();

for (int i = 0; i < max; i++) {
refs.add(i < min ? reqRef : optRef);
}
} else {
refs.add(reference);
}
}

Reference readReference(XMLStreamReader reader, Map<String, EDIType> types) {
QName element = reader.getName();
String refId = null;

if (references.contains(element)) {
if (qnAny.equals(element)) {
refId = "ANY";
} else if (references.contains(element)) {
refId = readReferencedId(reader);
Objects.requireNonNull(refId);
} else if (qnLoop.equals(element)) {
Expand Down
5 changes: 4 additions & 1 deletion src/main/java/io/xlate/edi/internal/schema/StaEDISchema.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@
import io.xlate.edi.schema.Schema;
import io.xlate.edi.schema.implementation.LoopImplementation;

class StaEDISchema implements Schema {
public class StaEDISchema implements Schema {

public static final String ANY_ELEMENT_ID = "io.xlate.edi.internal.schema.ANY_ELEMENT";
public static final String ANY_COMPOSITE_ID = "io.xlate.edi.internal.schema.ANY_COMPOSITE";

final String interchangeName;
final String transactionStandardName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.List;
import java.util.logging.Logger;

import io.xlate.edi.internal.schema.StaEDISchema;
import io.xlate.edi.internal.stream.StaEDIStreamLocation;
import io.xlate.edi.internal.stream.tokenization.Dialect;
import io.xlate.edi.internal.stream.tokenization.ElementDataHandler;
Expand Down Expand Up @@ -765,7 +766,7 @@ public boolean validCompositeOccurrences(Location position) {
}

public boolean isComposite() {
return composite != null;
return composite != null && !StaEDISchema.ANY_COMPOSITE_ID.equals(composite.getId());
}

public boolean validateElement(Dialect dialect, StaEDIStreamLocation position, CharSequence value) {
Expand Down
36 changes: 34 additions & 2 deletions src/main/resources/schema/EDISchema-v3.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,19 @@
<attribute name="title" type="string" use="optional" />
</complexType>

<complexType name="anyElementType">
<attribute name="minOccurs" type="nonNegativeInteger" default="0">
<annotation>
<documentation>The minimum number of times an undefined element may occur at the declared location in the EDI structure.</documentation>
</annotation>
</attribute>
<attribute name="maxOccurs" type="nonNegativeInteger" default="1">
<annotation>
<documentation>The maximum number of times an undefined element may occur at the declared location in the EDI structure.</documentation>
</annotation>
</attribute>
</complexType>

<complexType name="controlType" abstract="true">
<complexContent>
<extension base="tns:baseType">
Expand Down Expand Up @@ -511,9 +524,18 @@
</documentation>
</annotation>
<complexType>
<sequence>
<choice minOccurs="1" maxOccurs="unbounded">
<element name="element" type="tns:elementStandard" minOccurs="1" maxOccurs="unbounded" />
</sequence>
<element name="any" type="tns:anyElementType">
<annotation>
<documentation>
May be used to declare that any component element may occur in this composite type up
to the maximum number given by maxOccurs. The value of minOccurs defines the number of
undefined component elements that MUST occur in the composite.
</documentation>
</annotation>
</element>
</choice>
</complexType>
</element>
<element ref="tns:syntax" minOccurs="0" maxOccurs="unbounded" />
Expand Down Expand Up @@ -543,6 +565,16 @@
<choice minOccurs="0" maxOccurs="unbounded">
<element name="element" type="tns:elementStandard" />
<element name="composite" type="tns:compositeStandard" />
<element name="any" type="tns:anyElementType">
<annotation>
<documentation>
May be used to declare that any element or composite may occur in this segment type up
to the maximum number given by maxOccurs. The value of minOccurs defines the number of
undefined elements that MUST occur in the segment at this position. Elements that repeat
may occur up to 99 times and are not affected by the value of the maxOccurs attribute.
</documentation>
</annotation>
</element>
</choice>
</complexType>
</element>
Expand Down

0 comments on commit dc9d01e

Please sign in to comment.