XML to X12: Detail Design


Main Program

The shell main program functions are very similar to those of the other XML to legacy format utilities. We do, however, add calls (1) before processing all documents to write the X12 interchange and group header segments, and (2) after finishing to write the trailer segments.

Logic for the Shell Main Routine for XML to X12
 Arguments:   Input Directory Name   Output X12 Interchange Name   File Description XML Document Name Options:   Validate input   Help Validate and process command line arguments IF help option specified   Display help message   Exit ENDIF Open output file Create new X12TargetConverter object, passing:     Output Stream     File Description Document Name Set up implementation dependent DOM environment for loading,     parsing, and validating input documents Open input directory Get first file from input directory Call X12TargetConverter writeHeaders method DO for all files in input directory   Input Document <- Load input file, validating it if requested   Call X12TargetConverter processDocument method, passing       the Input Document   Increment number of documents processed ENDDO Call X12TargetConverter writeTrailers method Close output file Display completion message with number of documents processed 

X12TargetConverter Class (Extends TargetConverter)

Overview

The X12TargetConverter is again very similar to the CSV and flat file target converters, but again we add some complexities due to the grammar differences and the requirement to create the X12 control segments.

Attributes:

  • None

Methods :

  • Constructor

  • processDocument

  • writeHeaders

  • writeTrailers

Methods
Constructor

The constructor method sets up the X12TargetConverter object and the X12 RecordWriter object.

Logic for the X12TargetConverter Constructor Method
 Arguments:   Output Stream X12 Interchange Output file   String File Description Document Name Call base class constructor, passing File     Description Document Name Create X12RecordWriter object, passing:     File Description DOM Document and Output Stream 
processDocument

As was the case with the X12SourceConverter's processFile method, we aren't able to simply call the base TargetConverter class's processGroup method to perform the bulk of the required processing. Because of the way we have defined the grammar of X12 transaction sets, the first segment after the transaction set header isn't always required and we can't treat the document as just another group. We must include some of the same types of operations that we have in the main loop of the processGroup method, then call that method when we actually do need to process a group. We can use the processGroup method from the Target Converter base class.

Logic for the X12TargetConverter processDocument Method
 Arguments:   DOM Document Input Document Returns:   Error status or throws exception Root Element <- Get Document's documentElement attribute Root Element Name <- Get Root Element's tagName attribute IF Root Element Name != Grammar Root Element Name   Return error ENDIF Call X12RecordWriter's writeST method to write Transaction Set     Header segment Segment Grammar Node <- Get firstChild from Grammar Element     skipping over non-Element Nodes Segment Grammar Element <- Segment Grammar Node Grammar Tag <- Call Segment Grammar's getAttribute for     "ElementName" Segment Element <- Get first childNode from Root Element,     skipping over non-Element Nodes DO until all child Elements of the Root have been processed   Segment Name <- call Segment Element's getNodeName   DO until Grammar Name = Segment Name      Segment Grammar Element <- Get next Segment Element from         Grammar, skipping over non-Element Nodes     IF Segment Grammar Element is NULL       Return error  //  This record is not part of the document     ENDIF     Grammar Name <- Call Segment Grammar's getAttribute for         "ElementName"   ENDDO   Grammar Element Name <- Call Segment Grammar Element's       getNodeName   IF Grammar Element Name = "GroupDescription"     Call processGroup, passing Record Element and Record Grammar         Element   ELSE     Call X12RecordWriter parseRecord, passing Record Element and         Record Grammar Element     Call X12RecordWriter writeRecord, passing Record         Grammar Element   ENDIF   Record Element <- Get Record Element's nextSibling, skipping       over non-Element Nodes ENDDO Call X12RecordWriter's writeSE method to write Transaction Set     Trailer Segment Return success 
writeHeaders

This method calls the X12RecordWriter's methods to write the interchange and group header control segments. This and the writeTrailers methods are included here because the main program knows nothing of the X12RecordWriter class. Its methods to write header and trailer segments can be invoked only by a call to one of the X12TargetConverter's methods.

Logic for the X12TargetConverter writeHeaders Method
 Arguments:   None Returns:   Status or throws exception Call X12RecordWriter writeISA Call X12RecordWriter writeGS Return success 
writeTrailers

This method calls the X12RecordWriter's methods to write the interchange and group trailer control segments.

Logic for the X12TargetConverter writeTrailers Method
 Arguments:   Integer Number of Included Transaction Sets Returns:   Status or throws exception Call X12RecordWriter writeGE Call X12RecordWriter writeIEA Return success 

