How To Use OBOE 
Open Business Objects for EDI From a Java Programmer's Perpective

Version 3.5.7


Copyright 1999-2007 - American Coders, Ltd. Raleigh NC USA


Author: Joe McVerry


WORK IN PROGRESS


Last updated 2007-09-10.



Table Of Contents

  1. Introduction
    1. Why Should You Use OBOE?
    2. Purpose Of This Document
  2. What Is OBOE?
    1. Other Functionality
    2. Why The XML Rules Engine?
  3. An Overview Of Classes
      EDI Envelope Hierarchy
    1. Envelope - Abstractly And Concretely
    2. Functional Groups
    3. About Dynamic And Static Classes
    4. Transaction Set Its Template And Factory Classes
    5. Tables and Templates
    6. Loops and Templates
    7. Segments and Templates
    8. Composite Data Elements and Templates
    9. Data Elements and Templates
    10. Other Classes
    11. Utility And Exception Classes
    12. External Classes You Need To Get On Your Own
  4. EDI Structure Rules Are Defined in XML Files.
    1. The XML Rules
    2. The DTD File:TransactionSetRules.dtd
  5. Installation
    1. Where To Place OBOE.properties File
    2. Where To Place The XML And DTD Files
    3. Transaction Set Rules DTD Description (Basic Edition)
    4. Transaction Set Rules DTD Description (Extended Edition)
    5. Validating Methods.
    6. The IDLISTxxx XML Files
    7. The IDListClass Class
    8. The XML File
    9. The OBOE Properties File
      1. The OBOE Properties Description
      2. Where To Define The OBOE Properties File
  6. Programming
    1. Parsing An EDI Document
        Using the Properties File To Specify Specific Rules Files
      1. Using A Non Specific Rules File
      2. Using A Version Specific Rules File
      3. Using A Sender Specific Rules File
      4. Using A Receiver/Vendor/Production Specific Rules File
    2. Building An EDI Document
      1. Building An Envelope
      2. Adding Transaction Sets
        1. Method 1 - Building From A Local File Containing XML Rules
        2. Method 2 - Building from a transactionset object for a specific trading partner
        3. Method 3 - Building from a transactionset object for a specific version and production
        4. Method 4 - Building From A URL, File With XML Rules Are Not Local
        5. Using In Memory Stored Transactions Sets
      3. Instantiating The XML Parser
        1. Local File Example:
        2. Remote File Example:
        3. Returning A Transactionset
        4. How The Transaction Set Is Built
      4. Creating A Table
      5. Loops
      6. Segments
        1. Creating A Segment
        2. Getting To A Segment
      7. Data Elements
        1. Creating A Data Element
        2. Flavors Of Data Elements
        3. Getting To A Data Element
        4. Setting Data Element Values
        5. Assigning Default Value From The Rules File
        6. Getting Data Element Values
      8. Creating A Transaction Set XML File
        1. Requesting Other Formats.
    3. Parsing An XML/EDI Document
      1. The XML Rules And Document Files
        1. Transactionsets And Table Parsing
        2. Tables, Loops And Segment Parsing
        3. Loop Parsing
        4. Segment Parsing
        5. Segment And Data Element Parsing
      2. Creating A Transaction Set XML File
      3. Pulling Data From Segments And Data Elements
        1. Getting To The Data
    4. The OBOE Mail Classes
      1. Transmitting An EDI Document
      2. Receiving An EDI Document
      3. Other Considerations For An EDI Document
    5. The OBOE FTP Class
      1. FTP Transmission
      2. Receiving By FTP
    6. Sample Source Programs
      1. viewsamples And viewsample
      2. EDImailcall
  7. Other Source Programs
  8. Other Sources Of Information
  9. Acknowledgments
  10. Appendices



Introduction

Why Should You Use OBOE?

OBOE - Open Business Objects for EDI is a collection of Java classes that build and translate EDI documents. By using OBOE, it becomes easier for you to create a powerful and flexible method to handle a variety of different data formats and translate them into EDI/XML documents or legacy EDI definitions. By using an XML-based rules engine to build and parse EDI documents, OBOE allows you the flexibility to respond to EDI/XML standards as they are developed. OBOE allows you to use existing components that are already widely available on the Internet for your Java Development Kit, XML Parser and more. OBOE also allows you to transmit and receive EDI documents by Internet Mail (Extended Edition only)

If you need to create an EDI program that can accept EDI data from other systems that use a different EDI format, or if you need to translate data from an EDI legacy system, OBOE is perfect for you. With OBOE, it is possible to have the OBOE rules files for specific customers, X12 versions or inbound/outbound type files.

The classes you need to run OBOE are available free for a 30 day trial period from this site for download (you will have to download some additional classes yourself). You can also arrange for American Coders, Ltd. to provide expert support for your OBOE development efforts.

The Purpose Of This Document

This document shows how your Java programs and OBOE can be used to build EDI objects. The document explains how to write programs that interact with these objects through the package method calls.

The OBOE package contains several source sample programs. You should read these programs to learn how write OBOE based Java applications and applets. Reading and using the sample programs is the best way to become familiar with the OBOE System.

The sample programs won't teach you Java, or how to write a Java application or applet. The sample programs won't teach EDI implementations. Nor will the programs explain the inner workings of the OBOE classes.

The samples provide a guide on how to write to the OBOE API.

The document explains Open Business Objects for EDI and its inner workings.

Remember, the document does not show how you to write Java programs nor teach EDI. You should be very familiar with the Java programming language and EDI standards prior to using OBOE.

Return to Contents


What Is OBOE?


OBOE uses an XML parser for a rules based engine to create EDI Objects. The EDI objects, in turn, are used to build and parse an EDI document or an EDI/XML file.

OBOE XML files fuels the rules based engine. These XML files define the structure of EDI objects through a base set of classes. These rules files and the Java classes are based on legacy EDI Definitions, primarily ANSI/X12 and UN/EDIFact. OBOE can also be used to build EDI/XML objects. And just as OBOE can translate legacy EDI document, these new EDI/XML objects can translate EDI/XML documents into the EDI objects. Which, by the way, can be used to create legacy EDI objects.

Again, OBOE's primary use for XML is to build Java EDI Objects. The XML files map to existing EDI structures or definitions.

As the OBOE XML rules file is parsed and depending on the type of object, the OBOE runtime package creates literally hundreds of objects of two flavors, fixed and template. The fixed objects created are the TransactionSet object and from one to three Table objects. All other objects - loops, segments, composites and data elements are first defined through the template objects. As an EDI document is parsed the template objects are used to create the fixed objects that they represent.

When an incoming EDI document is passed to the TransactionSet object the  template objects contain methods to parse the document. Using the parsed text and the template characteristics a dynamic EDI object is built and attached to its parent object, an Envelope. So, for example, a template object representing a "name" data element, such as an X12 93 data element or an EDIFact C080, is used to create a DataElement object of the same type. Just as the template data element is attached to its parent segment, the DataElement object will become part of the same parent segment or composite. So, TemplateLoops are used to create Loops, TemplateSegments are used to create Segments; TemplateComposites are used to create CompositeDEs and TemplateDEs are used to create DataElements. So, in turn, Loop and Segment objects are attached to a table object or its parent Loop object by its template. Composite data element objects are attached to its parent segment object by its template. And data element objects are attached to a its parent segment or composite data element object by its template. This all occurs while the core objects parse an EDI document.

When you need to build an EDI object, your program will request that the dynamic objects be built through calls to the objects' parent object and, indirectly, to its template (or fixed) objects. Your program calls methods in the parent object of the to-be-built object. The parent object uses the same template objects, mentioned above, to build the requested object. For instance, if a segment needs a particular data element, a method call is made to the segment object. The method creates the data element object. The segment method knows about all the template data element objects that are part of its hierarchy. The segment method in turn calls a method of the appropriate data element template object. The template data element creates the fixed data element object. The fixed data element object is returned to the requesting segment method.

Other Functionality

Available in the Extended Edition version is another OBOE function is to transmit and receive EDI Documents using Internet Mail. The How To and the Why For is discussed later.

What's not implemented in OBOE is an external database interface for storing and retrieving EDI documents. When I designed the system, I knew that most EDI systems have been around for a long time. For you folks that have to deal with legacy systems, there are plenty of available hooks in OBOE to provide an interface between your legacy systems and OBOE. How? Well, most of these systems are using SQL databases, such as MySQL, DB2 and Oracle. By using Java's JDBC classes, connecting to these legacy databases access is easy and already available. For those who don't have a legacy systems to deal with, the design allows you build a OBOE application to your own specifications without requiring OBOE to bind to a specific data store.

Why The XML Rules Based Engine?

Early in the release of the product, several people noted how some computer systems use rule engines. Not knowing how to write a rules engine, I went ahead and designed the system so that each EDI object had its own Java class source file -- such as a Purchase Order Object, a Request Validation segment, and a Message Direction Code data element. This created a rather large and cumbersome system of several-hundred source programs. Which, in turn, became very difficult to maintain. So, it was time for a rules engine. But what tool to use, a database, a flat file,... ahhh XML. It was an easy choice. XML is a great data definition tool and several web sites offered Java classes for parsing XML files. (see Apache, IBM, SUN, and Microsoft)

