1 package DTDDoc;
2
3 import java.util.HashMap;
4 import java.util.Map;
5
6 import com.wutka.dtd.DTDComment;
7
8 /** <p>This class contains several tools used for parsing javadoc-like
9 * comments (tags) appearing in XML comments.</p>
10 *
11 * <p>Such a comment
12 * is made of text and "tags". A tag is a \@ immediately followed by
13 * a word and preceeded by at least a space.
14 * This function will return a map that associate
15 * tags to their text. The text associated to a tag is the one
16 * that follows it and that precedes the next tag or the end
17 * of the comment. The text that appears before the first
18 * tag will automatically associated to the "comment" tag.</p>
19 * <p>Right now, only "attr" tag can appear multiple times :
20 * other tags can appear once and only once!</p>
21 * <p>It is guaranteed that there are no spaces at the beginning or
22 * at the end of the tag's value.</p>
23 *
24 * @see #getUniqueTagValue(String)
25 * @see #getMultipleTagValue(String)
26 * @author Stefan Champailler */
27
28 public class CommentParser {
29
30 private final Logger log;
31
32 /** The character preceding each of the tag recognized in our comment
33 * system. */
34
35 private static final char BEGIN_TAG = DTDCommenter.BEGIN_TAG;
36
37 /** The tag starting a comment. This one is put in front on the
38 * XML comments by default. */
39
40 private static final String COMMENT_TAG = DTDCommenter.COMMENT_TAG;
41
42 /** A mapping between each "@" tag and its value.
43 * @see #putTagValue(String, String)
44 */
45 private final Map values = new HashMap();
46
47 /** This function parses a javaDoc-like comment:the resulting
48 * mapping between each tag and its value is added in {@link #values} Map attribute.
49 *
50 * @param comment the comment
51 * @param getAroundNetBeanComments If true, we replace <!--- with
52 * <!-- (and thus interpreting NetBeans comments as they should, as
53 * explained <a
54 * href="http://sourceforge.net/mailarchive/forum.php?thread_id=23713463&forum_id=33177">here</a>.)
55 */
56
57 private void parseComment( String comment, boolean
58 getAroundNetBeanComments) {
59
60 int start = 0;
61
62
63
64
65
66 if( getAroundNetBeanComments && comment.startsWith("-")) {
67 comment = comment.substring(1);
68 }
69
70
71
72
73 comment = COMMENT_TAG+" "+comment;
74
75
76
77 while( start < comment.length()) {
78
79 int tagNameStart = comment.indexOf( BEGIN_TAG, start);
80
81
82
83 int tagNameEnd = comment.indexOf( ' ', tagNameStart);
84
85 if( tagNameStart >= start && tagNameEnd > tagNameStart) {
86
87
88 String tagName = comment.substring( tagNameStart, tagNameEnd);
89
90
91
92
93 int tagValueStart = tagNameEnd + 1;
94 int tagValueEnd = comment.indexOf( BEGIN_TAG, tagValueStart);
95
96
97
98
99 if( tagValueEnd == -1)
100 tagValueEnd = comment.length();
101
102
103
104
105 if( tagValueEnd > tagValueStart &&
106 comment.substring( tagValueStart, tagValueEnd)
107 .trim().length() > 0) {
108
109 String tagValue = comment.substring( tagValueStart, tagValueEnd).trim();
110 putTagValue( tagName, tagValue);
111 } else if (! COMMENT_TAG.equals(tagName)) {
112
113
114 log.warn("The tag "+tagName+" can not be empty.");
115 }
116
117 start = tagNameEnd + 1;
118
119 } else
120 start = comment.length();
121 }
122 }
123
124 public String getUniqueTagValue( String tagName) {
125
126 Object v = values.get( tagName);
127
128 if( v == null)
129 return null;
130 else if( v instanceof String)
131 return (String) v;
132 else if( v instanceof Map) {
133 log.warn("Expected a unique value for tag " + BEGIN_TAG + tagName);
134 return null;
135 } else {
136 log.error("Internal error, unexpected type for" +
137 " tag " + BEGIN_TAG + tagName + "'s value.");
138 return null;
139 }
140 }
141
142 public Map getMultipleTagValue( String tagName) {
143 Object v = values.get( tagName);
144
145 if( v == null)
146 return null;
147 else if( v instanceof Map)
148 return (Map) v;
149 else if( v instanceof String) {
150 log.warn("Expected a multiple value for tag " + BEGIN_TAG + tagName);
151 return null;
152 } else {
153 log.error("Unexpected type for" +
154 " tag " + BEGIN_TAG + tagName + "'s value.");
155 return null;
156 }
157 }
158
159 private void putTagValue( String name, String content) {
160
161 if( name == null)
162 throw new IllegalArgumentException("putTagValue(): null tag name !");
163
164 if( "@attr".equalsIgnoreCase( name)) {
165
166 if( content == null)
167 throw new IllegalArgumentException("putTagValue(): content null for "+name+" !");
168
169 String key = null;
170 String value = null;
171 int firstSpaceIndex = content.indexOf(' ');
172
173 if( firstSpaceIndex != -1 && firstSpaceIndex+1 < content.length()) {
174 key = content.substring( 0, firstSpaceIndex);
175 value = content.substring( firstSpaceIndex+1, content.length());
176 } else {
177 log.warn("The tag " + name + " requires a key and a value !");
178 return;
179 }
180
181 Map current = (Map) values.get( name);
182 if( current == null) {
183 current = new HashMap();
184 values.put( name, current);
185 }
186 current.put( key, value);
187 } else {
188
189 values.put( name, content);
190 }
191 }
192
193 public CommentParser( DTDComment comment, Logger log, boolean
194 getAroundNetBeanComments) {
195 this.log = log;
196 parseComment( comment.getText(), getAroundNetBeanComments);
197 }
198 }