Home | History | Annotate | Download | only in jdiff
      1 package jdiff;
      2 
      3 import java.io.*;
      4 import java.util.*;
      5 
      6 /* For SAX XML parsing */
      7 import org.xml.sax.Attributes;
      8 import org.xml.sax.SAXException;
      9 import org.xml.sax.SAXParseException;
     10 import org.xml.sax.XMLReader;
     11 import org.xml.sax.helpers.DefaultHandler;
     12 
     13 /**
     14  * Handle the parsing of an XML file and the generation of a Comments object.
     15  *
     16  * All HTML written for the comments sections in the report must
     17  * use tags such as <p/> rather than just <p>, since the XML
     18  * parser used requires that or matching end elements.
     19  *
     20  * From http://www.w3.org/TR/2000/REC-xhtml1-20000126:
     21  * "Empty elements must either have an end tag or the start tag must end with /<".
     22  *
     23  * See the file LICENSE.txt for copyright details.
     24  * @author Matthew Doar, mdoar (at) pobox.com
     25  */
     26 class CommentsHandler extends DefaultHandler {
     27 
     28     /** The Comments object which is populated from the XML file. */
     29     public Comments comments_ = null;
     30 
     31     /** The current SingleComment object being populated. */
     32     private List currSingleComment_ = null; // SingleComment[]
     33 
     34     /** Set if in text. */
     35     private boolean inText = false;
     36 
     37     /** The current text which is being assembled from chunks. */
     38     private String currentText = null;
     39 
     40     /** The stack of SingleComments still waiting for comment text. */
     41     private LinkedList tagStack = null;
     42 
     43     /** Default constructor. */
     44     public CommentsHandler(Comments comments) {
     45         comments_ = comments;
     46         tagStack = new LinkedList();
     47     }
     48 
     49     public void startDocument() {
     50     }
     51 
     52     public void endDocument() {
     53         if (trace)
     54             comments_.dump();
     55     }
     56 
     57     public void startElement(java.lang.String uri, java.lang.String localName,
     58                              java.lang.String qName, Attributes attributes) {
     59 	// The change to JAXP compliance produced this change.
     60 	if (localName.equals(""))
     61 	    localName = qName;
     62         if (localName.compareTo("comments") == 0) {
     63             String commentsName = attributes.getValue("name");
     64             String version = attributes.getValue("jdversion"); // Not used yet
     65             if (commentsName == null) {
     66                 System.out.println("Error: no identifier found in the comments XML file.");
     67                 System.exit(3);
     68             }
     69             // Check the given names against the names of the APIs
     70             int idx1 = JDiff.oldFileName.lastIndexOf('.');
     71             int idx2 = JDiff.newFileName.lastIndexOf('.');
     72             String filename2 = JDiff.oldFileName.substring(0, idx1) +
     73                 "_to_" + JDiff.newFileName.substring(0, idx2);
     74             if (filename2.compareTo(commentsName) != 0) {
     75                 System.out.println("Warning: API identifier in the comments XML file (" + filename2 + ") differs from the name of the file.");
     76             }
     77         } else if (localName.compareTo("comment") == 0) {
     78             currSingleComment_ = new ArrayList(); // SingleComment[];
     79         } else if (localName.compareTo("identifier") == 0) {
     80             // May have multiple identifiers for one comment's text
     81             String id = attributes.getValue("id");
     82             SingleComment newComment = new SingleComment(id, null);
     83             // Store it here until we can add text to it
     84             currSingleComment_.add(newComment);
     85         } else if (localName.compareTo("text") == 0) {
     86             inText = true;
     87             currentText = null;
     88         } else {
     89             if (inText) {
     90                 // Start of an element, probably an HTML element
     91                 addStartTagToText(localName, attributes);
     92             } else {
     93                 System.out.println("Error: unknown element type: " + localName);
     94                 System.exit(-1);
     95             }
     96         }
     97     }
     98 
     99     public void endElement(java.lang.String uri, java.lang.String localName,
    100                            java.lang.String qName) {
    101 	if (localName.equals(""))
    102 	    localName = qName;
    103         if (localName.compareTo("text") == 0) {
    104             inText = false;
    105             addTextToComments();
    106         } else if (inText) {
    107             addEndTagToText(localName);
    108         }
    109 
    110     }
    111 
    112     /** Deal with a chunk of text. The text may come in multiple chunks. */
    113     public void characters(char[] ch, int start, int length) {
    114         if (inText) {
    115             String chunk = new String(ch, start, length);
    116             if (currentText == null)
    117                 currentText = chunk;
    118             else
    119                 currentText += chunk;
    120         }
    121     }
    122 
    123     /**
    124      * Trim the current text, check it is a sentence and add it to all
    125      * the comments which are waiting for it.
    126      */
    127     public void addTextToComments() {
    128         // Eliminate any whitespace at each end of the text.
    129         currentText = currentText.trim();
    130         // Check that it is a sentence
    131         if (!currentText.endsWith(".") &&
    132             !currentText.endsWith("?") &&
    133             !currentText.endsWith("!") &&
    134             currentText.compareTo(Comments.placeHolderText) != 0) {
    135             System.out.println("Warning: text of comment does not end in a period: " + currentText);
    136         }
    137         // Add this comment to all the SingleComments waiting for it
    138         Iterator iter = currSingleComment_.iterator();
    139         while (iter.hasNext()) {
    140             SingleComment currComment = (SingleComment)(iter.next());
    141             if (currComment.text_ == null)
    142                 currComment.text_ = currentText;
    143             else
    144                 currComment.text_ += currentText;
    145             comments_.addComment(currComment);
    146         }
    147     }
    148 
    149     /**
    150      * Add the start tag to the current comment text.
    151      */
    152     public void addStartTagToText(String localName, Attributes attributes) {
    153         // Need to insert the HTML tag into the current text
    154         String currentHTMLTag = localName;
    155         // Save the tag in a stack
    156         tagStack.add(currentHTMLTag);
    157         String tag = "<" + currentHTMLTag;
    158         // Now add all the attributes into the current text
    159         int len = attributes.getLength();
    160         for (int i = 0; i < len; i++) {
    161             String name = attributes.getLocalName(i);
    162             String value = attributes.getValue(i);
    163             tag += " " + name + "=\"" + value+ "\"";
    164         }
    165 
    166         // End the tag
    167         if (Comments.isMinimizedTag(currentHTMLTag)) {
    168             tag += "/>";
    169         } else {
    170             tag += ">";
    171         }
    172         // Now insert the HTML tag into the current text
    173         if (currentText == null)
    174             currentText = tag;
    175         else
    176             currentText += tag;
    177     }
    178 
    179     /**
    180      * Add the end tag to the current comment text.
    181      */
    182     public void addEndTagToText(String localName) {
    183         // Close the current HTML tag
    184         String currentHTMLTag = (String)(tagStack.removeLast());
    185         if (!Comments.isMinimizedTag(currentHTMLTag))
    186             currentText += "</" + currentHTMLTag + ">";
    187     }
    188 
    189     public void warning(SAXParseException e) {
    190         System.out.println("Warning (" + e.getLineNumber() + "): parsing XML comments file:" + e);
    191         e.printStackTrace();
    192     }
    193 
    194     public void error(SAXParseException e) {
    195         System.out.println("Error (" + e.getLineNumber() + "): parsing XML comments file:" + e);
    196         e.printStackTrace();
    197         System.exit(1);
    198     }
    199 
    200     public void fatalError(SAXParseException e) {
    201         System.out.println("Fatal Error (" + e.getLineNumber() + "): parsing XML comments file:" + e);
    202         e.printStackTrace();
    203         System.exit(1);
    204     }
    205 
    206     /** Set to enable increased logging verbosity for debugging. */
    207     private static final boolean trace = false;
    208 
    209 }
    210 
    211