Little did I realize that others were doing the same. But I went ahead a designed a DTD and XML file to map to EDI. Thus a XML file is used to create the OBOE objects, from the same objects designed in earlier OBOE releases. These OBOE objects form the basis of the static classes, as mentioned above.

As it turns out, the best thing about XML is that it is so easy to use.

Return to Contents


Overview of Classes

EDI Envelope Hierarchy

Envelope - Abstractly And Concretely


This abstract class represents an entire EDI Document Object.
This class represents a X12 EDI Envelope Object.
This class represents an EDIFact EDI Envelope Object.

This class is a container class for an EDI transmission. It contains 3 primary objects -- Interchange Header segment, Functional Group container and a Interchange Trailer. Note outside the U.S. EDIFact does not require functional groups. The OBOE application still utilizes the concept even though it does not require Functional Group Headers or Trailer segments. Functional groups are stored in a Vector of the Envelope class. An envelope may contain several functional groups. The Envelope class provides methods to add, get and remove functional groups from the Vector as well as return the number of functional groups in the Envelope.

The Envelope class can also contain several other optional segments depending on whether it represents an X12 document or an EDIFact document.

The primary or super Envelope class is actually an abstract class used by the X12Envelope and EDIFactEnvelope classes. The Envelope class contains several attributes related to the internal representation of a message, such as EDI type, delimiters, etc.

X12Envelope Attributes

Name Type Purpose
ISA_Interchange_Control_Header Segment ISA segment
ISB_Grade_of_Service_Request Segment ISB segment (optional)
IEA_Deferred_Delivery_Request Segment IEA segment (optional)
InterchangeAcknowledgments Vector of Segments TA1 segments (optional)
ISE_Interchange_Control_Trailer Segment ISE Segment

X12Envelope Constants

Name Value Purpose
SEGMENT_DELIMITER
'\n'
End of segment marker. I used cr/lf for debugging. Some use 0x1f while others use '~'.
FIELD_DELIMITER
'*'
End of field marker.
GROUP_DELIMITER
'<'
End of group marker.

EDIFactEnvelope Attributes

Name Type Purpose
UNA_Service_String_Advice Segment UNA segment (optional)
UNB_Interchange_Header Segment UNB segment
UNZ_Interchange_Trailer Segment UNZ Segment

EDIFactEnvelope Constants

Name Value Purpose
SEGMENT_DELIMITER
'
End of segment marker.
FIELD_DELIMITER
+
End of field marker.
GROUP_DELIMITER
:
End of group marker.

Functional Groups

The FunctionalGroup object is a carry over from the X12 functional group concept which is grouping Transaction Sets into common groups. The FunctionalGroup object acts as a container for TransactionSet objects by storing them in a Vector object. The class provides methods to add, get and remove transaction sets from the Vector as well as get a count of the number of transaction sets within the functional group.

Functional groups are not required for EDIFact EDI. The OBOE EDIFact Envelope object utilizes this concept even though it does not required. If your application is EDIFact and your trading partners do not use functional groups then your programs can simply ignore the functional Group Headers or Trailer segments.

protected Segment header;
protected Vector transactionSets = new Vector();
protected Segment trailer;

About Dynamic and Static Classes

As mentioned above OBOE creates two sets of classes -- dynamic (the real EDI objects) and static (the template classes).

Template Classes - The Static Classes

Template Classes are the internal representation of the XML rules file. Therefor they represent the structure of an EDI object. The OBOE EDI Objects (the dynamic class) objects are built by calls to the template classes. EDI data is not stored in the template classes. Also a template class know nothing about the status or content of its static counterpart.

The template classes extend java.IO.Serializable or java.IO.Externalizable. Serialization allows the template classes to be stored locally. Storing the classes on the local hard drive allows the package to reuse the objects and thereby reduce the need to reparse the XML rules file. The package date checks both the XML rules file and its serialized object file. If the XML rules file is newer then the package will reparse the XML file and recreate the serialized file. Otherwise the package will read the serialized file to create the template objects.

EDI Object Classes - The Dynamic Classes

The dynamic classes are the internal representation of an EDI document. The document parser or an OBOE program interacts with these classes to store and retrieve document data. The dynamic classes contain references to their static counterpart

Transaction Set Its Template And Factory Classes

This class represents an entire EDI Transaction Object
This class is the base for each transaction contained within an Envelope. It contains the EDI objects: tables, loops, segments, composite data elements, and data elements. The TransactionSet is also represented by its template class. The TemplateTransactionSet class is a container for the sub template classes starting with the TemplateTable class. The TransactionSet class' two primary functions are to parse and get. The parse method is used to parse an incoming EDI document. Get and getFormattedText methods are use to build an EDI document. To access children objects, such as segments, calls are made through the table object's methods.

Note: The OBOE design requires at least one table object within a TransactionSet. If a particular EDI document is defined without a table, meaning only segments, then the XML rule file for the TransactionSet must define a Header table.

TransactionSetFactory

This class builds a preliminary version of all the EDI objects based on an XML file that it parses.

This class reads in an OBOE XML rules file to build EDI objects. Processing is simple. As each element is read from the rules file a template object is built. If an object is contained within another such as a segment within a loop or a data element within a segment, a template object is created and assigned to the owning template object.

This class extends the SAX2 DefaultHandler parser class. The SAX2 parser is an event driven XML file parser.

The TemplateTransaction set class contains all the template objects needed for a particular transaction set. This class, like the other template classes, is an extension of java.io.serializable. To reduce processing time of reading and parsing the XML rules file every time a transaction set needs to be built the factory class does two things.

  1. The template file is stored in an external format. The TransactionSetFactory searches the local directory structure for rules files based on its Transaction set ID and an XML prefix. (for instance 840.xml or ORDERS.xml.) Then the factory class searches for an associated object file with the same filename prefix but with the filename suffix of "object" (for instance 840.object or ORDERS.object.) If the object file is not found the factory class will parse the OBOE rules file and then store the OBOE EDI objects for that particular transaction set into an object file. Thereby allowing the class to simply read in the rules and removing the parsing step the next time the transaction set class is requested to be built.
  2. While the application is active, the TransactionSetFactory stores the parsed template objects in a Hashtable object. When subsequent calls are made for a rules file that has already been parsed or loaded the factory simply passes the in-memory stored object. This one step alone reduces file input processing time considerably.

Tables and Templates

Tables are containers for loops and segments. Tables provide access methods to the loops and segments it holds. Likewise Template Tables are containers for template loops and template segments. TemplateTable provides access methods to the template loops and template segments it holds.

As mentioned above, if an EDI document does not define a table you must define a header table in the XML TransactionSet. The document's segments to this table.

Classes that dynamically represent the 3 EDI tables, header, details, summary.

Classes that contain TemplateSegments and statically represent the dynamic tables.

Loops and Templates

Loop

A class that represents an EDI Loop. Loops are containers for other segments and other loops.

TemplateLoop

Class represents a fixed or static version of an EDI Loop. Used by the TransactionSetFactory class.

Constructed when the XML rules file is read. This class is used to build the dynamic loop class it represents. As a loop and segment container it also contains child TemplateLoops and TemplateSegments.

ITemplateLoopContainer

An interface for describing methods for storing and accessing TemplateSegments. This interface defines TemplateLoops containership

Segments and Templates

Segment

A class that represents an EDI segment. Segments are containers for composites and data elements.

TemplateSegment

Class represents a fixed or static version of an EDI segment. Used by the TransactionSetFactory class.

Constructed when the XML rules file is read. This class is used to build the dynamic segment class it represents. Like its dynamic counter part which contain composite and DataElement objects the TemplateSegment object may contain template composites and template data elements.

ISegmentContainer

An interface for defining how Segments are stored.

This interface defines segment containership

ITemplateSegmentContainer

An interface for describing methods for storing and accessing TemplateSegments. This interface defines TemplateSegments containership

Composite Data Elements and Its Template

CompositeDE

A class to represent an EDI Composite Data Element. A CompositeDE is EDI's way of defining a special type of Data Element container.

A class to statically represent an EDI Composite Data Element. This class is used to create its composite counterpart.

Data Elements

This is a collection of classes used to describe the various data element types defined in EDI. This super class provides for all the externalized methods used by the subordinate classes, DateDE, CharDE...

DataElement

A class to describe all EDI Data Elements. Used as a super class to specific data element types.

TemplateDE

A class to provide preliminary definitions of a data element. Constructed with XML data this class provides no real purpose to the general application. It is used to build its data element counterpart.

IDataElementContainer

An interface describing methods for storing data elements.

This interface defines segment containership

Character Data Elements

A class for EDI Character Data Elements.

Binary Data Elements

A class for EDI Binary Data Elements.

Date Data Elements

A class for EDI Date Data Elements.

ID Data Elements

A class for EDI ID Data Elements.

Numeric Data Elements

A class for EDI Numeric Data Elements.

Real Data Elements

A class for EDI Real Numeric Data Elements

Time Data Elements

A class for EDI Time Data Elements.

Other Classes

ValidXMLEDIParser