EDIRecordWriter Class (Extends RecordWriter)

Overview

Our analysis showed us that there were sufficient commonalities among the possible RecordReader classes for EDI to XML conversions (one derived class for each specific EDI syntax) to create a base EDIRecordReader class and put the common functionality into it. We have the same situation with the RecordWriter derived classes used to process EDI formats as the target of our conversions. So, in this class we develop some common functions for converting from XML to generic EDI segments, maintaining control information that will be used by the derived classes. Again, we build in preliminary support for the repetition separator and the release character, even though they aren't implemented in version 004010 of X12.

Attributes:

  • DOM Document EDI Control

  • Character Element Separator

  • Character Component Separator

  • Character Repetition Separator

  • Character Release Character

  • Integer Segment Count

Methods:

  • Constructor

  • parseRecord

  • writeRecord

  • writeEDIControl

The writeEDIControl method writes the updated EDI Control document to the EDIControl.xml file in BBHOME. It is fairly simple and very dependent on the DOM API implementation, so I won't discuss it further below.

Methods
Constructor

When we read EDI we parse the input to determine the delimiters. However, when we write it we must derive the delimiters from a data store. The primary purpose of this method is to get the delimiters from the file description document. In addition, the constructor method loads the EDIControl.xml file for sequence number generation.

Logic for the EDIRecordWriter Constructor Method
 Arguments:   DOM Document File Description Document   Output Stream Call RecordWriter base class constructor, passing File     Description Document and Output Stream Delimiters Element <- Call File Description Document's     getElementsByTagName for "Delimiters" Segment Terminator Element <- call Delimiters     getElementsByTagName         for "SegmentTerminator" Delimiter Value = call Segment Terminator's getAttribute for     "value" Record Terminator1 <- Call setDelimiter, passing Delimiter Value Element Separator Element <- call Delimiters     getElementsByTagName         for "SegmentTerminator" Delimiter Value = call Element Separator Element's getAttribute     for "value" Element Separator <- Call setDelimiter, passing Delimiter Value Component Separator Element <- call Delimiters     getElementsByTagName         for "ComponentSeparator" Delimiter Value = call Component Separator Element's     getAttribute         for "value" Component Separator <- Call setDelimiter, passing Delimiter Value Repetition Separator Element <- call Delimiters getElementsByTagName     for "RepetitionSeparator" IF Repetition Separator Element is not null   Delimiter Value = call Repetition Separator Element's getAttribute       for "value"   Repetition Separator <- Call setDelimiter, passing Delimiter Value ENDIF Release Character Element <- call Delimiters getElementsByTagName     for "ReleaseCharacter" IF Release Character Element is not null   Delimiter Value = call Release Character Element's getAttribute       for "value"  Release Character <- Call setDelimiter, passing Delimiter Value ENDIF BBHomePath <- from system property or environment variable for     BBHome EDIControlPath <- BBHomePath + "EDIControl.xml" Call implementation dependent methods to load EDIControl Document 
parseRecord

This method is very similar to the parseRecord method of the RecordReader base class, although again we add some functionality that is solely needed for processing the EDI representations of composite data structures. Rather than confuse the base class method I have created a more specialized method for the derived class. For Babel Blaster 1.0 this might be moved to the base class if design review and testing verify that it will work fine for other legacy formats.

Logic for the EDIRecordWriter parseRecord Method
 Arguments:   DOM Element Record   DOM Element Record Grammar Returns:   Void Field Grammar <- Get first Grammar child Element from Record     Grammar Element, skipping over non-Element nodes Grammar Field Name <- call Field Grammar's getAttribute     on "ElementName" DO for all Field Elements that are children of Record Element   // Test for a composite data structure   Composite <- False   childNode <- get Field Element's firstChild   DO until childNode is null or Composite is true     IF childNode nodeType = ELEMENT       Composite <- true     ELSE       childNode <- childNode's nextSibling     ENDIF   ENDDO   IF Composite is false     Element Text <- call getElement Text on Field Element     IF Element Text is empty       Proceed to next field     ENDIF   ENDIF   Field Name <- Field Element's tagName attribute   DO UNTIL Field Name == Grammar Field Name or Grammar Element         is null     Get next sibling Field Grammar Element, skipping over         non-Element Nodes     Grammar Field Name <- Field Element's tagName attribute   ENDDO   IF Grammar Element is null     Return error   ENDIF   IF Composite is true     Call base class parseRecord, passing Field Element and         Grammar Element   ELSE     Field Number <- Call Field Grammar's getAttribute         on "FieldNumber"     New Cell <- call createDataCell, passing Field Number         and Grammar     New Cell <- call New Cell's putField, passing Element Text   ENDIF ENDDO 

