XML file implementation for the IO API.


Interface Summary
XMLIndentationEngine XMLIndentationEngine returns the indentation information to be written to the stream based on events received.

Class Summary
PrettyXMLIndentationEngine PrettyXMLIndentationEngine writes the the elements in XML in the folloing manner.
XMLFileReader XMLFileReader reads the specified xml file according to the given file spec and returns the recrods on the needed basis.
XMLFileSpec XMLFileSpec represents the file spec defines the xml file where each different kind of record identified by the xpath.
XMLFileWriter XMLFileWriter writes the specified xml file according to the given file spec with the the recrods submitted to write into the file.
XMLRecordSpec XMLRecordSpec represents record-spec element in the file spec belongs to the xml file type.

Package Description

XML file implementation for the IO API.

XML files are becoming popular choice by the enterprises to exchange the data. This package provides the implementation to work with the XML files. Implementation assumes that file consists of set of records and each can be identified using the xpath.

XML File Implementation

XML files consists of set of different records where each record can be identified by using xpath expression and all the elements beneath the element identified by xpath are treated as fields of that record.
Defining the file spec for xml files
File spec which descibes the xml file expects the file-type attribute value should be "xml". It requires one additional attribute along with the file-type attribute, which is root-element which will be used highly while generating the xml file from the set of records. The value in the attribute specifies the root element of the xml document. This file spec optionally requires 2 more attributes "indentation-engine" and "encoding". "indentation-engine" attribute value tells the class to be used for the indentation purposes. This class should implement the XMLIndentationEngine interface. If this attribute is not specified and the given class is not valid, it uses default indentation engine. The value specified in "encoding" attribute will be used in generated xml processing instruction.
             <file-spec file-type="xml" root-element="sample-root" indentation-engine="" encoding="ISO-8859-1">
There could be multiple record specs exists in a file spec. Along with the record-type attribute, it requires an additional attribute record-xpath which tells the xpath in the document to identify the record.
             <file-spec file-type="xml" root-element="sample-root" indentation-engine="" encoding="ISO-8859-1">
                 <record-spec record-type="DETAIL" record-xpath="/sample-root/detail-record"/>
Since all the elements beneath the element represented by record spec will be exposed as a field values, record spec doesnt require any field specs. All the simple elements in the record element will be exposed as field name and values where element name represents the field name and element value represents the field value. All the complex elements(nested elements or elements contains child elements) will be exposed as a records again. All the repeat elements(elements which can repeat more than once) values will be exposed as list.
Here onwards will try to show how to process/read and generates/write the following xml file. Lets assume we need to read and write and following xml file.
            <?xml version='1.0' encoding='ISO-8859-1'?>
                    <file-type>Employee Records</file-type>
                            <city>Menomonee Falls</city>
                            <city>Menomonee Falls</city>

Following is the file spec to read and write the above given file.
            <?xml version="1.0" encoding="UTF-8"?>

            <file-spec file-type="xml" root-element="sample-root" indentation-engine="" encoding="ISO-8859-1">
                <record-spec record-type="header" record-xpath="/sample-root/sample-header"/>
                <record-spec record-type="detail" record-xpath="/sample-root/sample-detail"/>
                <record-spec record-type="trailer" record-xpath="/sample-root/sample-trailer"/>