This class builds an EDI object from a valid XML file. The OBOE application can create output to represent an EDI object is several formats. One format is in a valid XML format which is validated against by the DTD file. Your application uses this class to parse the XML/EDI file into EDI objects.

This class builds an EDI object from a well formed XML file. Unlike its valid XML counter part a well formed XML file is not validated against a DTD. Your application uses this class to parse the XML/EDI file into EDI objects.

DocumentParser

This abstract class describes how EDI objects are extracted from an EDI Document.

DocumentHandler

This interface describes how the parser class notifies EDI object events when parsing EDI objects from an EDI Document.

X12DocumentParser

This class extracts X12 EDI objects from an EDI Document.

X12DocumentHandler

This class stores X12 EDI objects from an EDI Document in an envelope container. When working with X12 documents you would work with class most of the time.

EDIFactDocumentParser

This class extracts EDIFact EDI objects from an EDI Document.

EDIFactDocumentHandler

This class stores EDIFact EDI objects from an EDI Document in an envelope container. When working with UN/EDIFACT documents you would work with class most of the time.

Tokenizer

Class with methods to break down an EDI Document into tokens.

DocumentErrors

This class is used to track errors while parsing an incoming EDI object. Also it is used in conjunction with the base classes validate method to track errors with an EDI object and the rules defined for that object.

Utility And Exception Classes

Utility classes to format date and time fields.

Also contains an XML normalizer method. You use this method to normalize a String representing XML data. Normalization is the process of replacing XML specific markers, such as '>' with text '>'

Byte Conversion Utility This class provides static methods to convert bytes to base64 characters. It is only used by the mail classes.

OBOE Exception Class Exception class for throwing OBOE errors. This class extends the Java RuntimeException class. By using runtime exceptions if an exception is uncaught the class allows a failing program to continue.

External Classes You Need To Get On Your Own

OBOE is built using components from other Java package providers. To build code using the OBOE classes you must visit several other web sites to get their classes. I don't provide these external classes with the OBOE product because some of the other package owners do not provide a general license agreement to distribute their development environment. Specifically you will need a Java Developer Kit (JDK) Java2 (for the Swing classes), the Java Mail package (Extended Edition only), the Java Activation Framework package (Extended Editoin only), the Java Cryptography Extensions (Extended Editoin only), and a XML parser.

JDK

To compile the OBOE files you will need a Java Developer's Toolkit. If you plan on using the mail classes supported by OBOE you need the Java2 environment. The mail viewer requires Swing and mail encryption requires the Java Cryptography Extensions of Java2.

There are several JDKs on the market. Some free, some you have to pay for.

At this time I program and test with the Java development tool Eclipse.   This excellent tool is available from The Eclipse Website.

Java Mail

To use the OBOE Extended Edition, let alone compile the Extended Edition source files, you will need the Java mail jar file from Sun. It is available at http://java.sun.com/products/javam ail/ these classes provide access to SMTP mail server, for outgoing mail, and to IMAP mail server, for incoming mail. If you need access to a POP3 incoming mail server you need to download the POP3 package class at the same site.

Java Activation Framework (JAF)

One of the requirements for the Java Mail package is another package from Sun called Java Activation Framework or JAF. It is available at http://www.javasoft.com/be ans/glasgow/jaf.html The primary purpose of this class to act as an agent between a MIME specified document and a Java application or class.

Java Cryptography Extension (JCE)

One of the requirements for the Java Mail package is another package from Sun called Java Cryptography Extension. It is available at http://www.javasoft.com/products/jce . The primary purpose of this class to support encryption of mail documents. This package may be supplemented by another vendor's cryptography extension.

XML Parser

SAX - Simple API

OBOE uses the SAX (Simple API for XML) API (application programming interface) XML parser. By using the TransactionSet DTD and a validating SAX parser your TransactionSet XML file is validated prior to being loaded into OBOE objects.

Why Not DOM?

I didn't choose DOM for two reasons. First, DOM returns a tree structure of your document. Since the OBOE already builds a tree structure of an EDI document This is redundant. Second, SAX has a faster start-up. Since SAX starts returning document objects immediately the objects created by OBOE would share this immediacy also.

Return to Contents


EDI Structure Rules Are Defined in XML Files.

As you have read elsewhere in this document OBOE uses XML files to define the structure and rules of all EDI objects.

The XML Rules

Each element object in an OBOE XML file represents an EDI object. These elements map one-for-one. As OBOE receives an XML element from the SAX parser it creates a Java object. Some objects, such as transaction sets, are used through-out the life of the EDI object life, others use, such as TemplateSegments, are created to create a real or usable object when needed, in this case a segment.

Since a DTD file is used with the validating parser a lot of up-front editing is reduced for the OBOE processor. For instance, the validating parser insures that a data element is correctly related to a transaction set.

The DTD File:TransactionSetRules.dtd

One DTD file is used to define one complete EDI transaction set. The file describes the transaction set, from one to three tables, the loops and segments within tables and other segments, composite data elements and data elements. The description generally includes a name, id, description and xmltag attribute. Some of the elements may have other attributes.

Since the 2.5.0 release a second rules file, envelope.dtd, was introduced. This rules file describes the format of envelopes by the structure of the envelope segments (e.g. ISA or UNB), functional groups and its segments. Do note that the OBOE package still uses the static class definitions for envelopes and the other envelope structures you can create a envelope rules file in case the OBOE definitions do not meet your needs.

Since OBOE is available in two packages, there are two distinct DTD files. While the structure is similar the Extended Edition contains several nodes not found in the Basic Edition.

Installation

Where To Place The OBOE.properties File

The parser looks for the properties file in one of four location in this order:

You should refer to your JDK and Operating System documentation on setting the environment variables.

Where To Place The XML and DTD File

The parser looks for the rules files in a location as specified by the xmlPath in the OBOE.properties file. Refer to

Transaction Set Rules DTD Description (Basic Edition)

<?xml encoding="UTF-8"?> <!-- OBOE release 3.5.0 Thursday, February 22, 2007--> <!-- http://www.americancoders.com --> <!-- OBOE - Open Business Objects for EDI --> <!-- Purpose: validates EDI rules --> <!-- 3.4.0 change: added used attribute to most major nodes, added exclude/include to idlistfile--> <!-- 3.5.0 change: further defined type attribute of dataElement node added exclude/include to idlistfile--> <!ELEMENT transactionSet (table+)> <!ATTLIST transactionSet name CDATA #REQUIRED id CDATA #REQUIRED revision CDATA #IMPLIED functionalGroup CDATA #IMPLIED description CDATA #IMPLIED xmlTag CDATA #IMPLIED> <!ELEMENT table (segment?, loop?)*> <!ATTLIST table section (header | detail | summary) "header"> <!ELEMENT loop (((segment?, loop?)*)|(copyLoop))> <!ATTLIST loop name CDATA #REQUIRED id CDATA #REQUIRED occurs CDATA #REQUIRED required (M | O | C) "M" used (Y | N) "Y" xmlTag CDATA #IMPLIED> <!ELEMENT copyLoop EMPTY> <!ATTLIST copyLoop refid CDATA #REQUIRED> <!ELEMENT segment ((compositeDE?, dataElement?)*|(copySegment))> <!ATTLIST segment name CDATA #REQUIRED id CDATA #REQUIRED sequence CDATA #REQUIRED description CDATA #IMPLIED occurs CDATA #IMPLIED required (M | O | C) "M" used (Y | N) "Y" xmlTag CDATA #IMPLIED> <!ELEMENT compositeDE (dataElement)+> <!ATTLIST compositeDE name CDATA #REQUIRED id CDATA #REQUIRED description CDATA #IMPLIED sequence CDATA #IMPLIED required CDATA #IMPLIED occurs CDATA #IMPLIED used (Y | N) "Y" xmlTag CDATA #IMPLIED> <!ELEMENT dataElement (idList | idListClass | idListFile)?> <!ATTLIST dataElement name CDATA #REQUIRED id CDATA #REQUIRED type (A | AN | B | DT | ID | N| N0 | N1 | N2 | N3 | N4 | N5 | N6 | N7 | N8 | N9 | R | TM) #REQUIRED sequence CDATA #IMPLIED required CDATA #IMPLIED description CDATA #IMPLIED minLength CDATA #REQUIRED maxLength CDATA #REQUIRED occurs CDATA #IMPLIED used (Y | N) "Y" xmlTag CDATA #IMPLIED> <!ELEMENT idList ((idCode, idValue)*)> <!ELEMENT idCode (#PCDATA)> <!ATTLIST idCode used (Y | N) "Y"> <!ELEMENT idValue (#PCDATA)> <!ELEMENT idListClass EMPTY> <!ATTLIST idListClass className CDATA #REQUIRED> <!ELEMENT idListFile EMPTY> <!ATTLIST idListFile fileName CDATA #REQUIRED include CDATA #IMPLIED exclude CDATA #IMPLIED> <!ELEMENT copySegment EMPTY> <!ATTLIST copySegment refid CDATA #REQUIRED>
Element
Attribute
Description of XML Contents
Required
TransactionSet name see EDI definition. example value 'Request For Quotation'  
  id see EDI definition. example value '840'  
  revision see EDI definition, maybe critical to the Implementation Convention of the sender or receiver. Not required
  functionalGroup see EDI definition Not required
  description if not specified name is used Not required
  xmlTag Used by getFormatted methods when generating XML and the ValidatableXMLParser. If not specified the id field is used as the tag name. Not required
