001package Torello.HTML; 002 003/** 004 * Represents HTML Comments, and is one of only three HTML Element Classes provided by the Java 005 * HTML Library Tool, and also one of the three data-classes that can be generated by the HTML 006 * Parser. 007 * 008 * <EMBED CLASS='external-html' DATA-FILE-ID=COMMENT_NODE> 009 * 010 * <EMBED CLASS='external-html' DATA-FILE-ID=HTML_NODE_SUB_IMG> 011 * 012 * @see TagNode 013 * @see TextNode 014 * @see HTMLNode 015 */ 016@Torello.JavaDoc.JDHeaderBackgroundImg(EmbedTagFileID="HTML_NODE_SUBCLASS") 017public final class CommentNode 018 extends HTMLNode 019 implements CharSequence, java.io.Serializable, Cloneable, Comparable<CommentNode> 020{ 021 /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUID> */ 022 public static final long serialVersionUID = 1; 023 024 /** 025 * This stores a copy of the body of the comment. Specifically, (and simply) the java string 026 * method {@code body = str.substring(4, str.length() - 3);} is called and stored here. Yes, 027 * this does mean that extra memory / double memory is used to store comments, however the 028 * trade-offs are somewhat high. 029 * 030 * <BR /><BR /><B><SPAN STYLE="color: red;">TRADEOFFS:</B></SPAN> If the programmer or user 031 * ever wishes to perform a search, it becomes obvious that leaving off the beginning and 032 * trailing {@code '<!--'} and {@code '-->'} markers when specifying a search provides more 033 * easily readable code, and less error prone code. Thus, when using the 034 * {@code CommentNodeFind, Get, Peek, Poll, etc...} methods in the {@code package NodeSearch}, 035 * a Java String {@code substring(...)} would have to be invoked on every search comparison 036 * loop invocation. Primarily, keeping {@code class HTMLNode} and it's descendants all 037 * immutable is a much higher priority to ensure clean code, it becomes necessary to keep a 038 * redundant copy of the body {@code String}. 039 */ 040 public final String body; 041 042 /** 043 * This constructor simply makes a call to {@code super(s); } <I>a.k.a.</I> 044 * {@code class HTML.HTMLNode} 045 * 046 * <BR /><BR />This constructor also checks to ensure that the internal {@code String}-field 047 * ({@code public final String str}) contains beginning and ending comment markers: 048 * {@code '<!--'} and {@code '-->'} 049 * 050 * @throws IllegalArgumentException If the passed string does not start and end with the 051 * appropriate HTML comment-markers: {@code <!--} and {@code -->} 052 */ 053 public CommentNode(String s) 054 { 055 super(s); 056 057 if (! s.startsWith("<!--")) throw new IllegalArgumentException 058 ("The passed HTML string does not start with comment marker '<!--'"); 059 060 if (! s.endsWith("-->")) throw new IllegalArgumentException 061 ("The passed HTML string does not end with comment marker '-->'"); 062 063 body = str.substring(4, str.length() - 3); 064 065 if (body.contains("-->")) throw new IllegalArgumentException 066 ("The passed HTML string has multiple occurrences of substring '-->'"); 067 } 068 069 /** 070 * This method identifies that {@code 'this'} instance of (abstract parent-class) 071 * {@link HTMLNode} is, indeed, an instance of sub-class {@code CommentNode}. 072 * 073 * <BR /><BR /><B CLASS=JDDescLabel>Final Method:</B> 074 * 075 * <BR />This method is final, and cannot be modified by sub-classes. 076 * 077 * @return This method shall always return {@code TRUE} It overrides the parent-class 078 * {@code HTMLNode} method {@link #isCommentNode()}, which always returns {@code FALSE}. 079 */ 080 @Override 081 public final boolean isCommentNode() { return true; } 082 083 /** 084 * This method identifies that {@code 'this'} instance of (abstract parent-class) 085 * {@link HTMLNode} is, indeed, an instance of sub-class {@code CommentNode}. 086 * 087 * <BR /><BR /><B CLASS=JDDescLabel>Final Method:</B> 088 * 089 * <BR />This method is final, and cannot be modified by sub-classes. 090 * 091 * @return {@code 'this'} reference. This method can be used inside loops for improving 092 * the readability of loop-condition expressions. See example below: 093 * 094 * <DIV CLASS=EXAMPLE>{@code 095 * Vector<HTMLNode> fileVec = HTMLPage.getPageTokens(new URL("http://some.url.com"), false); 096 * CommentNode c; 097 * 098 * // NOTE: The casting to class CommentNode is automatically acheived with this method, 099 * // which can make loops a lot easier to read. Only a CommentNode instance will have 100 * // a '.body' field. Attempting to read a '.body' field from an instance of HTMLNode 101 * // would immediately generate a compile-time error. 102 * 103 * for (HTMLNode n : fileVec) 104 * if ((c = myHTMLVector.elementAt(i).ifCommentNode()) != null) 105 * if (c.body.equals("Some Comment Node Text")) 106 * ... 107 * }</div> 108 * 109 * <BR /><BR />This method-version overrides the parent-class-version, which always returns 110 * null. This method is <I>not overriden by other {@code HTMLNode} sub-classes.</I> 111 */ 112 @Override 113 public final CommentNode ifCommentNode() { return this; } 114 115 /** 116 * Java's {@code interface Cloneable} requirements. This instantiates a new 117 * {@code CommentNode} with identical {@code String str} and {@code String body} fields. 118 * @return A new {@code CommentNode} whose internal fields are identical to this one. 119 */ 120 public CommentNode clone() { return new CommentNode(str); } 121 122 /** 123 * Java's {@code interface Comparable<T>} requirements. This does a very simple comparison 124 * using the underlying field {@code final String str} that all {@code HTMLNode's} contain. 125 * @param cn Any other {@code CommentNode} to be compared to {@code 'this' CommentNode} 126 * @return An integer that fulfils Java's {@code interface Comparable<T> public boolean 127 * compareTo(T t)} method requirements. 128 */ 129 public int compareTo(CommentNode cn) 130 { return this.body.compareToIgnoreCase(cn.body); } 131}