Note that we don't need a special method to parse the XML representation of a composite data element. We can use the base class's parseRecord method because the structure of a composite data element's XML representation and grammar are the same as records in our other legacy formats.

writeRecord

Since we can identify a grammar that applies to the segments of most EDI syntaxes, we can develop this common method to write such segments. The overall logic flow is very similar to that of the CSVRecordWriter since both deal with delimited record formats. As with that method we walk the DataCell Array. For this method we must keep track of a few more pieces of information so that we write the correct delimiters. The Element Position counter keeps track of data element position within the output segment. The Component Position counter keeps track of component data element position within a composite data structure. The Previous Element Position indicates whether or not we have a repeating data element.

Logic for the EDIRecordWriter writeRecord Method
 Arguments:   DOM Element Segment Grammar Returns:   Error status or throws exception Initialize Output Record Buffer to null Segment Tag <- Call Segment Grammar's getAttribute for "TagValue" Output Buffer <- Segment Tag Set Buffer Length to Tag length Element Position <- 0 Previous Element Position <- 0 Component Position <- 1 DO for Index from 0 through Highest Cell   // Test for new element   Cell Position = Get Cell's Field Number   // Reset to start new composite if needed   IF Element Position != Cell Position     Component Position <- 1   ENDIF   // Write preceding data element separators   DO while Element Position < Cell Position     Append Element Separator to Record Buffer     Increment Element Position   ENDDO   // Write preceding repetition separator   // NOTE - An additional test is needed here to write repeating   //     composite data structures correctly   IF Element Position = Previous Element Position     Append Repetition Separator to Record Buffer   ENDIF   Previous Element Position = Element Position   // Write preceding component data element separators   Cell SubPosition = Get Cell's SubField Number   DO while Component Position < Cell SubPosition     Append Component Separator to Record Buffer     Increment Component Position   ENDDO   Call fromXML to convert Cell contents from XML data type   Call prepareOutput to format Cell contents for EDI output   Cell Contents <- Call getField to retrieve Cell Buffer       contents   Clear Array entry   Append Cell Contents to Record Buffer ENDDO Highest Cell <- -1 Append base RecordHandler's Record Terminator1 to Record Buffer Call language's write routines to do physical write of     Record Buffer Increment Segment Count Return success 

Again, this version of the method doesn't fully support composite data structures when used as repeating data elements. A Babel Blaster 1.0 requirement is to widen support beyond the demands of X12 version 004010.

X12RecordWriter Class (Extends EDIRecordWriter)

Overview

The X12RecordWriter is derived from the EDIRecordWriter. It handles the specialized requirements of writing X12 control segments.

Attributes:

  • DOM Element TP Element for trading partner information

  • String Interchange Control Number

  • String Group Control Number

  • Integer Transaction Set Count

  • String Date

  • String Time

Methods:

  • Constructor

  • writeGE

  • writeGS

  • writeIEA

  • writeISA

  • writeSE

  • writeST

Methods

As with the case of the X12RecordReader class, only a few of these methods are very significant. The constructor method doesn't do anything except call the base class constructor. The methods that write transaction set and group trailer segments, writeGE and writeSE, are simple methods that write the number of included components , followed by the control number that was written in the header segment. The methods that write the header segments and the interchange trailer are worthy of a bit more discussion. I'll discuss them below, starting with the outer control segments of the interchange, moving inward.

writeISA

Based on trading partner information in the file description document, this method looks up the last used interchange control number from the EDIControl.xml data store. The method increments the control number, updates the value in EDIControl, and calls language and system dependent functions to get the current date and time for the ISA and GS segments. The method then populates the rest of the ISA segment from other Elements in the file description document and writes the ISA segment.