table
child to transactionSet
section Values are header, details, and summary. Each must be unique within the transaction set.  
  xmlTag   Not required
loop
child to table or loop
name see EDI definition, example value 'Data Segment Note'  
  id see EDI definition. example value '2000' or 'HL'  
  occurs use -1 for unlimited how many times the loop occurs.
  required 'M' for mandatory, 'O' for optional or 'C' for computed defaults to 'M', presently 'C' is treated as optional
  used 'Y' used by implementation, 'N' not used.
If marked as 'N' all elements within the loop object are ignored by the OBOE processor
defaults to 'Y'.
  xmlTag Used by getFormatted methods when generating XML and the ValidatableXMLParser. If not specified the id field is used as the tag name. Not required
copyloop
child to loop
refid copy a previously defined loop as defined by its id field  
segment
child to table or loop
name see EDI definition, example value 'Data Segment Note'  
  id see EDI definition. example value 'AK3'  
  sequence sequence number as defined by the EDI specifications.  
  description if not specified name is used Not required
  occurs use -1 for unlimited, must be 1 for first segment in loop  
  required 'M' for mandatory, 'O' for optional or 'C' for computed defaults to 'M', presently 'C' is treated as optional
  used 'Y' used by implementation, 'N' not used.
If marked as 'N' all elements within the segment object are ignored by the OBOE processor
defaults to 'Y'.
  xmlTag Used by getFormatted methods when generating XML and the ValidatableXMLParser. If not specified the id field is used as the tag name. Not required
copysegment
child to segment
refid copy a previously defined segment as defined by its id field  
compositeDE
child to segment
name see EDI definition  
  id see EDI definition  
  description if not specified name is used Not required
  sequence Sequence with in segment see EDI definitions defaults to position relative to its position with in the segment rule
  required    

occurs
The number of times this composite may repeat.  New for Version 3.1.  Written for X12 version greater that 4010 and EDIFACT 9735-2.
Defaults to '1'
  used 'Y' used by implementation. 'N' not used.
If marked as 'N' all elements within the composite object are ignored by the OBOE processor
defaults to 'Y'.
  xmlTag Used by getFormatted methods when generating XML and the ValidatableXMLParser. If not specified the id field is used as the tag name. Not required
dataElement
child to segment and compositeDE
name see EDI definition  
  id see EDI definition  
  type binary, char, date, id, numeric, real, or time.  
  sequence Sequence with in segment or composite see EDI definitions defaults to position relative to its position with in the segment or composite rule
  required    
  description    
  minLength The base package ignores this value. It is used by data element class validate method in the Extended Edition.  
  maxLength The base package ignores this value It is used by data element class validate method in the Extended Edition.  

occurs
The number of times this element may repeat.  New for Version 3.1.  Written for X12 versions greater than 4010 and EDIFACT 9735-2
Defaults to '1'
  used 'Y' used by implementation. 'N' not used. defaults to 'Y'.
  xmlTag Used by getFormatted methods when generating XML and the ValidatableXMLParser. If not specified the id field is used as the tag name. Not required
idList
child to dataElement
    defines an inplace list of values associated with an ID type field
use only if the dataElement type is defined as "ID"
idCode
child to idList
used 'Y' used by implementation. 'N' not used. defaults to 'Y'.
idValue
child to idList
     
idListClass
child to dataElement
className Specifies a Java class that will provide the idCode and idValue list  
idListFile
child to dataElement
fileName Specifies a XML file containing the idCode and idValue list  
  include a list of codes to only use, example 00,02-05,99 says to validate only 00 02 03 04 05 and 99 that are specified in the idList file  
  exclude a list of codes to ignore, example 00,02-05,99 says to validate all values in file except 00 02 03 04 05 and 99  
copysegment
child to segment
refid copy a previously defined segment as defined by its id field  

Transaction Set Rules DTD Description (Extended Edition)

<?xml encoding="UTF-8"?> <!-- OBOE release 3.5.0 Thursday, February 22, 2007--> <!-- http://www.americancoders.com --> <!-- OBOE - Open Business Objects for EDI --> <!-- Purpose: validates EDI rules --> <!-- 3.4.0 change: added used attribute to most major nodes, added exclude/include to idlistfile--> <!-- 3.5.0 change: further defined type attribute of dataElement node--> <!ELEMENT transactionSet (table+)> <!ATTLIST transactionSet name CDATA #REQUIRED id CDATA #REQUIRED revision CDATA #IMPLIED functionalGroup CDATA #IMPLIED description CDATA #IMPLIED validatingMethod CDATA #IMPLIED xmlTag CDATA #IMPLIED> <!ELEMENT table (segment?, loop?)*> <!ATTLIST table validatingMethod CDATA #IMPLIED section (header | detail | summary) "header"> <!ELEMENT loop (((segment?, loop?)*)|(copyLoop))> <!ATTLIST loop name CDATA #REQUIRED id CDATA #REQUIRED occurs CDATA #REQUIRED required (M | O | C) "M" validatingMethod CDATA #IMPLIED used (Y | N) "Y" xmlTag CDATA #IMPLIED> <!ELEMENT copyLoop EMPTY> <!ATTLIST copyLoop refid CDATA #REQUIRED> <!ELEMENT segment (((compositeDE?, dataElement?)*, elementRule*)|(copySegment))> <!ATTLIST segment name CDATA #REQUIRED id CDATA #REQUIRED sequence CDATA #REQUIRED description CDATA #IMPLIED occurs CDATA #IMPLIED required (M | O | C) "M" validatingMethod CDATA #IMPLIED used (Y | N) "Y" xmlTag CDATA #IMPLIED> <!ELEMENT compositeDE (dataElement)+> <!ATTLIST compositeDE name CDATA #REQUIRED id CDATA #REQUIRED description CDATA #IMPLIED sequence CDATA #IMPLIED required CDATA #IMPLIED occurs CDATA #IMPLIED validatingMethod CDATA #IMPLIED used (Y | N) "Y" xmlTag CDATA #IMPLIED> <!ELEMENT dataElement ((idList | idListClass | idListFile)?, (default)?)> <!ATTLIST dataElement name CDATA #REQUIRED id CDATA #REQUIRED type (A | AN | B | DT | ID | N| N0 | N1 | N2 | N3 | N4 | N5 | N6 | N7 | N8 | N9 | R | TM) #REQUIRED sequence CDATA #IMPLIED required CDATA #IMPLIED description CDATA #IMPLIED minLength CDATA #REQUIRED maxLength CDATA #REQUIRED occurs CDATA #IMPLIED validatingMethod CDATA #IMPLIED used (Y | N) "Y" xmlTag CDATA #IMPLIED> <!ELEMENT idList ((idCode, idValue)*)> <!ELEMENT idCode (#PCDATA)> <!ATTLIST idCode used (Y | N) "Y"> <!ELEMENT idValue (#PCDATA)> <!ELEMENT idListClass EMPTY> <!ATTLIST idListClass className CDATA #REQUIRED> <!ELEMENT idListFile EMPTY> <!ATTLIST idListFile fileName CDATA #REQUIRED include CDATA #IMPLIED exclude CDATA #IMPLIED> <!ELEMENT default (#PCDATA)> <!ATTLIST default from (constant | property | method) #REQUIRED> <!ELEMENT elementRule EMPTY> <!ATTLIST elementRule rule (oneOrMoreMustExist | ifFirstExistsThenAllMustExist | oneAndOnlyOneMayExist | ifFirstExistsThenAtLeastOneMoreMustExist | allOrNoneMayExist | ifFirstExistsThenNoOthersMayExist) #REQUIRED positions CDATA #REQUIRED> <!ELEMENT copySegment EMPTY> <!ATTLIST copySegment refid CDATA #REQUIRED>
Element
Attribute
Description of XML Contents
Required
transactionSet name see EDI definition. example value 'Request For Quotation'  
  id see EDI definition. example value '840'  
  revision see EDI definition Not required
  functionalGroup see EDI definition Not required
  description if not specified name is used Not required

validationMethod
The name of a static Java method called during the validation process. Not required
  xmlTag Used by getFormatted methods when generating XML and the ValidatableXMLParser. If not specified the id field is used as the tag name. Not required
table
child to transactionSet
section Values are header, details, and summary.  
  xmlTag   Not required

validationMethod
The name of a static Java method that is called during the validation process. Not required
loop
child to table or loop
name see EDI definition, example value 'Data Segment Note'  
  id see EDI definition. example value '2000'  

occurs use -1 for unlimited

required 'M' for mandatory, 'O' for optional or 'C' for computed defaults to 'M', presently 'C' is treated as optional

validationMethod
The name of a static Java method that is called during the validation process. Not required
  used 'Y' used by implementation. 'N' not used.
If marked as 'N' all elements within the loop object are ignored by the OBOE processor
defaults to 'Y'.

