KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > xml > tools > doclet > DTDDoclet


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.netbeans.modules.xml.tools.doclet;
20
21 import java.util.*;
22 import java.text.DateFormat JavaDoc;
23
24 import org.xml.sax.Locator JavaDoc;
25 import org.xml.sax.InputSource JavaDoc;
26 import org.xml.sax.SAXException JavaDoc;
27 import org.xml.sax.SAXParseException JavaDoc;
28 import org.xml.sax.AttributeList JavaDoc;
29
30 import org.xml.sax.DocumentHandler JavaDoc;
31 import org.xml.sax.DTDHandler JavaDoc;
32 import org.xml.sax.ErrorHandler JavaDoc;
33 import org.xml.sax.EntityResolver JavaDoc;
34
35 import org.netbeans.tax.*;
36 import org.netbeans.tax.decl.*;
37
38 /**
39  * Creates [X]HTML documentation for DTD.
40  * <p>There is a special doclet comment preceding element declaration.
41  * The comment is delimited by "<!---" and "-->" i.e. starting
42  * delimiter uses three "---".
43  *
44  * <p>Generated element content model consists of hyperlinked structure.
45  *
46  * @author Petr Kuzel
47  * @version 1.0
48  */

49 public class DTDDoclet {
50
51     private RefList s; //tmp holding whole result
52

53     private RefList elementIndex = new RefList();
54     
55     private String JavaDoc comment; //last suitable comment or null if none
56

57     /* This ellement is just being commented.
58      * Used for "referenced by" creation.
59      */

60     private String JavaDoc currentElement = null;
61     
62     /* Hold element name keyed RefLists used at
63      * "referenced by" section.
64      */

65     private HashMap elementRefs = new HashMap();
66     
67     // configurable output format
68

69     private final String JavaDoc HEADLINE1 = "h2"; // NOI18N
70
private final String JavaDoc HEADLINE2 = "b"; // NOI18N
71

72     private final String JavaDoc LIST = "ul"; // NOI18N
73
private final String JavaDoc LIST_ITEM = "li"; // NOI18N
74

75     private final String JavaDoc PAR = "p"; // NOI18N
76

77     private final String JavaDoc ROOT = "html"; // NOI18N
78
private final String JavaDoc BODY = "body"; // NOI18N
79

80     /** Creates new DTDDoclet engine*/
81     public DTDDoclet() {
82         
83     }
84
85     /**
86      * @return a String representing XHTML content
87      */

88     public String JavaDoc createDoclet (TreeDTD dtd) {
89         if (dtd == null)
90             return ""; // NOI18N
91

92         Iterator it;
93         s = new RefList();
94         
95         s.append("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"); // NOI18N
96

97         s.appendStartTag(ROOT).append("\n<head>\n<title>" + Util.THIS.getString("PAGE_TITLE") + "</title>\n"); // NOI18N
98
s.append("<meta http-equiv=\"Content-Type\" content=\"text/xhtml; charset=UTF-8\" />\n");
99         s.append("</head>\n");
100         s.append("\n<!-- Generated on " + DateFormat.getDateInstance().format(new Date()) + " by NetBeans XML module. -->\n"); // NOI18N
101
s.appendStartTag(BODY);
102         
103         headline1(Util.THIS.getString("TEXT_Element_Index"));
104         
105         s.append(elementIndex);
106         
107         headline1(Util.THIS.getString("TEXT_Element_Details"));
108                         
109         it = dtd.getChildNodes(TreeChild.class, true).iterator();
110         
111         Vector list = new Vector();
112         while (it.hasNext()) {
113             TreeNode child = (TreeNode)it.next();
114         if (child instanceof TreeElementDecl) {
115         commentElement((TreeElementDecl) child);
116         comment = null;
117         } else if (child instanceof TreeComment) {
118         comment = decodeComment((TreeComment) child);
119             } else if (child instanceof TreeText || child instanceof TreeParameterEntityReference) {
120                 // do not clear comment #30094
121
} else {
122         // disable comment
123
comment = null;
124             }
125         }
126
127         
128         // create index at elementIndex reference position.
129
// strings are sorted by alphabet
130

131         TreeSet index = new TreeSet();
132         it = elementRefs.keySet().iterator();
133                 
134         while (it.hasNext()) {
135             index.add(it.next());
136         }
137         
138         elementIndex.appendStartTag(LIST);
139         it = index.iterator();
140         while (it.hasNext()) {
141             Object JavaDoc next = it.next();
142             listitem(elementIndex, "<a HREF=\"#" + next + "\">" + next + "</a>"); // NOI18N
143
}
144         elementIndex.appendEndTag(LIST);
145         
146         
147         // terminate the html page
148
//
149

150         s.appendEndTag(BODY).appendEndTag(ROOT);
151         return s.toString();
152     }
153
154     //~~~~~~~~~~~~~~~ DOCUMENTATION STUFF ~~~~~~~~~~~~~~~~~~~~~~~~
155

156     
157     /** Comment is paired just with the next element declaration and
158      * it must statt with <!---.
159      */

160     private String JavaDoc decodeComment(TreeComment node) {
161         return node.getData().startsWith("-") ? node.getData().substring(1).trim() : null; // NOI18N
162
}
163     
164
165     
166     private void commentElement(TreeElementDecl node) {
167         String JavaDoc tag = node.getName();
168         currentElement = tag;
169                 
170         headline1(tag, tag);
171         // try to survive various user tags wrap it in <div>
172
s.append(comment == null ? "" : "<div>" + comment + "</div>"); // NOI18N
173
commentAttributes(node);
174         
175         headline2(Util.THIS.getString("TEXT_ContentModel"));
176         TreeElementDecl.ContentType type = node.getContentType();
177         s.append("<p><tt>"); // NOI18N
178
commentContentModel(type);
179         s.append("</tt></p>"); // NOI18N
180

181         headline2(Util.THIS.getString("TEXT_Referenced_by"));
182         s.append("<p><tt>"); // NOI18N
183
s.append(getRefList(tag));
184         s.append("</tt></p>"); // NOI18N
185
s.append("\n"); // NOI18N
186
}
187     
188     /*
189      * attributes are commented like Java fields declarations.
190      * <modifier> <type> <name> = <default>
191      */

192     private void commentAttributes(TreeElementDecl element) {
193         
194         Iterator it = element.getAttributeDefs().iterator();
195         
196         if (!!! it.hasNext())
197         return;
198         
199         headline2(Util.THIS.getString("TEXT_Declared_Attributes"));
200         s.appendStartTag(LIST); // NOI18N
201

202         while (it.hasNext()) {
203             TreeAttlistDeclAttributeDef next = (TreeAttlistDeclAttributeDef) it.next();
204             
205             String JavaDoc defVal = next.getDefaultValue();
206             if ( ( defVal == null ) ||
207                  ( defVal.length() == 0 ) ) {
208                 defVal = "";
209             } else {
210                 defVal = " = " + defVal; // NOI18N
211
}
212             
213             String JavaDoc defType = next.getDefaultTypeName() == null ? "#DEFAULT" : next.getDefaultTypeName(); // NOI18N
214

215             String JavaDoc text = ""; // NOI18N
216

217             if (next.getType() == next.TYPE_ENUMERATED) {
218                 text = defType + " ENUMERATION " + next.getEnumeratedTypeString(); // NOI18N
219
} else {
220                 text = defType + " " + next.getTypeName(); // NOI18N
221
}
222             
223             text += " " + next.getName() + defVal; // NOI18N
224

225             listitem(s, text);
226         }
227         
228         s.appendEndTag(LIST); // NOI18N
229
}
230
231     /*
232      * Content model documentation consists of links to element definitions.
233      * It is recursive implementation.
234      */

235     private void commentContentModel (TreeElementDecl.ContentType type) {
236
237         if (type instanceof EMPTYType) {
238             
239             s.append("EMPTY"); // NOI18N
240
return;
241             
242         } else if (type instanceof ANYType) {
243
244             s.append("ANY"); // NOI18N
245
return;
246             
247         }
248
249         
250         if (type instanceof LeafType) {
251             
252             LeafType leaf = (LeafType)type;
253             String JavaDoc tag = leaf.getName();
254             s.append("<a HREF=\"#").append(tag).append("\">"); // NOI18N
255
s.append(tag).append("</a>").append(leaf.getMultiplicity()); // NOI18N
256

257             // append "tag reference from currentElement" as fragment to force uniques // NOI18N
258
// because one content model can reference same tag more times
259
RefList refs = getRefList(tag);
260             String JavaDoc prefixSeparator = ", "; // NOI18N
261
if (refs.isEmpty()) {
262                 prefixSeparator = ""; // NOI18N
263
}
264             
265             refs.appendUniq(prefixSeparator + "<a HREF=\"#" + currentElement + "\">" + currentElement + "</a>"); // NOI18N
266

267             return;
268         }
269
270
271         s.append("("); // NOI18N
272

273         if (type.allowText()) {
274                     
275             s.append("#PCDATA"); // NOI18N
276

277         }
278         
279
280         // it is a group, select proper separator
281

282         String JavaDoc separator = ""; // NOI18N
283
if (type instanceof ChildrenType) {
284             String JavaDoc sepChar = ((ChildrenType)type).getSeparator();
285             
286             //',' always directly follows previous word otherwise put and extra space
287
String JavaDoc prefix = sepChar.equals(",") == false ? "&nbsp;" : ""; // NOI18N
288
separator = prefix + sepChar + " "; // NOI18N
289
}
290         
291         // do not prepend separator if first
292
boolean prependSeparator = type.allowText(); //#PCDATA
293

294         // recursive descend through given content model groups
295

296         if (type instanceof TypeCollection) {
297             TypeCollection col = (TypeCollection) type;
298             Collection types = col.getTypes();
299                                     
300             Iterator it = types.iterator();
301             while (it.hasNext()) {
302                 TreeElementDecl.ContentType next = (TreeElementDecl.ContentType) it.next();
303                 
304                 if (prependSeparator) {
305                     s.append (separator);
306                 }
307                 
308                 prependSeparator = true;
309                     
310                 commentContentModel(next);
311             }
312         }
313
314         s.append(")" + type.getMultiplicity()); // NOI18N
315

316     }
317
318     private void headline1(String JavaDoc text, String JavaDoc id) {
319         s.append("\n\n<hr />\n").appendStartTag(HEADLINE1); //NOI18N
320
if (id != null) s.append("<a name=\"" + id + "\"></a>"); // NOI18N
321
s.append(text).appendEndTag(HEADLINE1).append("\n"); // NOI18N
322
}
323     
324     private void headline1(String JavaDoc text) {
325         headline1(text, null);
326     }
327
328     private void headline2(String JavaDoc text) {
329         s.append("\n").appendStartTag(PAR).appendStartTag(HEADLINE2).append(text).appendEndTag(HEADLINE2).appendEndTag(PAR).append("\n"); // NOI18N
330
}
331     
332     private void listitem(RefList s, String JavaDoc text) {
333         s.appendStartTag(LIST_ITEM).append("<tt>").append(text).append("</tt>").appendEndTag(LIST_ITEM).append("\n"); // NOI18N
334
}
335     
336     //~~~~~~~~~~~~~~~~~ BACKGROUND STUFF ~~~~~~~~~~~~~~~~~~~~~~~
337

338     
339     
340
341     /*
342      * @return RefList for given tag, never null
343      */

344     private RefList getRefList(String JavaDoc element) {
345   
346         RefList toret = (RefList) elementRefs.get(element);
347         
348         if (toret == null) {
349             toret = new RefList();
350             elementRefs.put(element, toret);
351         }
352         
353         return toret;
354     }
355     
356         
357     /** Ref list allows embedding an empty list that is contructed later.
358      * The implementation mimics StringBuffer append() behaviour.
359      */

360     private class RefList extends LinkedList {
361         
362         /** Serial Version UID */
363         private static final long serialVersionUID = 4291872863957329823L;
364
365         /**
366          * @param obj accepts String, StringBuffer or RefList instances.
367          */

368         public boolean add(Object JavaDoc obj) {
369             if (obj instanceof StringBuffer JavaDoc || obj instanceof RefList || obj instanceof String JavaDoc) {
370                 return super.add(obj);
371             } else {
372                 throw new ClassCastException JavaDoc("String or RefList required."); // NOI18N
373
}
374         }
375         
376         public RefList append(String JavaDoc s) {
377             if (size() != 0 && (getLast() instanceof StringBuffer JavaDoc)) {
378                 StringBuffer JavaDoc last = (StringBuffer JavaDoc) getLast();
379                 last.append(s);
380             } else {
381                 add(new StringBuffer JavaDoc(s));
382             }
383             return this;
384         }
385
386         public RefList append(RefList s) {
387             add(s);
388             return this;
389         }
390         
391         /** Append it as fragment only if this fragment does not exist */
392         public RefList appendUniq(String JavaDoc fragment) {
393             if (!contains(fragment)) add(fragment);
394             return this;
395         }
396         
397         // append start tag
398
RefList appendStartTag(String JavaDoc tag) {
399             return append("<" + tag + ">"); // NOI18N
400
}
401         
402         RefList appendEndTag(String JavaDoc tag) {
403             return append("</" + tag + ">"); // NOI18N
404
}
405
406         
407         public String JavaDoc toString() {
408             Iterator it = iterator();
409             StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
410             while(it.hasNext()) {
411                 buf.append(it.next().toString());
412             }
413             return buf.toString();
414         }
415                 
416     }
417 }
418
Popular Tags