blob: 8061fbe63ee251d1260a91acf8cc0f83cacae44a [file] [log] [blame]
package jdiff;
import java.io.*;
import java.util.*;
/* For SAX XML parsing */
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
/**
* Handle the parsing of an XML file and the generation of a Comments object.
*
* All HTML written for the comments sections in the report must
* use tags such as <p/> rather than just <p>, since the XML
* parser used requires that or matching end elements.
*
* From http://www.w3.org/TR/2000/REC-xhtml1-20000126:
* "Empty elements must either have an end tag or the start tag must end with /<".
*
* See the file LICENSE.txt for copyright details.
* @author Matthew Doar, mdoar@pobox.com
*/
class CommentsHandler extends DefaultHandler {
/** The Comments object which is populated from the XML file. */
public Comments comments_ = null;
/** The current SingleComment object being populated. */
private List currSingleComment_ = null; // SingleComment[]
/** Set if in text. */
private boolean inText = false;
/** The current text which is being assembled from chunks. */
private String currentText = null;
/** The stack of SingleComments still waiting for comment text. */
private LinkedList tagStack = null;
/** Default constructor. */
public CommentsHandler(Comments comments) {
comments_ = comments;
tagStack = new LinkedList();
}
public void startDocument() {
}
public void endDocument() {
if (trace)
comments_.dump();
}
public void startElement(java.lang.String uri, java.lang.String localName,
java.lang.String qName, Attributes attributes) {
// The change to JAXP compliance produced this change.
if (localName.equals(""))
localName = qName;
if (localName.compareTo("comments") == 0) {
String commentsName = attributes.getValue("name");
String version = attributes.getValue("jdversion"); // Not used yet
if (commentsName == null) {
System.out.println("Error: no identifier found in the comments XML file.");
System.exit(3);
}
// Check the given names against the names of the APIs
int idx1 = JDiff.oldFileName.lastIndexOf('.');
int idx2 = JDiff.newFileName.lastIndexOf('.');
String filename2 = JDiff.oldFileName.substring(0, idx1) +
"_to_" + JDiff.newFileName.substring(0, idx2);
if (filename2.compareTo(commentsName) != 0) {
System.out.println("Warning: API identifier in the comments XML file (" + filename2 + ") differs from the name of the file.");
}
} else if (localName.compareTo("comment") == 0) {
currSingleComment_ = new ArrayList(); // SingleComment[];
} else if (localName.compareTo("identifier") == 0) {
// May have multiple identifiers for one comment's text
String id = attributes.getValue("id");
SingleComment newComment = new SingleComment(id, null);
// Store it here until we can add text to it
currSingleComment_.add(newComment);
} else if (localName.compareTo("text") == 0) {
inText = true;
currentText = null;
} else {
if (inText) {
// Start of an element, probably an HTML element
addStartTagToText(localName, attributes);
} else {
System.out.println("Error: unknown element type: " + localName);
System.exit(-1);
}
}
}
public void endElement(java.lang.String uri, java.lang.String localName,
java.lang.String qName) {
if (localName.equals(""))
localName = qName;
if (localName.compareTo("text") == 0) {
inText = false;
addTextToComments();
} else if (inText) {
addEndTagToText(localName);
}
}
/** Deal with a chunk of text. The text may come in multiple chunks. */
public void characters(char[] ch, int start, int length) {
if (inText) {
String chunk = new String(ch, start, length);
if (currentText == null)
currentText = chunk;
else
currentText += chunk;
}
}
/**
* Trim the current text, check it is a sentence and add it to all
* the comments which are waiting for it.
*/
public void addTextToComments() {
// Eliminate any whitespace at each end of the text.
currentText = currentText.trim();
// Check that it is a sentence
if (!currentText.endsWith(".") &&
!currentText.endsWith("?") &&
!currentText.endsWith("!") &&
currentText.compareTo(Comments.placeHolderText) != 0) {
System.out.println("Warning: text of comment does not end in a period: " + currentText);
}
// Add this comment to all the SingleComments waiting for it
Iterator iter = currSingleComment_.iterator();
while (iter.hasNext()) {
SingleComment currComment = (SingleComment)(iter.next());
if (currComment.text_ == null)
currComment.text_ = currentText;
else
currComment.text_ += currentText;
comments_.addComment(currComment);
}
}
/**
* Add the start tag to the current comment text.
*/
public void addStartTagToText(String localName, Attributes attributes) {
// Need to insert the HTML tag into the current text
String currentHTMLTag = localName;
// Save the tag in a stack
tagStack.add(currentHTMLTag);
String tag = "<" + currentHTMLTag;
// Now add all the attributes into the current text
int len = attributes.getLength();
for (int i = 0; i < len; i++) {
String name = attributes.getLocalName(i);
String value = attributes.getValue(i);
tag += " " + name + "=\"" + value+ "\"";
}
// End the tag
if (Comments.isMinimizedTag(currentHTMLTag)) {
tag += "/>";
} else {
tag += ">";
}
// Now insert the HTML tag into the current text
if (currentText == null)
currentText = tag;
else
currentText += tag;
}
/**
* Add the end tag to the current comment text.
*/
public void addEndTagToText(String localName) {
// Close the current HTML tag
String currentHTMLTag = (String)(tagStack.removeLast());
if (!Comments.isMinimizedTag(currentHTMLTag))
currentText += "</" + currentHTMLTag + ">";
}
public void warning(SAXParseException e) {
System.out.println("Warning (" + e.getLineNumber() + "): parsing XML comments file:" + e);
e.printStackTrace();
}
public void error(SAXParseException e) {
System.out.println("Error (" + e.getLineNumber() + "): parsing XML comments file:" + e);
e.printStackTrace();
System.exit(1);
}
public void fatalError(SAXParseException e) {
System.out.println("Fatal Error (" + e.getLineNumber() + "): parsing XML comments file:" + e);
e.printStackTrace();
System.exit(1);
}
/** Set to enable increased logging verbosity for debugging. */
private static final boolean trace = false;
}