xmlTag Used by getFormatted methods when generating XML and the ValidatableXMLParser. If not specified the id field is used as the tag name. Not required
copyloop
child to loop
refid copy a previously defined loop as defined by its id field  
segment
child to table
name see EDI definition, example value 'Data Segment Note'  
  id see EDI definition. example value 'AK3'  
  sequence Sequence number - see EDI definitions
  description if not specified name is used Not required
  occurs use -1 for unlimited, must be 1 for first segment in loop  
  required 'M' for mandatory, 'O' for optional or 'C' for computed defaults to 'M', presently 'C' is treated as optional
  validatingMethod
Specifies static method to call when validation method is called
Not required
  used 'Y' used by implementation. 'N' not used.
If marked as 'N' all elements within the segment object are ignored by the OBOE processor
defaults to 'Y'.
  xmlTag Used by getFormatted methods when generating XML and the ValidatableXMLParser. If not specified the id field is used as the tag name. Not required
compositeDE
child to segment
name see EDI definition  
  id see EDI definition  
  description if not specified name is used Not required
  sequence Sequence with in segment see EDI definitions defaults to position relative to its position with in the segment rule
  required    

occurs
The number of times this composite may repeat.  New for Version 3.1.  Written for X12-4040 and EDIFACT 9735-2. Defaults to 1

validationMethod
The name of a static Java method that is called during the validation process. Not required
  used 'Y' used by implementation. 'N' not used.
If marked as 'N' all elements within the composite object are ignored by the OBOE processor
defaults to 'Y'.
  xmlTag Used by getFormatted methods when generating XML and the ValidatableXMLParser. If not specified the id field is used as the tag name. Not required
dataElement
child to segment and compositeDE
name see EDI definition  
  id see EDI definition  
  type char, date, id, numeric, real, or time.  
  sequence Sequence with in segment or composite see EDI definitions defaults to position relative to its position with in the segment or composite rule
  required    
  description    
  minLength The base package ignores this value. It is used by data element class validate method in the Extended Edition.  
  maxLength The base package ignores this value It is used by data element class validate method in the Extended Edition.  

occurs
The number of times this element may repeat.  New for Version 3.1.  Written for X12-4040 and EDIFACT 9735-2. Defaults to '1'

validationMethod
The name of a static Java method that is called during the validation process. Not required
  used 'Y' used by implementation. 'N' not used. defaults to 'Y'.
  xmlTag Used by getFormatted methods when generating XML and the ValidatableXMLParser. If not specified the id field is used as the tag name. Not required
idList
child to dataElement
    defines an inplace list of values associated with an ID type field
use only if the dataElement type is defined as "ID"
idCode
child to idList
used 'Y' used by implementation. 'N' not used. defaults to 'Y'.
idValue
child to idList
     
idListClass
child to dataElement
className Specifies a Java class that will provide the idCode and idValue list  
idListFile
child to dataElement
fileName Specifies a XML file containing the idCode and idValue list  
  include a list of codes to only use, example 00,02-05,99 says to validate only 00 02 03 04 05 and 99 that are specified in the idList file  
  exclude a list of codes to ignore, example 00,02-05,99 says to validate all values in file except 00 02 03 04 05 and 99  
default
(not required)
child to dataElement
from Specifies location of default data from one of three places:
  1. constant - use the contents of the #PCDATA value space.
  2. property - using the #PCDATA value, searches the OBOE.properties files for this value as a name and then uses value associated with name in OBOE.properties.
  3. method - using the #PCDATA value, calls a static method is a class to return a value. Structure of #PCDATA value must be xxxxxx#yyyyyyy where xxxxxx is some class name and yyyyyy is a static method in the class. The static method must not accept any input parameters and it must return a String object.
Required. Also uses the #PCDATA XML value space, specifies data or location of data that can go into the value field
elementRule
(not required)
child to Segment
rule Indicates the specific rule for the elements of this segment. Use one of the following values:
  1. oneOrMoreMustExist
  2. ifFirstExistsThenAllMustExist
  3. oneAndOnlyOneMayExist
  4. ifFirstExistsThenAtLeastOneMoreMustExist
  5. allOrNoneMayExist
  6. ifFirstExistsThenNoOthersMayExist
Required
  positions Specifies the position of all the elements associated with the rule, offset value starts at 1. Use the dataElement position. Required
copysegment
child to segment
refid copy a previously defined segment as defined by its id field  

Validation Methods


All of the primary objects in the transaction set: transaction set, table, segment, loop, composite and data element, have an attribute named validationMethod. The validation method is something you write that is called.  Your method is called after during the validation process.  It always called as the last step in the validation process for the particular object. 

How To Write A Validation Method

Basically you write a static method that accepts two arguments and returns a boolean.

The method may reside in any source file and be associated with any package.  For consistency and ease of maintenance Try to keep the validating methods within the same source program.

The source program will need to import at a minimum two OBOE classes:  DocumentErrors and the class that is to be validated, such as Segment.

The validating method must be public and static.

The method must return a boolean to indicate success or failure. By returning a false your method indicates that method found an error.  Conversely a true indicates no error is found.

The method accepts two objects, the object to be validated and a DocumentErrors object.   The object to be validated can be any one of the primary OBOE objects.  The DocumentErrors object is used by the method to explain the error found.  The object is associated when the rules file is parsed.  OBOE will validate that the method conforms to the three requirements.  If  the method can't be found or the argument list is incorrect the TransactionSetFactory class will throw a parsing exception.

Which Object To Associated The Method With.


You should assign the validation method to the container that has access to every object to be checked.  For instance if you need to check the relationships of data elements within a segment then you would assign the method to the segment object.   Or if you needed to check the relationship of two data elements in different parts of a transaction set then you would assign the transaction set to the validating method.

What If I Need More Than One Method For An Object.

Simply make one single common method for that object and have that method call the other methods.

Example
This is an example of a method accepting a table object.    The object is used to search through all of it's segments with the ID of "REF".  The validation process is verifying that at least one of these REF segments has a DataElement with an id of "128" contains a value of "14".  If one is found it returns a true.  If none is found then the DocumentErrors object is populated with meaningful data and a false is returned.

    public static boolean dValidatingMethod820DetailTableRefs(Table inTbl,    DocumentErrors des)
            throws Exception {
        int iRef = inTbl.getCount("REF"); // there's gotta be one because it's mandatory
        Segment seg = null;
        for (int i = 0; i < iRef; i++) {
           seg = inTbl.getSegment("REF", i);
           if (seg.getDataElement("128").get().compareTo("14") == 0)
             return true;
            }
       
        des.addError( 0,  "128",
            "Required value of \"14\" in 128 field of REF expected in at least one segment",
            inTbl,  "7",  seg);
        return false;
    }
   
  

In the rules file the table entry would read as follows:

    <table section="detail"
        validatingMethod="com.americancoders.tests.dValidatingClass.dValidatingMethod820DetailTableRefs">



The IDList XML Files


The OBOE data element objects IDDE use a secondary XML rules file called IDList files. These files provide a complete list of used ID and Value pairs associated with the IDDE object. For instance in X12, the ID element 353 defines all the Purpose Code for transaction sets. The name/value pair for 353 are the transaction sets id and the description for the transaction set. In the idlist file there would be an entry for each purpose code
EXAMPLE

     	<idlist>
     	<idcode>00</idcode>
     	<idvalue>Original</idvalue>
     	<idcode>01</idcode>
     	<idvalue>Cancellation</idvalue>
     	<idcode>02</idcode>
     	<idvalue>Add</idvalue>
     	</idlist>