Logic for the X12RecordWriter writeISA Method
 Arguments:   None Returns:   Status or throws exception ISA Info <- Call File Description Document's     GetElementsByTagName for "ISAInformation" ISA ReceiverID <- Call ISAInfo's getElementsByTagName for     "ReceiverID", then getAttribute for "value" X12 Control <- Call EDI Control document's getElementsByTagName     for "X12OutboundControl" TP NodeList <- Call X12 Control's getElementsByTagName for     "TradingPartner" DO for all entries in TP NodeList or until     Control Receiver ID = ISA Receiver ID   Control Receiver ID <- call TP NodeList item's getAttribute     for "ReceiverID" ENDDO IF no match found   TP Element <- call EDI Control's createElement method using       Element name of "TradingPartner"   X12 Control <- call X12 Control's appendChild to attach       TP Element   Interchange Number <- 1   Call TP Element's setAttribute for "ReceiverID", passing       ISA Receiver ID as value to set ELSE   Interchange Number <- Call TP Element's getAttribute for       "LastInterchangeNumber"   Increment Interchange Number ENDIF Call TP Element's setAttribute for "LastInterchangeNumber",     passing Interchange Number as value to set Date <- Get date from system, and reformat to YYMMDD Time <- Get time from system, and reformat to HHMM Get remaining values from ISA Info Element and pad to required     Lengths Initialize Record Buffer Build ISA Segment in Record Buffer with "ISA" segment tag, values     from ISA Info Element, Date, Time, and Delimiters from base     class members, appending Record Terminator1 as segment     terminator Write Record Buffer using language-specific methods Return success 

We could, perhaps, use a more sophisticated method for looking up the trading partner in EDIControl than the algorithm in this method. However, I don't see significant performance gains in using something like XQuery for the number of entries likely to exist in this document. Also, we would be complicating the code by adding yet another type of technology.

writeGS

This method retrieves the last group control number used from the EDIControl file and populates the remainder of the segment from values from the GSInformation Element in the file description document. It also initializes the transaction set count.

Logic for the X12RecordWriter writeGS Method
 Arguments:   None Returns:   Status or throws exception Transaction Set Count <- 0 GSInfo <- Call File Description Document's getElementsByTagName     for "GSInformation" GSReceiverID <- Call GSInfo's getElementsByTagName for     "ApplicationReceiversCode", then getAttribute for "value" GSType <- Call GSInfo's getElementsByTagName for     "FunctionalIDCode", then getAttribute for "value" GroupNodeList <- Call TP Element's getElementsByTagName for     "FunctionalGroup" DO for all entries in GroupNodeList or until     ControlReceiverID = GSReceiverID and     ControlType = GSType   ControlReceiverID <- call GroupNodeList item's getAttribute       for "ReceiverID"   ControlType <- call GroupNodeList item's getAttribute       for "FunctionalIDCode" ENDDO IF no match found   GroupElement <- call EDI Control's createElement method using       Element name of "FunctionalGroup"   TP Element <- call TP Element's appendChild to attach       GroupElement   Group Number <- 1   Call GroupElement's setAttribute for "ReceiverID", passing       GSReceiverID as value to set   Call GroupElement's setAttribute for "FunctionalIDCode",       passing GSType as value to set ELSE   Group Number <- Call Group Element's getAttribute for       "LastGroupNumber"   Increment Group Number ENDIF Call Group Element's setAttribute for "LastGroupNumber",     passing Group Number as value to set Get remaining values from GSInfo Element Initialize Record Buffer Build GS Segment in Record Buffer with "GS" segment tag, values     from GSInfo Element, Date, Time, and Delimiters from base     class members, appending RecordTerminator1 as segment     terminator Write Record Buffer using language-specific methods Return success 
writeST

This method is quite a bit simpler that the writeISA and writeGS methods since we start a new sequence of transaction set control numbers with each new functional group we write. We need to retrieve only one value from the file description document.

Logic for the X12RecordWriter writeST Method
 Arguments:   None Returns:   Status or throws exception Increment Transaction Set Count Pad Transaction Set Count to four digits with leading zeroes    if required STInfo <- Call File Description Document's getElementsByTagName     for "STInformation" STType <- Call STInfo's getAttribute for "TransactionSetIDCode" Initialize Record Buffer Build ST Segment in Record Buffer with "ST" segment tag, STType,     and Transaction Set Count, using Element Separator from     base class members and appending RecordTerminator1 as segment     terminator Write Record Buffer using language-specific methods Segment Count <- 1 Return success 
writeIEA

Writing the trailer segment is pretty simple since we write only two values. However, for control number integrity we don't save the EDIControl document until after the interchange trailer is successfully written.

Logic for the X12RecordWriter writeIEA Method
 Arguments:   None Returns:   Status or throws exception Initialize Record Buffer Build IEA Segment in Record Buffer with "IEA" segment tag,     "1" included functional group, and Interchange Control     Number, using Element Separator from base class members     and appending Record Terminator1 as segment terminator Write Record Buffer using language-specific methods Save EDI Control Document to EDI Control File Path Return success 


Using XML with Legacy Business Applications
Using XML with Legacy Business Applications
ISBN: 0321154940
EAN: 2147483647
Year: 2003
Pages: 181

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net