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