// Break an individual line into tokens.
// This is a recursive function
// that extracts the first token, then
// recursively parses the
// remainder of the line.
private void parseLine(String curLine, ContentHandler ch)
throws IOException, SAXException {

The first thing this method does is check for the existence of a
SAX ContentHandler. The base class, AbstractXMLReader, provides access to this object, which
is responsible for listening to the SAX events. In our example, an instance of
JAXP's TransformerHandler is used as the SAX ContentHandler implementation. If this handler is not
registered, our parse method simply returns because
nobody is registered to listen to the events. In a real SAX parser, the XML
would be parsed anyway, which provides an opportunity to check for errors in
the XML data. Choosing to return immediately was merely a performance
optimization selected for this class.

The SAX InputSource parameter allows
our custom parser to locate the CSV file. Since an InputSource has many options for reading its data,
parsers must check each potential source in the order shown here:

Our parser simply ignores many SAX 2 features, particularly XML
namespaces. This is why many values passed as parameters to the various ContentHandler methods simply contain empty strings. The
EMPTY_ATTR constant indicates that this XML element
does not have any attributes.

The CSV file itself is very straightforward, so we merely loop
over every line in the file, emitting SAX events as we read each line. The
parseLine method is a private helper method that
does the actual CSV parsing:

The remaining methods in CSVXMLReader
are not discussed in detail here because they are really just responsible for
breaking down each line in the CSV file and checking for commas, quotes, and
other mundane parsing tasks. One thing worth noting is the code that emits
text, such as the following:

<value>Some Text Here</value>

SAX parsers use the characters method
on ContentHandler to represent text, which has this
signature:

public void characters(char[] ch, int start, int length)

Although this method could have been designed to take a String, using an array allows SAX parsers to preallocate
a large character array and then reuse that buffer repeatedly. This is why an
implementation of ContentHandler cannot simply
assume that the entire ch array contains meaningful
data. Instead, it must read only the specified number of characters beginning
at the start position.

Our parser uses a relatively straightforward approach, simply
converting a String to a character array and
passing that as a parameter to the characters
method: