KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > au > id > jericho > lib > html > EndTag


1 // Jericho HTML Parser - Java based library for analysing and manipulating HTML
2
// Version 2.2
3
// Copyright (C) 2006 Martin Jericho
4
// http://sourceforge.net/projects/jerichohtml/
5
//
6
// This library is free software; you can redistribute it and/or
7
// modify it under the terms of the GNU Lesser General Public
8
// License as published by the Free Software Foundation; either
9
// version 2.1 of the License, or (at your option) any later version.
10
// http://www.gnu.org/copyleft/lesser.html
11
//
12
// This library is distributed in the hope that it will be useful,
13
// but WITHOUT ANY WARRANTY; without even the implied warranty of
14
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
// Lesser General Public License for more details.
16
//
17
// You should have received a copy of the GNU Lesser General Public
18
// License along with this library; if not, write to the Free Software
19
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20

21 package au.id.jericho.lib.html;
22
23 import java.util.*;
24
25 /**
26  * Represents the <a target="_blank" HREF="http://www.w3.org/TR/html401/intro/sgmltut.html#didx-element-3">end tag</a> of an
27  * {@linkplain Element element} in a specific {@linkplain Source source} document.
28  * <p>
29  * An end tag always has a {@linkplain #getTagType() type} that is a subclass of {@link EndTagType}, meaning it
30  * always starts with the characters '<code>&lt;/</code>'.
31  * <p>
32  * <code>EndTag</code> instances are obtained using one of the following methods:
33  * <ul>
34  * <li>{@link Element#getEndTag()}
35  * <li>{@link Tag#findNextTag()}
36  * <li>{@link Tag#findPreviousTag()}
37  * <li>{@link Source#findPreviousEndTag(int pos)}
38  * <li>{@link Source#findPreviousEndTag(int pos, String name)}
39  * <li>{@link Source#findPreviousTag(int pos)}
40  * <li>{@link Source#findPreviousTag(int pos, TagType)}
41  * <li>{@link Source#findNextEndTag(int pos)}
42  * <li>{@link Source#findNextEndTag(int pos, String name)}
43  * <li>{@link Source#findNextEndTag(int pos, String name, EndTagType)}
44  * <li>{@link Source#findNextTag(int pos)}
45  * <li>{@link Source#findNextTag(int pos, TagType)}
46  * <li>{@link Source#findEnclosingTag(int pos)}
47  * <li>{@link Source#findEnclosingTag(int pos, TagType)}
48  * <li>{@link Source#getTagAt(int pos)}
49  * <li>{@link Segment#findAllTags()}
50  * <li>{@link Segment#findAllTags(TagType)}
51  * </ul>
52  * <p>
53  * The {@link Tag} superclass defines the {@link Tag#getName() getName()} method used to get the name of this end tag.
54  * <p>
55  * See also the XML 1.0 specification for <a target="_blank" HREF="http://www.w3.org/TR/REC-xml#dt-etag">end tags</a>.
56  *
57  * @see Tag
58  * @see StartTag
59  * @see Element
60  */

61 public final class EndTag extends Tag {
62     private final EndTagType endTagType;
63
64     /**
65      * Constructs a new <code>EndTag</code>.
66      *
67      * @param source the {@link Source} document.
68      * @param begin the character position in the source document where this tag {@linkplain Segment#getBegin() begins}.
69      * @param end the character position in the source document where this tag {@linkplain Segment#getEnd() ends}.
70      * @param endTagType the {@linkplain #getEndTagType() type} of the end tag.
71      * @param name the {@linkplain Tag#getName() name} of the tag.
72      */

73     EndTag(final Source source, final int begin, final int end, final EndTagType endTagType, final String JavaDoc name) {
74         super(source,begin,end,name);
75         this.endTagType=endTagType;
76     }
77
78     /**
79      * Returns the {@linkplain Element element} that is ended by this end tag.
80      * <p>
81      * Returns <code>null</code> if this end tag is not properly matched to any {@linkplain StartTag start tag} in the source document.
82      * <p>
83      * This method is much less efficient than the {@link StartTag#getElement()} method.
84      * <p>
85      * IMPLEMENTATION NOTE: The explanation for why this method is relatively inefficient lies in the fact that more than one
86      * {@linkplain StartTagType start tag type} can have the same
87      * {@linkplain StartTagType#getCorrespondingEndTagType() corresponding end tag type}, so it is not possible to know for certain
88      * which type of start tag this end tag is matched to (see {@link EndTagType#getCorrespondingStartTagType()} for more explanation).
89      * Because of this uncertainty, the implementation of this method must check every start tag preceding this end tag, calling its
90      * {@link StartTag#getElement()} method to see whether it is terminated by this end tag.
91      *
92      * @return the {@linkplain Element element} that is ended by this end tag.
93      */

94     public Element getElement() {
95         if (element!=Element.NOT_CACHED) return element;
96         int pos=begin;
97         while (pos!=0) {
98             StartTag startTag=source.findPreviousStartTag(pos-1);
99             if (startTag==null) break;
100             Element foundElement=startTag.getElement(); // this automatically sets foundElement.getEndTag().element cache
101
if (foundElement.getEndTag()==this) return foundElement; // no need to set element as it was already done in previous statement
102
pos=startTag.begin;
103         }
104         return element=null;
105     }
106
107     /**
108      * Returns the {@linkplain EndTagType type} of this end tag.
109      * <p>
110      * This is equivalent to <code>(EndTagType)</code>{@link #getTagType()}.
111      *
112      * @return the {@linkplain EndTagType type} of this end tag.
113      */

114     public EndTagType getEndTagType() {
115         return endTagType;
116     }
117
118     // Documentation inherited from Tag
119
public TagType getTagType() {
120         return endTagType;
121     }
122
123     // Documentation inherited from Tag
124
public boolean isUnregistered() {
125         return endTagType==EndTagType.UNREGISTERED;
126     }
127
128     /**
129      * Returns an XML representation of this end tag.
130      * <p>
131      * This method is included for symmetry with the {@link StartTag#tidy()} method and simply
132      * returns the {@linkplain Segment#toString() source text} of the tag.
133      *
134      * @return an XML representation of this end tag.
135      */

136     public String JavaDoc tidy() {
137         return toString();
138     }
139
140     /**
141      * Generates the HTML text of a {@linkplain EndTagType#NORMAL normal} end tag with the specified tag {@linkplain #getName() name}.
142      * <p>
143      * <h4>Example:</h4>
144      * The following method call:
145      * <p>
146      * <code>EndTag.generateHTML("INPUT")</code>
147      * <p>
148      * returns the following output:
149      * <p>
150      * <code>&lt;/INPUT&gt;</code>
151      *
152      * @param tagName the {@linkplain #getName() name} of the end tag.
153      * @return the HTML text of a {@linkplain EndTagType#NORMAL normal} end tag with the specified tag {@linkplain #getName() name}.
154      * @see StartTag#generateHTML(String tagName, Map attributesMap, boolean emptyElementTag)
155      */

156     public static String JavaDoc generateHTML(final String JavaDoc tagName) {
157         return EndTagType.NORMAL.generateHTML(tagName);
158     }
159
160     public String JavaDoc getDebugInfo() {
161         final StringBuffer JavaDoc sb=new StringBuffer JavaDoc();
162         sb.append("\"/").append(name).append("\" ");
163         if (endTagType!=EndTagType.NORMAL) sb.append('(').append(endTagType.getDescription()).append(") ");
164         sb.append(super.getDebugInfo());
165         return sb.toString();
166     }
167
168     /**
169      * Regenerates the HTML text of this end tag.
170      * <p>
171      * This method has been deprecated as of version 2.2 and replaced with the exactly equivalent {@link #tidy()} method.
172      *
173      * @return the regenerated HTML text of this end tag.
174      * @deprecated Use {@link #tidy()} instead.
175      */

176     public String JavaDoc regenerateHTML() {
177         return toString();
178     }
179
180     /**
181      * Indicates whether the end tag of an <a HREF="HTMLElements.html#HTMLElement">HTML element</a> with the specified name is {@linkplain HTMLElements#getEndTagForbiddenElementNames() forbidden}.
182      * <p>
183      * This method has been deprecated as of version 2.0 and replaced with the {@link HTMLElements#getEndTagForbiddenElementNames()} method.
184      *
185      * @return <code>true</code> if the end tag of an <a HREF="HTMLElements.html#HTMLElement">HTML element</a> with the specified name is {@linkplain HTMLElements#getEndTagForbiddenElementNames() forbidden}, otherwise <code>false</code>.
186      * @deprecated Use {@link HTMLElements#getEndTagForbiddenElementNames()}<code>.contains(name.toLowerCase())</code> instead.
187      */

188     public static boolean isForbidden(String JavaDoc name) {
189         return HTMLElements.getEndTagForbiddenElementNames().contains(name.toLowerCase());
190     }
191
192     /**
193      * Indicates whether the end tag of an <a HREF="HTMLElements.html#HTMLElement">HTML element</a> with the specified name is {@linkplain HTMLElements#getEndTagOptionalElementNames() optional}.
194      * <p>
195      * This method has been deprecated as of version 2.0 and replaced with the {@link HTMLElements#getEndTagOptionalElementNames()} method.
196      *
197      * @return <code>true</code> if the end tag of an <a HREF="HTMLElements.html#HTMLElement">HTML element</a> with the specified name is {@linkplain HTMLElements#getEndTagOptionalElementNames() optional}, otherwise <code>false</code>.
198      * @deprecated Use {@link HTMLElements#getEndTagOptionalElementNames()}<code>.contains(name.toLowerCase())</code> instead.
199      */

200     public static boolean isOptional(String JavaDoc name) {
201         return HTMLElements.getEndTagOptionalElementNames().contains(name.toLowerCase());
202     }
203
204     /**
205      * Indicates whether the end tag of an <a HREF="HTMLElements.html#HTMLElement">HTML element</a> with the specified name is {@linkplain HTMLElements#getEndTagRequiredElementNames() required}.
206      * <p>
207      * This method has been deprecated as of version 2.0 and replaced with the {@link HTMLElements#getEndTagRequiredElementNames()} method.
208      *
209      * @return <code>true</code> if the end tag of an <a HREF="HTMLElements.html#HTMLElement">HTML element</a> with the specified name is {@linkplain HTMLElements#getEndTagRequiredElementNames() required}, otherwise <code>false</code>.
210      * @deprecated Use {@link HTMLElements#getEndTagRequiredElementNames()}<code>.contains(name.toLowerCase())</code> instead.
211      */

212     public static boolean isRequired(String JavaDoc name) {
213         return HTMLElements.getEndTagRequiredElementNames().contains(name.toLowerCase());
214     }
215
216     /**
217      * Returns the previous or next end tag matching the specified {@linkplain #getName() name}
218      * and {@linkplain EndTagType type}, starting at the specified position.
219      * <p>
220      * Called from {@link Source#findPreviousEndTag(int pos, String name)} and {@link Source#findNextEndTag(int pos, String name, EndTagType endTagType)}.
221      *
222      * @param source the {@link Source} document.
223      * @param pos the position to search from.
224      * @param name the {@linkplain #getName() name} of the tag (must be lower case and not null).
225      * @param endTagType the {@linkplain EndTagType type} of end tag to search for.
226      * @param previous search backwards if true, otherwise search forwards.
227      * @return the previous or next end tag matching the specified {@linkplain #getName() name} and {@linkplain EndTagType type}, starting at the specified position, or null if none is found.
228      */

229     static EndTag findPreviousOrNext(final Source source, final int pos, final String JavaDoc searchName, final EndTagType endTagType, final boolean previous) {
230         if (searchName==null) return (EndTag)Tag.findPreviousOrNextTag(source,pos,endTagType,previous);
231         if (searchName.length()==0) throw new IllegalArgumentException JavaDoc("searchName argument must not be zero length");
232         final String JavaDoc searchString=endTagType.generateHTML(searchName);
233         try {
234             final ParseText parseText=source.getParseText();
235             int begin=pos;
236             do {
237                 begin=previous?parseText.lastIndexOf(searchString,begin):parseText.indexOf(searchString,begin);
238                 if (begin==-1) return null;
239                 final EndTag endTag=(EndTag)source.getTagAt(begin);
240                 if (endTag!=null && endTag.getEndTagType()==endTagType) return endTag;
241             } while (previous ? (begin-=1)>=0 : (begin+=1)<source.end);
242         } catch (IndexOutOfBoundsException JavaDoc ex) {
243             // this should only happen when the end of file is reached in the middle of a tag.
244
// we don't have to do anything to handle it as there will be no more tags anyway.
245
}
246         return null;
247     }
248
249     static EndTag findPreviousOrNext(final Source source, int pos, final boolean previous) {
250         while (true) {
251             final Tag tag=Tag.findPreviousOrNextTag(source,pos,previous);
252             if (tag==null) return null;
253             if (tag instanceof EndTag) return (EndTag)tag;
254             pos+=previous?-1:1;
255         }
256     }
257 }
258
259
Popular Tags