New DataCell Methods and Derived ClassesFor this chapter, in addition to adding a few new derived classes to support our new data types, we also need to add methods to existing classes to handle the requirements of formatting fields for flat file records. We allow the text contents of the field Elements in our input XML documents to be of any length (subject to whatever restrictions you define in your schemas, should you choose to use schemas). However, the fields in our flat file records have fixed lengths. So, if the content from the XML document is shorter than the field, we must fill and justify it appropriately. Conversely, if the content from the XML document is longer than the field, we must truncate it if allowed or force an error if not. We'll first discuss the new methods we're adding to the base DataCell class to support these requirements. We'll next look at the prepareOutput method we're adding to the existing derived classes. We'll wrap up with the new derived classes added for this chapter. New DataCell MethodsThree new methods are added to the DataCell base class to support filling and justification. The primary method is fillField, called from the prepareOutput method in the derived classes. It retrieves the appropriate Length and FillCharacter Attributes from the field grammar Element, then calls the justifyFieldLeft or justify FieldRight methods. Note that in addition to retrieving a Length Attribute from the Grammar Element, fillField also attempts to retrieve a MinLength Attribute. Although we don't need this feature for flat files, we'll need it later for EDI formats, so I include it now. We don't need to be concerned in the code about having both values defined. The file description document schemas ensure that we'll have the one appropriate for the particular legacy format. We supply a default fill character (an ASCII space) if the grammar Element doesn't have a FillCharacter Attribute. This also fulfills the requirements of EDI and similar formats. Logic for the DataCell fillField MethodArguments: Character Justify - L or R for left or right justification Integer Fixed Length - For fixed length, if specified Returns: Status or throws exception Length <- Fixed Length IF (Length = 0) Minimum Length <- Call Grammar Element's getAttribute for "MinLength" Length <- Minimum Length, converted from string ENDIF IF (Buffer Length >= Length) return ENDIF Fill Character <- Call Grammar Element's getAttribute for "FillCharacter" IF Fill Character is empty Fill Character = ASCII space ENDIF IF ( Justify = R ) Call justifyFieldRight, passing Length and Fill Character ELSE Call justifyFieldLeft, passing Length and Fill Character ENDIF Return success Logic for the DataCell justifyFieldLeft MethodArguments: Integer Length Character Fill Character Returns: Status or throws exception Dependent on language features, fill Cell Buffer right portion for Length with passed Fill Character Return success Logic for the DataCell justifyFieldRight MethodArguments: Integer Length Character Fill Character Returns: Status or throws exception Dependent on language features, shift Cell Buffer contents to the right-most positions within passed Length, and fill left with passed Fill Character Return success New Methods in DataCell Derived ClassesWe defined three derived classes to support CSV formats in Chapter 7. To use those classes now for flat files we must add a prepareOutput method. It is very similar in most classes, but it varies depending on justification and whether or not truncation is allowed. Note again that for flat file formats we need to use only the Length Attribute of the grammar Element, but for EDI support in the next chapter we retrieve the MaxLength Attribute if Length is not present. DataCellAN prepareOutput MethodFor the alphanumeric data type supported by the DataCellAN class, we left-justify and truncate if specified by the Truncatable Attribute of the Grammar Element. Logic for the DataCellAN prepareOutput MethodArguments: None Returns: Status or throws exception Length <- Call Grammar Element's getAttribute for "Length" Call fillField, passing 'L' for left justification, and Length IF ( Length = 0 ) Maximum Length <- Call Grammar Element's getAttribute for "MaxLength" Length <- Maximum Length, converted from string ENDIF IF (Buffer Length <= Length) Return success ENDIF Truncate <- Call Grammar Element's getAttribute for "Truncatable" IF ( Truncate = false ) Return error ENDIF Depending on language features, truncate Cell Buffer contents to specified Length Buffer Length <- Length Return success DataCellReal prepareOutput MethodFor the real (or decimal) data type supported by the DataCellReal class, we right-justify. If a sign character is present in the input XML Element, its position in the output is dependent on the fill character. If the fill character is a zero, the sign character is placed in the left-most position. For all other fill characters the sign character immediately precedes the most significant digit. If the field is truncatable and it exceeds the maximum length specified, fractional digits to the right of the decimal point (and the decimal point if required) are truncated. If this is done and the digits to the left of the decimal still exceed the maximum length, an error occurs. Logic for the DataCellReal prepareOutput MethodArguments: None Returns: Status or throws exception Length <- Call Grammar Element's getAttribute for "Length" Sign Character <- First character in Cell Buffer Call fillField, passing 'R' for right justification, and Length IF (Sign Character = "+" or "-") and (First character in Cell Buffer = "0") Dependent on language features, find Sign Character in Cell Buffer and swap with first character in Cell Buffer ENDIF IF ( Length = 0 ) Maximum Length <- Call Grammar Element's getAttribute for "MaxLength" Length <- Maximum Length, converted from string ENDIF IF (Buffer Length <= Length) Return success ENDIF Truncate <- Call Grammar Element's getAttribute for "Truncatable" IF ( Truncate = false ) Return error ENDIF Depending on language features, truncate Cell Buffer contents to specified Length stopping when Length is achieved or decimal point is truncated IF (Buffer Length > Length) Return failure ENDIF Buffer Length <- Length Return success DataCellDateMMsDDsYYYY prepareOutput MethodThe DataCellDateMMsDDsYYYY class supports the date data type with dates in an MM/DD/YYYY format. For this type we left-justify and fill with spaces. This class is not truncatable, and we don't check the maximum length since the fromXML method ensures that we have a length of ten characters. Logic for the DataCellDateMMsDDsYYYY prepareOutput MethodArguments: None Returns: Status or throws exception Length <- Call Grammar Element's getAttribute for "Length" Call fillField, passing 'L' for left justification, and Length Return success DataCellN ClassThis class handles conversion to and from a number with an implied decimal point and the schema language decimal data type. The data type code for this class is Nx, where x represents the number of implied decimal places. For the fromXML method, if the number of fractional digits in the source decimal number exceeds the number of implied decimal places, it is right-truncated to the number of implied places. Zeroes are added as fractional digits if the source number has fewer fractional digits than the specified number of implied places. Logic for the DataCellN fromXML MethodArguments: None Returns: Error status or throws exception IF first Character in Cell Buffer = '+' Cell Buffer <- Shift Cell Buffer left one character to remove plus sign Decrement Buffer Length ENDIF Data Type <- Call Grammar Element's getAttribute for "DataType" Implied Places <- Extract portion of Data Type following 'N' Difference Places <- Implied Places Find decimal point in Number Depending on language features IF Decimal Point present Fractional Digits <- Digits to the right of the decimal point Cell Buffer <- Shift fractional digits to the left to overlay the decimal point, and clear the last byte Decrement Buffer Length Difference Places <- Implied Places - Fractional Digits IF (Difference Places < 0) Cell Buffer <- Truncate right-most Difference Places digits Buffer Length <- Buffer Length - Difference Places ENDIF ENDIF IF (Difference Places > 0) Cell Buffer <- Append Difference Places number of zeroes ENDIF Return success For the toXML method we trim leading zeroes and whitespace, then insert the explicit decimal point. Logic for the DataCellN toXML MethodArguments: None Returns: Error status or throws exception Call trimLeadingZeros to remove leading zeroes and leading and trailing whitespace from Cell Buffer Data Type <- Call Grammar Element's getAttribute for "DataType" Implied Places <- Extract portion of Data Type following 'N' IF Implied Places > 0 OR Buffer Length is zero Return ENDIF IF Buffer Length after trimming is less than Implied Places plus one Pad to Implied Places with zeroes, plus a zero to the left of the decimal ENDIF Cell Buffer <- Substring of Cell Buffer from 0 through (Length - Implied Places) + "." + leftmost Implied Places characters of Cell Buffer ELSE Return success The prepareOutput method is a bit simpler than for the real number data type since we have already handled fractional digits and we don't truncate. As with the real data type, the number is right-justified within the field. Again, leading characters are set according to the fill character. If the fill character is a zero, the sign character is placed in the left-most position. For all other fill characters the sign character immediately precedes the most significant digit. We don't truncate. Since we don't check length in the fromXML method (as is the case with the date data types), we check length here and return an error if the length exceeds the defined fixed or maximum length. Logic for the DataCellN prepareOutput MethodArguments: None Returns: Status or throws exception Length <- Call Grammar Element's getAttribute for "Length" Sign Character <- First character in Cell Buffer Call fillField, passing 'R' for right justification, and Length IF (Sign Character = "+" or "-") and (First character in Cell Buffer = "0") Dependent on language features, find Sign Character in Cell Buffer and swap with first character in Cell Buffer ENDIF IF ( Length = 0 ) Maximum Length <- Call Grammar Element's getAttribute for "MaxLength" Length <- Maximum Length, converted from string ENDIF IF (Buffer Length > Length) Return failure ENDIF Return success DataCellDateYYYYMMDD ClassThis class handles conversion to and from the date data type in the common YYYYMMDD format to the schema language date data type in ISO 8601 date format, that is, YYYY-MM-DD. In keeping with our strategy of using schema validation as our primary data validation mechanism, I include error checking sufficient to prevent only most runtime exceptions. Logic for the DataCellDateYYYYMMDD fromXML MethodArguments: None Returns: Error status or throws exception IF Buffer Length != 10 Return error ENDIF Month <- Cell Buffer characters at offsets 5 and 6 Day <- Cell Buffer characters at offsets 8 and 9 Year <- Cell Buffer characters at offsets 0 through 3 Cell Buffer <- Year + Month + Day Return success Logic for the DataCellDateYYYYMMDD toXML MethodArguments: None Returns: Error status or throws exception Cell Buffer < trim leading and trailing whitespace from Cell Buffer IF Buffer Length != 8 Return error ENDIF Year <- Cell Buffer characters at offsets 0 through 3 Month <- Cell Buffer characters at offsets 4 and 5 Day <- Cell Buffer characters at offsets 6 and 7 Cell Buffer <- Year + "-" + Month + "-" + Day Return success The prepareOutput method performs left-justification and fills as necessary with the specified fill character. This date data type may not be truncated, so there is no code that deals with truncation. In addition, since the fromXML method ensures that we have the correct length we're not concerned with exceeding the specified length. Logic for the DataCellDateYYYYMMDD prepareOutput MethodArguments: None Returns: Status or throws exception Length <- Call Grammar Element's getAttribute for "Length" Call fillField, passing 'L' for left justification, and Length Return success |