001: // Copyright (C) 2003,2004,2005 by Object Mentor, Inc. All rights reserved.
002: // Released under the terms of the GNU General Public License version 2 or later.
003: package fit;
004:
005: // Copyright (c) 2002 Cunningham & Cunningham, Inc.
006: // Released under the terms of the GNU General Public License version 2 or later.
007:
008: import java.io.*;
009: import fit.exception.FitParseException;
010:
011: public class Parse {
012:
013: public String leader;
014:
015: public String tag;
016:
017: public String body;
018:
019: public String end;
020:
021: public String trailer;
022:
023: public Parse more;
024:
025: public Parse parts;
026:
027: public static String tags[] = { "table", "tr", "td" };
028:
029: public Parse(String tag, String body, Parse parts, Parse more) {
030: this .leader = "\n";
031: this .tag = "<" + tag + ">";
032: this .body = body;
033: this .end = "</" + tag + ">";
034: this .trailer = "";
035: this .parts = parts;
036: this .more = more;
037: }
038:
039: public Parse(String tag, String body, String className) {
040: this .tag = "<" + tag + " class=\"" + className
041: + "\" colspan=\"0\">";
042: this .leader = "\n";
043: this .body = body;
044: this .end = "</" + tag + ">";
045: this .trailer = "";
046: this .parts = null;
047: this .more = null;
048: }
049:
050: public Parse(String text) throws FitParseException {
051: this (text, tags, 0, 0);
052: }
053:
054: public Parse(String text, String tags[]) throws FitParseException {
055: this (text, tags, 0, 0);
056: }
057:
058: public Parse(String text, String tags[], int level, int offset)
059: throws FitParseException {
060: String lc = text.toLowerCase();
061: int startTag = lc.indexOf("<" + tags[level]);
062: int endTag = lc.indexOf(">", startTag) + 1;
063: // int startEnd = lc.indexOf("</" + tags[level], endTag);
064: int startEnd = findMatchingEndTag(lc, endTag, tags[level],
065: offset);
066: int endEnd = lc.indexOf(">", startEnd) + 1;
067: int startMore = lc.indexOf("<" + tags[level], endEnd);
068: if (startTag < 0 || endTag < 0 || startEnd < 0 || endEnd < 0) {
069: throw new FitParseException("Can't find tag: "
070: + tags[level], offset);
071: }
072:
073: leader = text.substring(0, startTag);
074: tag = text.substring(startTag, endTag);
075: body = text.substring(endTag, startEnd);
076: end = text.substring(startEnd, endEnd);
077: trailer = text.substring(endEnd);
078:
079: if (level + 1 < tags.length) {
080: parts = new Parse(body, tags, level + 1, offset + endTag);
081: body = null;
082: } else { // Check for nested table
083: int index = body.indexOf("<" + tags[0]);
084: if (index >= 0) {
085: parts = new Parse(body, tags, 0, offset + endTag);
086: body = "";
087: }
088: }
089:
090: if (startMore >= 0) {
091: more = new Parse(trailer, tags, level, offset + endEnd);
092: trailer = null;
093: }
094: }
095:
096: /* Added by Rick Mugridge, Feb 2005 */
097: protected static int findMatchingEndTag(String lc,
098: int matchFromHere, String tag, int offset)
099: throws FitParseException {
100: int fromHere = matchFromHere;
101: int count = 1;
102: int startEnd = 0;
103: while (count > 0) {
104: int embeddedTag = lc.indexOf("<" + tag, fromHere);
105: int embeddedTagEnd = lc.indexOf("</" + tag, fromHere);
106: // Which one is closer?
107: if (embeddedTag < 0 && embeddedTagEnd < 0)
108: throw new FitParseException("Can't find tag: " + tag,
109: offset);
110: if (embeddedTag < 0)
111: embeddedTag = Integer.MAX_VALUE;
112: if (embeddedTagEnd < 0)
113: embeddedTagEnd = Integer.MAX_VALUE;
114: if (embeddedTag < embeddedTagEnd) {
115: count++;
116: startEnd = embeddedTag;
117: fromHere = lc.indexOf(">", embeddedTag) + 1;
118: } else if (embeddedTagEnd < embeddedTag) {
119: count--;
120: startEnd = embeddedTagEnd;
121: fromHere = lc.indexOf(">", embeddedTagEnd) + 1;
122: }
123: }
124: return startEnd;
125: }
126:
127: public int size() {
128: return more == null ? 1 : more.size() + 1;
129: }
130:
131: public Parse last() {
132: return more == null ? this : more.last();
133: }
134:
135: public Parse leaf() {
136: return parts == null ? this : parts.leaf();
137: }
138:
139: public Parse at(int i) {
140: return i == 0 || more == null ? this : more.at(i - 1);
141: }
142:
143: public Parse at(int i, int j) {
144: return at(i).parts.at(j);
145: }
146:
147: public Parse at(int i, int j, int k) {
148: return at(i, j).parts.at(k);
149: }
150:
151: public String text() {
152: return unescape(unformat(body)).trim();
153: }
154:
155: public static String unformat(String s) {
156: int i = 0, j;
157: while ((i = s.indexOf('<', i)) >= 0) {
158: if ((j = s.indexOf('>', i + 1)) > 0) {
159: s = s.substring(0, i) + s.substring(j + 1);
160: } else
161: break;
162: }
163: return s;
164: }
165:
166: public static String unescape(String s) {
167: int i = -1, j;
168: while ((i = s.indexOf('&', i + 1)) >= 0) {
169: if ((j = s.indexOf(';', i + 1)) > 0) {
170: String from = s.substring(i + 1, j).toLowerCase();
171: String to = null;
172: if ((to = replacement(from)) != null) {
173: s = s.substring(0, i) + to + s.substring(j + 1);
174: }
175: }
176: }
177: return s;
178: }
179:
180: public static String replacement(String from) {
181: if (from.equals("lt"))
182: return "<";
183: else if (from.equals("gt"))
184: return ">";
185: else if (from.equals("amp"))
186: return "&";
187: else if (from.equals("nbsp"))
188: return " ";
189: else
190: return null;
191: }
192:
193: public void addToTag(String text) {
194: int last = tag.length() - 1;
195: tag = tag.substring(0, last) + text + ">";
196: }
197:
198: public void addToBody(String text) {
199: body = body + text;
200: }
201:
202: public void print(PrintWriter out) {
203: out.print(leader);
204: out.print(tag);
205: if (parts != null) {
206: parts.print(out);
207: } else {
208: out.print(body);
209: }
210: out.print(end);
211: if (more != null) {
212: more.print(out);
213: } else {
214: out.print(trailer);
215: }
216: }
217: }
|