In the rules file you may use one of three optional nodes to specify the name/value pairs.

  • Directly in the file with an idlist node,
  • indirectly from an idListFile node. The idListFile node includes a required fileName attribute that defines the file containing the code/value pair definitions. There are two optional attributes include and exclude. These two attributes act as filters to allow you to further decide what code/value pairs are to be used for the particular element. The filter acts against the contents of the file. Include indicates what codes are used while exclude indicates what codes are not to be used. If both are specified then the second attribute will act as a filter of the first attribute filters. The value of the attribute is a comma delimited, dash range specifying stream. An example include="AA-BB,CC,LK-MO,ZZ" indicates that all values between AA through BB, LK through MO, the specific value of CC and ZZ are to be used as valid values.
  • finally another indirect method using an idListClass node.

    The IDListClass Class


    OBOE offers another way to externalize IDList Codes and Values. A java class that implements the Interface IDListProcessor can be used to provide the codes and values need for a particular IDDE dataElement. This class could be used when codes and values are stored in a SQL database or some other file system.
    The class is loaded when the rules file is parsed.
    For further information see the JavaDoc file referring to com.americancoders.edi.IDListProcessor.

    The XML File

    All OBOE EDI definitions are found in a XML rules file. These XML files use the TransactionSetRules.DTD file for validating their definitions.

    The XML file for a particular transaction set can get very large, well over 500k characters long.

    There is a XML facility to include, or import, other XML files. Using this import facility will simplify a file but may create a large number of files. If you do use this you should break the files logically along the same lines as the DTD elements.

    Return to Contents

    The OBOE Properties File

    The OBOE.properties files is used to store information that describes your system's environment to the OBOE package.

    The OBOE Properties Description

    Parser Property

    Name Description
    xmlpath Directory location of the xml and dtd files
    searchDirective An optional property which instructs the TransactionSetFactory class how to further find a specific rules file. Specify any combination of VTRS
    • V - version
    • T - test or production
    • R - receiver id
    • S - sender id
    Used in conjunction with either fields from an incoming document or fields specified with the TransactionSetFactory class buildTransactionSet method. Refer to the TransactionSetFactory Javadoc for more information
    useObject An optional property which instructs the TransactionSetFactory class to use object files if newer than the XML rules file. If set to any value other than "true" the package will assume false.
    One way of speeding up the OBOE load process is for the package to build object files representing the XML files. This property indicates that the package should take advantage of this feature.
    no specific property name An optional property that is treated as a variable to parse an incoming a well formed EDI/XML file You must specify the name found in the well formed file with a transaction set id
    for example to parse a well formed 840 file, if the XML node name is RequestForQuotation then specify
    RequestForQuotation=840
    Likewise to parse an EDIFact ORDERS transaction set and if the XML node is PurchaseOrderMessage then specify
    PurchaseOrderMessage=orders
    YOU DON'T NEED THIS FOR VALIDATIBLE XML FILES SINCE THE TRANSACTION SET ID IS AN ATTRIBUTE OF THE TRANSACTION SET NODE.
    x12Delimiters An optional property to set x12 delimiters: segment field group
    for example x12Delimiters=|~:
    EDIFactDelimiters An optional property to set EDIFact delimiters: segment field group
    for example: EDIFactDelimiters=^&*
    throwParsingException An optional property to indicate to the two DocumentHandlers if they should throw an Exception if any parsing errors are encountered.
    Default value is true. Possible values are true or false.
    errorLevelToReport A numeric value indicating a threshold value. The value is tested against when an EDI parser finds an error with a message.
    Default value is 1. Possible values are 1 through 10.
    realNumbersRetainPrecision A optional property to indicate if Real data elements should keep the incoming decimal precision. If set to false, decimal point character and trailing zeros will be removed if determined to be unnecessary.
    Default value is false. Possible values are true or false.

    Where To Define The OBOE Properties File

    The packages searches for the OBOE.properties file in the following order:
    1. local directory
    2. user.home directory
    3. java.home directory
    4. classpath environment variable

    Programming

    Parsing An EDI Document

    Parsing an EDI document is accomplished by calling one of four parsers that are part of the OBOE package, X12, EDIFact, XML and Well-Formed XML.

    All OBOE parsers return an Envelope object.

    After parsing an Envelope, either from an X12 document, EDIFact document a well formed EDI/XML file or a valid EDI/XML file, your application will need to work its way through the document tree using the methods available with each tree object, Envelope, FunctionalGroup, TransactionSet, Table, Segment, Composite and DataElement. Below is a very simple example of traversing through an EDI document

    			/* assume document passed in as a java.io.Reader object inRDR */
    com.americancoders.edi.x12.X12DocumentHandler dh1 =
    new com.americancoders.edi.x12.X12DocumentHandler(inRDR);
    X12Envelope env = dh1.getEnvelope();
    Segment interchangeHeader =
    env.getInterchange_Header();
    for (int fgCursor = 0; fgCursor < env.getFunctionalGroupCount(); fgCursor++)
    { /* don't forget to work with the functional group header and trailer */
    FunctionalGroup fg = env.getFunctionalGroup(fgCursor);
    for (int tsCursor = 0; tsCursor < fg.getTransactionSetCount(); tsCursor++)
    {
    TransactionSet ts = fg.getTransactionSet(tsCursor);
    Table tbl = ts.getHeaderTable();
    Segment seg = tbl.getSegment("BEG");
    DataElement de = seg.getDataElement(0);
    }
    }
    Segment interchangeHeader = env.getInterchange_Header();

    Using the Properties File To Specify Specific Rules Files

    Since incoming documents are unknown prior to parsing them OBOE provides a mechanism in which you can specify location of specific Rules files to use. Using a search directive in the OBOE.properties file and specific data of the incoming document, the OBOE package will build a path name to a rules file to use. If the rules file is not found in the built path then the package will look up the directory structure until it finds a matching rules file.

    The X12DocumentParser, X12Envelope, EDIFactDocumentParser and EDIFactEnvelope classes are preprogrammed to use this functionality.

    The searchDirective.
    The OBOE.properties file may contain an optional variable named searchDirective. The variable may use any one of four characters V S R and/or T and specified in any order. Each character, if used, directs the package to build a path name on the specific contents of the incoming document variables. The variable meanings are as follows:

    V Version X12: "480 - Version Release Industry Identifier Code" from GS - Functional Group Header segment
    EDIFact: "0052" and "0054" from UNH segment, this will not work with the ValidXMLParser class since this information is not available at the time the transactionset is parsed.
    R Receiver X12: "I07 - Interchange Receiver ID" from ISA segment
    EDIFact: "0010 - Recipient Identification" from UNB segment
    S Sender X12: "I06 - Interchange Sender ID", from ISA segment
    EDIFact: "0004 - Sender identification", from UNB segment
    T Test or Production X12: "I14 - Test Indicator", values of P or T from ISA segment
    EDIFact: "0035 - TEST INDICATOR", from UNB segment

    Note: The package uses the values of these fields as directory names.
    Note: This logic does not apply to outgoing EDI documents which your application will build. See the TransactionSetFactory buildTransactionSet method for similar type of directory control.
    Note: Be consistent with incoming and outgoing directory names to reduce search and storage requirements.
    If the searchDirective variable is not specified in the OBOE.properties file then only the xmlPath variable will be used to build a XML rules file path.

    Examples

    Using A Non Specific Rules File
    It's simple. Don't specify the searchDirective variable in the OBOE.properties file.
    Using A Version Specific Rules File
    In the OBOE.properties file use searchDirective=V
    Using A Sender Specific Rules File
    In the OBOE.properties file use searchDirective=S
    Using A Receiver/Vendor/Production Specific Rules File
    In the OBOE.properties file use searchDirective=RVT

    Building An EDI Document

    Building an Envelope

    To start building an EDI document you should first create an Envelope object, either X12Envelope or EDIFactEnvelope. From here you will work with the interface header segment, functional groups and interface trailer segment. Since interface and functional group header/trailer segments are not defined in an XML rules file, OBOE contains classes to create these segments for you.

    Functional groups primary purpose is to be a container for transaction sets. In X12 functional groups are an integral part of an EDI document while in EDIFact functional groups are not required. OBOE implements the functional groups for both standards, but is intelligent enough not to generate functional group header/trailers for EDIFact documents.

    Functional groups are stored in the Envelope object in a Java.util Vector object there are methods in the Envelope class to get, add, remove functional groups. And likewise, since functional groups are containers for transactions sets, transaction sets are stored in a Vector object within the functional group with similar getter/setter methods.

    		/* example to create an envelope with a non-specific 840 transaction set.*/
    X12Envelope xenv = new X12Envelope();
    xenv.setInterchange_Header(Interchange_Control_Header.getInstance());
    FunctionalGroup fg = X12FunctionalGroup.getInstance();
    xenv.addFunctionalGroup(fg);
    fg.addTransactionSet(TransactionSetFactory.buildTransactionSet("840"))
    xenv.setInterchange_Trailer(Interchange_Control_Trailer.getInstance());

    		/* example to create an envelope with a partner specific 840 transaction set.
    "R" - look in subdirectroy specified by receiver parameter
    null - ignore version parameter
    "0900098" - receiver parameter - look in this subdirectory
    null - ignore sender parameter
    null - ignore test/production parameter
    */
    X12Envelope xenv = new X12Envelope();
    xenv.setInProcess();
    xenv.setInterchange_Header(Interchange_Control_Header.getInstance());
    FunctionalGroup fg = X12FunctionalGroup.getInstance();
    xenv.addFunctionalGroup(fg);
    fg.addTransactionSet(TransactionSetFactory.buildTransactionSet("840","R",null,"0900098",null,null))
    xenv.setInterchange_Trailer(Interchange_Control_Trailer.getInstance());

    Adding Transaction Sets

    The TransactionSetFactory class is an extension of the XML SAX handlerBase class. The TransactionSetFactory is not constructed, it contains only static methods and class variables. An OBOE class needing a TransactionSet uses the static method buildTransactionSet in the TransactionSetFactory class. These methods create and return a TransactionSet object.

    Method 1 - Building from a local file containing XML rules:

    The buildTransactionSet method accepts one parameter the id field of the EDI object to be created. For instance, if the value '840' is passed then a x12 "Request For Quotation" object would be created. Using the input parameter the method determines where the XML file is located. The methods reads from the OBOE.properties file the directory (or folder) location for all XML rules files. Taking this directory name, appending the parameter, and finally appending the suffix '.XML' the method determines the full path name for the XML rules file. OBOE.properties contains one property, which represents the first part of rule file path. The property name is xmlPath.

    xmlPath as defined in OBOE.properties
    c:/EDIXMLFiles/
    argument passed
    "840"
    file used by the parser
    c:/EDIXMLFiles/840.xml

    Method 2 - Building from a transactionset object for a specific trading partner:

    The second example buildTransactionSet method uses three of seven parameters, an ID field, a searchDirective string and a sender id string.

    		TransactionSetFactory.buildTransactionSet("840","S","TESTERONE",null,null,null))

    xmlPath as defined in OBOE.properties
    c:/EDIXMLFiles/
    argument 1 passed
    "840"
    argument 2 passed - search Directive
    "S"
    argument 3 passed - version directory
    null
    argument 4 passed - sendor directory
    "TESTERONE"
    argument 5 passed - receiver directory
    null
    argument 6 passed - test/production directory
    null
    file used by the parser
    c:/EDIXMLFiles/TESTTERONE/840.xml

    Method 3 - Building from a transactionset object for a specific version and production:

    The third example of the buildTransactionSet method uses four of seven parameters, an ID field, a searchDirective string and a sender id string.

    xmlPath as defined in OBOE.properties
    c:/EDIXMLFiles/
    argument passed
    "840"
    argument 2 passed - search Directive - use the test/production parameter first and then the version parameter to build the path
    "TV"
    argument 3 passed - version directory
    004010
    argument 4 passed - sendor directory
    null
    argument 5 passed - receiver directory
    null
    argument 6 passed - test/production directory
    "P"
    file used by the parser
    c:/EDIXMLFiles/P/004010/840.xml

    Method 4 - Building From A URL, File With XML Rules Are Not Local

    The last buildTransactionSet method accesses two parameters, a URL and an ID field. The URL parameter is a java.net.url object. The id field is a string identifying the EDI transaction set. Using these two parameters and appending a file extension of '.XML', a new URL object is created and passed to the SAX parser.
    URL builds do not support the subdirectory search mechanism

    java.net.URL object passed
    new java.net.URL("www.americancoders.com/xmlFile/")
    for applets use getCodeBase method to get the active URL.
    argument passed
    "840"
    URL used by the parser
    "www.americancoders.com/xmlFile/840.xml"

    Using Memory Stored Transaction Sets

    As mentioned earlier, when the TransactionSetFactory has already parsed or loaded a TransactionSetFactory it will pull the template object from Hashtable object stored with in it. Note like the other TransactionSetFactory attributes and variables, the Hashtable is static and is only valid as long as the OBOE package is active in the JVM.

    Instantiating the XML Parser.

    The buildTransactionSet then creates the SAX parser object; sets the handler base with the newly constructed object and finally calls the parser to parse either the local or remote file.

    Local file example:
    			Properties properties = new Properties();
    FileInputStream inStream = new FileInputStream("OBOE.properties");
    properties.load(inStream);
    String path = properties.getProperty("xmlPath");
    org.xml.sax.Parser parser = new
    com.ibm.xml.parsers.ValidatingSAXParser();
    TransactionSetFactory me = new TransactionSetFactory(parser);
    parser.setDocumentHandler(me);
    parser.parse(path + inTSID + ".XML");
    Remote file example:
    			Properties properties = new Properties();
    URL url = new URL(inURL + inTSID + ".XML");
    System.out.println("URL is " + url );
    org.xml.sax.Parser parser = new com.ibm.xml.parsers.ValidatingSAXParser();
    TransactionSetFactory me = new TransactionSetFactory(parser);
    parser.setDocumentHandler(me);
    parser.parse(url.toString());
    Returning a TransactionSet

    After successfully parsing the XML rules file use the buildTransactionSet method to return a TransactionSet object to your program. This TransactionSet object is built with the SAX parser along with the TransactionSetFactory method. The TransactionSet object contains the tables identified within the TransactionSet rules. Note some TransactionSets do not use all three tables, e.g. 997 Functional Acknowledgment, for these the system requires at least one header table. The table object will contain TemplateSegments, not the real segments, yet. Remember, that templates are static objects. Templates the static objects used to build the dynamic objects. Likewise, the TemplateSegments contain other TemplateSegments, TemplateCompositeDEs and TemplateDEs, which will eventually be used to create their dynamic object. All templates are stored in java.util.Vector objects in their respective owners. Eventually calls through the Table objects or segment objects, to create the necessary segments, composites or data elements.

    The TransactionSet object contains no EDI data. The object is the structure for building an EDI document or parsing an EDI document.

    How The Transaction Set Is Built.

    Every time the SAX parser encounters a new XML element the parser calls the startElement method of the registered handler base. The TransactionSetFactory class contains such a method. This method queries the element, its attributes and values. The OBOE methods starts building a tree of the transaction set, tables, segments, composites and data elements by querying the id field and the associated attributes. The object is then pushed onto a Java.util.Stack object.

    Every time the SAX parser encounters an end to an XML element the object is the popped off the stack.

    By utilizing this stack mechanism the OBOE parser allows recursion and thereby allows segments to own segments and composites to own composites.

    Creating a Table

    Logically, tables are automatically built by the TransactionSetFactory as the XML rules file is read.

    About Loops

    Loops are containers for segments and other loops. Loops are defined in EDI as either loops or groups. The names are synonymous.
    Creating A Loop

    A table or loop object contains a vector of TemplateLoops. To create a loop object, calls are made by the owning object to a TemplateLoop. The template returns an loop object. The loop object returns this loop object to the caller.

    Example from the parse method of Table:

    			Loop currentLoop =
    new Loop((TemplateLoop) templateLoopVector.elementAt(i));
    or you could use the TemplateLoop object to create a Loop object using the loop id: Example:
    			TemplateLoop tsg = (TemplateLoop) templateLoopVector.elementAt(i);
    Loop currentLoop = tsg.createLoop("AK9");
    Eventually you will need to associate a Loop with its owning table or loop. The method addLoop does this by adding the loop object to an internal java.util.Vector. This Vector contains only Loops. Example:
    			headerTable.addLoop(currentLoop);
    Getting to a Loop

    Loops are contained in/owned by Tables, other loops (super loops) or can be stand-alone. Objects that contain Loops implement the ILoopContainer interface. The interface is designed with several methods, most importantly for this discussion to get the loops the object owns. ILoopContainer has four getLoop methods:

    Single Occurring Loops:

    by the EDI Id within the Table or super Loop public Loop getLoop(String ID)
    by its position within the Table or super Loop public Loop getLoop(int iPosNo), position number is relative to 1

    Multiple Occurring Loops:

    by its EDI Id within a sub Loop public Loop getLoop(String ID, int index), index is relative to 0
    by its position within a sub Loop public Loop getLoop(int iPosNo, int index), position number is relative to 1, index is relative to 0

    About Segments

    Loops are containers for dataElements and compositeDEs.
    Creating A Segment

    A table or loop object contains a vector of TemplateSegments. To create a segment object, calls are made by the owning object to a TemplateSegment. The template returns an segment object. The segment object returns this segment object to the caller.

    Example from the parse method of Table:

    			Segment currentSegment =
    new Segment((TemplateSegment) templateSegmentVector.elementAt(i));
    or you could use the TemplateSegment object to create a Segment object using the segment id: Example:
    			TemplateSegment tsg = (TemplateSegment) templateSegmentVector.elementAt(i);
    Segment currentSegment = tsg.createSegment("AK9");
    Eventually you will need to associate a Segment with its owning table or loop. The method addSegment does this by adding the segment object to an internal java.util.Vector. This Vector contains only Segments. Example:
    			headerTable.addSegment(currentSegment);
    Getting to a Segment

    Segments are contained in/owned by Tables, loops or can be stand-alone. Objects that contain Segments implement the ISegmentContainer interface. The interface is designed with several methods, most importantly for this discussion to get the segments the object owns. ISegmentContainer has four getSegment methods:

    Single Occurring Segments:

    by the EDI Id within the Table or Loop public Segment getSegment(String ID)
    by its position within the Table or Loop public Segment getSegment(int iPosNo), position number is relative to 1

    Multiple Occurring Segments:

    by its EDI Id within a Table Loop public Segment getSegment(String ID, int index), index is relative to 0
    by its position within a Table or Loop public Segment getSegment(int iPosNo, int index), position number is relative to 1, index is relative to 0

    About Data Elements

    Creating A Data Element

    As with segments Data Elements are built using a template object. But unlike Segments the owning object does not create a DataElement. DataElements are either created in two ways. When a document is parsed then the element is created. Or when you are creating objects a call to the buildDE method of the owning Segment or Composite must be called. The buildDE method takes one argument, an int, which specifies the position in the Segment or Composite. The buildDE method returns an object so be sure to cast the returned value to the correct type, either a CompositeDE or a DataElement.

    			TransactionSet transactionSet = TransactionSetFactory.buildTransactionSet("840");
    Table currentTable = transactionSet.getHeaderTable();
    Segment currentSegment = currentTable.createSegment("ST");
    currentTable.addSegment(currentSegment);
    DataElement currentDE = (DataElement) currentSegment.buildDE(0);
    System.out.println(currentDE);
    currentDE.set("840");
    currentDE = (DataElement) currentSegment.buildDE(1);
    Flavors of Data Elements

    There are 7 different types of data elements. All are based on the X12 definitions. Some have unique setter/getter methods such as DateDE and TimeDE. All of these classes are based on the super class DataElement.

    1. BinaryDE - used for binary data types.
    2. CharDE - used for alphabetic and alphanumeric data types.
    3. DateDE - used for dates. Stores is value in a java.util.Calendar object. There is logic in the class to force Y2K compliance by pre-pending a '19' on values set with a length of 6 and YY value greater than 50 and pre-pending a '20' for values less than 51. For example, 000419 would become 20000419.
    4. IDDE - almost an extension of CharDE, this class has a list of valid values and description for the values.
    5. NumericDE - numeric data with a specific number of decimal places (0-9).
    6. RealDE - another numeric data type - floating point.
    7. TimeDE - used for times, Stores its value in a java.util.Calendar object.
    Getting to a Data Element

    Segments and Composite Data Elements own DataElements. Objects that contain or own Data Elements implement the IDataElementContainer interface. This interface is designed with several methods, such as getting to a Data Element. IDataElement container has two getDataElement methods:

    by the EDI Id public DataElement getDataElement(String ID)
    by its position
    public DataElement getDataElement(int inSequence), sequence number as defined in the XML rules file which should match the EDI specification

    Setting Data Element Values

    All data elements inherit the super class' set (String inValue) method. But some do have their own special set method.

    DateDE can set a specific part of the date value. With its class variable value as a java.util.Calendar OBOE provides a set method in which specific portions of the date field can be set. This is accomplished by using the java.util.Calendar constants related to dates.

    			method: public void set(int field, int value)

    TimeDE, like DateDE, can set a specific part of the time value. With its class variable value as a java.util.Calendar OBOE provides a set method in which specific portions of the data field can be set. This is accomplish by using the java.util.Calendar constants related to time.

    			method: public void set(int field, int value)
    Assigning Default Value From The Rules File
    Also see

    In the Extended Edition version of OBOE there is a mechanism to assign default values to dataelement fields. Using one of three possible references in the XML rules file along with the data element setDefault method a data elements value can be assigned globally and programmatically.

    In the extended version there is a element named "default" that is a child node of the dataelement node. The default node has one attribute named "from" which may contain one of three values "constant", "property" or "method." The from attribute used in conjunction with the CDATA value of the default node directs the OBOE package what data to put in or how data is to be put into the related dataelement object.

    Getting Data Element Values

    All data elements inherit the super class' String get() method. But some do have their own special get method.

    DateDE can get a specific part of the date value.

    		method: public int get(int field)
    			java.util.Calendar.YEAR java.util.Calendar.MONTH java.util.Calendar.DAY_OF_MONTH

    TimeDE, like DateDE, can get a specific part of the time value java.util.Calendar.HOUR

    			method: public int get(int field)
    java.util.Calendar.HOUR java.util.Calendar.MINUTE java.util.Calendar.SECOND

    Creating An EDI Document

    Each of the general EDI Objects, TransactionSet, Table, Segments, CompositeDE and DataElement share a common method named get. This method returns a string containing an EDI Object. While the method is publicly available, generally the method would be called from the TransactionSet object.

    Requesting other formats.

    Like the get method, all the general EDI Objects share a getFormattedText method. This method accepts one argument that determines the format style. Presently there are five styles, plain (or formatted), well formed XML, validated XML, X12 and EDIFact.

    The plain format returns a string for each object with its description and any value (data elements only) associated with it. The segment get method appends a cr/lf or '\n' to the end of the string. The plain format is the default format. The output is simply the description field plus a ':' character and the value of the field, if one is present.

    Calling getFormattedText with the static variable name Envelope.XML_FORMAT, which has an int value of 1, creates the XML format. An XML formatted string is returned. The XML tag names are defined in theXML rules based file.

    Calling getFormattedText with the static variable name Envelope.X12_FORMAT, which has an int value of 2, creates the X12 format. The output from the X12 format is similar to the get methods call. The output contains X12 separators as defined in the TransactionSet source program.

    Calling getFormattedText with the static variable name Envelope.EDIFACT_FORMAT, which has an int value of 3, creates the EDIFact format. The output contains EDIFact separators as defined in the TransactionSet source program.

    Calling getFormattedText with the static variable name Envelope.VALID_XML_FORMAT, which has an int value of 4, creates a XML file that is validated. An XML formatted string is returned. The associated DTD file is named envelope.dtd. This file has nothing to do with the envelope rules DTD file and should not be confused with the rules file.

    <?xml encoding="ISO-8859-1"?>
    <!-- OBOE release 3.0.0 -->
    <!-- used by ValidXMLEDIParse -->
    <!ELEMENT envelope (segment+, functionalgroup+, segment+)>
    <!ATTLIST envelope
    	format (X12 | EDIFact) #REQUIRED
    >
    <!ELEMENT functionalgroup (segment?, transactionset+, segment?)>
    <!ELEMENT transactionset (table+)>
    <!ATTLIST transactionset
    	code CDATA #REQUIRED
    	name CDATA #IMPLIED
    >
    <!ELEMENT table (loop?, segment?)*>
    <!ATTLIST table
    	section CDATA #REQUIRED
    >
    <!ELEMENT loop (loop?, segment?)*>
    <!ATTLIST loop
    	code CDATA #REQUIRED
    	name CDATA #IMPLIED
    >
    <!ELEMENT segment (composite?, element?)*>
    <!ATTLIST segment
    	code CDATA #REQUIRED
    	name CDATA #IMPLIED
    >
    <!ELEMENT composite (element)+>
    <!ATTLIST composite
    	code CDATA #REQUIRED
    	name CDATA #IMPLIED
    >
    <!ELEMENT element (#PCDATA | value)*>
    <!ATTLIST element
    	code CDATA #REQUIRED
    	name CDATA #IMPLIED
    >
    <!ELEMENT value (#PCDATA)>
    <!ATTLIST value
    	description CDATA #IMPLIED
    >
    
    
    ValidXMLEDIParser.java

    This class builds an EDI object from a valid XML file as defined above.

    Parsing An XML/EDI Document

    The XML Rules and Document Files

    There is a one for one mapping between the XML rules and the document's transaction set to be parsed.

    The first rule is that there must be a TransactionSet element. All EDI Documents contain a line indicating the transaction set within the document. In X12 this is found in the "ISA" segment's first 3 bytes. The DTD rule

    			<!ATTLIST TransactionSet id CDATA #REQUIRED>
    
    TransactionSets and Table Parsing

    The DTD rule

    			<TransactionSet name="Request_for_Quotation" id="840"
    				revision="!!!"
    				functionalGroup=""
    				description="Request_for_Quotation">
    				<table section="header">...
    					</table>
    				<table section="detail">...
    					</table>
    				<table section="summary">...
    					</table>
    			</TransactionSet>
    		
    Tables and Segment Parsing

    The second rule is that the Tables must match one of three possible header types.. In most cases an EDI document has three tables, Header, Detail and Trailer. There is only one occurrence of the Header and Trailer tables and multiple occurrences of the Detail table. But sometimes there is only a Header table. For instance, the 997 Functional Acknowledgment has only one Table. Each transaction set must have at least one table. If you are defining a transaction set with no table DEFINE A HEADER TABLE and place all the segments within this one HEADER TABLE.

    Tables are not explicitly identified within an EDI Document. So the parser searches for the first occurrence of a valid Segment within the table. So, for instance, when the last valid Segment identifier is found while parsing the Header table the parser knows to jump out and start working on Detail tables.

    The DTD rule "<!ELEMENT table (segment*, loop?) indicates that a table can contain multiple segments and loops. The segments and loops owned by the Table will fall within the bounds of the table<table...</table tags. So while the rules file is being read each Segment and loop found within the bounds gets a TemplateSegment ir TemplateLoop added to the Vector TemplateSegment Vector of the owning table. Here is an example of a Header Table containing two Segments:

    			<table section="header"></font>
    				<segment name="Transaction Set Header"
    					id="ST"
    					description="Transaction Set Header"
    					...
    				</segment>
    				<segment name="Beginning Segment for Request For Quotation"
    					id="BQT" description="Beginning Segment for Request For Quotation"
    					...
    				</segment>
    			</table>
    		
    Loop Parsing

    The DTD rule "<!ELEMENT loop (segment?, loop?)*>" says a loop can contain zero, one or more subLoops and zero or more segments. Segments and loops within a loop are processed as with tables. Here is an example of a N9 loop containing a N9 Segment:

            	<loop  name="Identification Reference" id="N9"
            	  occurs="1000"
            	  required='O'
            	  xmlTag="IdentificationReference">
            	    <segment name="Identification Reference" id="N9"
    				</segment>
    			</loop>
    		
    Loop Parsing

    The DTD rule "<!ELEMENT loop (segment?, loop?)*>" says a loop can contain zero, one or more subLoops and zero or more segments. Segments and loops within a loop are processed as with tables. Here is an example of a N9 loop containing a N9 Segment:

            	<loop  name="Identification Reference" id="N9"
            	  occurs="1000"
            	  required='O'
            	  xmlTag="IdentificationReference">
            	    <segment name="Identification Reference" id="N9"
    				</segment>
    			</loop>
    		
    Note that the first segment of a loop must specify an occurrence of 1.
    Segment and Data Element Parsing

    Data Elements are contained within a Segment or Composite Data Element. The DTD rule "!