Code to read the records from xml files
        FileReader fileReader=FileReader.getFileReader(new FileInputStream("C:\\sample-xml-file_2.xml"),this.getClass().getResourceAsStream("sample-xml-file-spec.xml"));
        ReaderRecord readerRecord=null;
                // Simple elements in the records can be read using either readFiled or readSimpleElement.
                String fileType=(String)readerRecord.readField("file-type");
                System.out.println("File type in header record = " + fileType);
            else if(readerRecord.getRecordType().equals(RecordType.TRAILER))
                // Trying to show that simple elements can be read using readSimpleElement.
                String transactionCount=((XMLReaderRecord)readerRecord).readSimpleElement("transaction-count");
            else if(readerRecord.getRecordType().equals(RecordType.DETAIL))
                XMLReaderRecord xmlDetailRecord=(XMLReaderRecord)readerRecord;
                // Simple elements can be read using readSimpleElement method.
                String firstName=xmlDetailRecord.readSimpleElement("first-name");
                String lastName=xmlDetailRecord.readSimpleElement("last-name");
                System.out.println(firstName + " " + lastName);
                // Nested elements can be read using readComplexElement method.
                XMLReaderRecord deptInfoComplexRecord=(XMLReaderRecord)xmlDetailRecord.readComplexElement("dept-info");
                String deptName=deptInfoComplexRecord.readSimpleElement("dept-name");
                String deptLocation=deptInfoComplexRecord.readSimpleElement("dept-location");
                System.out.println(deptName + " " + deptLocation);
                XMLReaderRecord addressesComplexRecord=(XMLReaderRecord)xmlDetailRecord.readComplexElement("addresses");
                List addressesRepeatList=addressesComplexRecord.readRepeatElement("address");
                for(Iterator iterator=addressesRepeatList.iterator();iterator.hasNext();)
                    if(addressRecord instanceof XMLReaderRecord)
                        XMLReaderRecord addressComplexRecord=(XMLReaderRecord)addressRecord;
                        String addressType=addressComplexRecord.readSimpleElement("address-type");
                        String city=addressComplexRecord.readSimpleElement("city");
                        String zipCode=addressComplexRecord.readSimpleElement("zip-code");
                        System.out.println(addressType + " " + city + " " + zipCode);
                    else if(addressRecord instanceof String)
                        System.out.println("Unknown type.");
                System.out.println("Unknown record type = " + readerRecord.getRecordType().toString());
Code to write the records into xml files
        // Get the file writer by providing the output stream to write the xml file and input stream to file spec.
        FileWriter fileWriter=FileWriter.getFileWriter(new FileOutputStream("C:\\sample-xml-file_2.xml"), this.getClass().getResourceAsStream("sample-xml-file-spec.xml"));

        // Create and write the header record.
        XMLWriterRecord headerRecord=(XMLWriterRecord)fileWriter.createWriterRecord(RecordType.HEADER);
        headerRecord.writeSimpleElement("file-type", "Employee Records");
        // Get the empty record you want to create by passing the record type you mentioned in file spec.
        XMLWriterRecord detailRecord=(XMLWriterRecord)fileWriter.createWriterRecord(RecordType.DETAIL);
        // Write the simple elements using either writeField or writeSimpleElement methods.
        detailRecord.writeSimpleElement("first-name", "Suresh");
        detailRecord.writeField("last-name", "Pragada");
        // Create the nested record by passing the nested element name. This automatically attached to detail record. No need to write it back to detail record.
        XMLWriterRecord deptComplexRecord=(XMLWriterRecord)detailRecord.createComplexElement("dept-info");
        deptComplexRecord.writeSimpleElement("dept-name", "IT");
        deptComplexRecord.writeSimpleElement("dept-location", "LOC1");
        XMLWriterRecord addressesComplexRecord=(XMLWriterRecord)detailRecord.createComplexElement("addresses");
        // Get the list to add all the elements needs to be written with the given name.
        List addressRepeatList=addressesComplexRecord.createRepeatElement("address");
        // Empty nested element record can be created using any XMLWriterRecord instance. 
        XMLWriterRecord homeAddressComplexRecord=(XMLWriterRecord)addressesComplexRecord.createComplexElement();
        homeAddressComplexRecord.writeSimpleElement("address-type", "home");
        homeAddressComplexRecord.writeSimpleElement("city", "Menomonee Falls");
        homeAddressComplexRecord.writeSimpleElement("zip-code", "53051");
        // Empty nested element record can be created using any XMLWriterRecord instance. 
        XMLWriterRecord officeAddressComplexRecord=(XMLWriterRecord)addressesComplexRecord.createComplexElement();
        officeAddressComplexRecord.writeSimpleElement("address-type", "office");
        officeAddressComplexRecord.writeSimpleElement("city", "Menomonee Falls");
        officeAddressComplexRecord.writeSimpleElement("zip-code", "53051");
        // Feel free to drop simple elements value as well.

        // Write the finished record into the file.
        // Create and write the trailer record.
        XMLWriterRecord trailerRecord=(XMLWriterRecord)fileWriter.createWriterRecord(RecordType.TRAILER);
        trailerRecord.writeSimpleElement("transaction-count", "1");