001: package net.sourceforge.squirrel_sql.fw.datasetviewer;
002:
003: /*
004: * Copyright (C) 2004 Gerd Wagner
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or (at your option) any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: */
020:
021: import net.sourceforge.squirrel_sql.fw.util.StringManager;
022: import net.sourceforge.squirrel_sql.fw.util.StringManagerFactory;
023:
024: import javax.swing.JOptionPane;
025: import java.util.ArrayList;
026:
027: /**
028: * This is an XML prettyprinter. It takes a string that is in XML format
029: * and converts it into a multi-line, indented structure
030: * that is easier for the user to read.
031: * Prior to calling this method, nothing in Squirrel is "XML-aware",
032: * so we do not prevent the user from calling this method if the
033: * data is not an XML string.
034: * However, we do warn the user if the data is not XML or is improperly formatted.
035: */
036: public class XmlRefomatter {
037:
038: private static final StringManager s_stringMgr = StringManagerFactory
039: .getStringManager(XmlRefomatter.class);
040:
041: // i18n[xmlRefomatter.unexpectedProblem=Unexpected problem during formatting.]
042: private static String DEFAULT_MESSAGE = s_stringMgr
043: .getString("xmlRefomatter.unexpectedProblem");
044: private static String _message = DEFAULT_MESSAGE;
045: private static boolean _showWarningMessages = true;
046:
047: public static String reformatXml(String xml) {
048: // do a simple check to see if the string might contain XML or not
049: if (xml.indexOf("<") == -1 || xml.equals("<null>")) {
050: // no tags, so cannot be XML
051: JOptionPane.showMessageDialog(null,
052: // i18n[xmlRefomatter.noXml=The data does not contain any XML tags. No reformatting done.]
053: s_stringMgr.getString("xmlRefomatter.noXml"),
054: // i18n[xmlRefomatter.xmlWarning=XML Warning]
055: s_stringMgr.getString("xmlRefomatter.xmlWarning"),
056: JOptionPane.WARNING_MESSAGE);
057: return xml;
058: }
059:
060: try {
061: StringBuffer ret = new StringBuffer();
062: int depth = 0;
063: ParseRes parseRes = getParseRes(xml, 0);
064:
065: if (parseRes == null) {
066: // the parse did not find XML, or it was mal-formed
067: showWarning(_message);
068: return xml;
069: }
070:
071: xml = xml.trim();
072:
073: // GWG XML format check code
074: ArrayList<String> tagList = new ArrayList<String>();
075:
076: while (null != parseRes) {
077:
078: if (ParseRes.BEGIN_TAG == parseRes.type) {
079: tagList.add(parseRes.item); // GWG XML format check code
080:
081: ret.append(getIndent(depth)).append(parseRes.item);
082: ParseRes nextRes = getParseRes(xml, parseRes.pos);
083:
084: // see if there was a problem during parsing
085: if (nextRes == null) {
086: // the parse did not find XML, or it was mal-formed
087: showWarning(_message);
088: return xml;
089: }
090:
091: if (ParseRes.TEXT != nextRes.type) {
092: ret.append("\n");
093: }
094:
095: ++depth;
096: } else if (ParseRes.END_TAG == parseRes.type) {
097: // GWG format check code follows...
098: if (tagList.size() > 0) {
099: String startTag = tagList
100: .remove(tagList.size() - 1);
101: // Assume that all start tags are "<...>" or include a space
102: // after the tag name (e.g. as in "<SOMETAG args>" and all
103: // end tags are "</...>". Remove the syntactic markers,
104: // then remove any spaces, and convert to upper case for comparison
105: String testableStartTag = startTag.substring(1,
106: startTag.length() - 1).trim()
107: .toUpperCase();
108: if (testableStartTag.indexOf(' ') > -1)
109: testableStartTag = testableStartTag
110: .substring(0, testableStartTag
111: .indexOf(' '));
112: String endTag = parseRes.item.substring(2,
113: parseRes.item.length() - 1).trim()
114: .toUpperCase();
115:
116: if (!testableStartTag.equals(endTag)) {
117: Object[] args = new Object[] { startTag,
118: parseRes.item };
119:
120: // i18n[xmlRefomatter.malformedXml=Possible mal-formed XML:\n Starting tag was: {0}\nEnding Tag was: {1}\nContinuing with reformatting XML."]
121: String msg = s_stringMgr.getString(
122: "xmlRefomatter.malformedXml", args);
123: showWarning(msg);
124: }
125: }
126: // End GWG format check code
127:
128: --depth;
129: if (ret.toString().endsWith("\n")) {
130: ret.append(getIndent(depth));
131: }
132: ret.append(parseRes.item).append("\n");
133: } else if (ParseRes.CLOSED_TAG == parseRes.type) {
134: ret.append(getIndent(depth)).append(parseRes.item)
135: .append("\n");
136: } else if (ParseRes.TEXT == parseRes.type) {
137: ret.append(parseRes.item);
138: }
139: parseRes = getParseRes(xml, parseRes.pos);
140: }
141:
142: return ret.toString();
143: } catch (Exception e) {
144: // the parse did not find XML, or it was mal-formed
145: JOptionPane
146: .showMessageDialog(
147: null,
148: DEFAULT_MESSAGE,
149: // i18n[xmlReformatter.xmlWarning2=XML Warning]
150: s_stringMgr
151: .getString("xmlReformatter.xmlWarning2"),
152: JOptionPane.WARNING_MESSAGE);
153: e.printStackTrace();
154: } finally {
155: _message = DEFAULT_MESSAGE;
156: _showWarningMessages = true;
157: }
158: return xml;
159:
160: }
161:
162: private static void showWarning(String message) {
163: if (false == _showWarningMessages) {
164: return;
165: }
166:
167: Object[] options = {
168: // i18n[xmlReformatter.yes=YES]
169: s_stringMgr.getString("xmlReformatter.yes"),
170: // i18n[xmlReformatter.no=NO]
171: s_stringMgr.getString("xmlReformatter.no") };
172:
173: int ret = JOptionPane.showOptionDialog(
174: null,
175: // i18n[xmlReformatter.seeOtherErrs={0}\nDo you wish to see other errors?"]
176: s_stringMgr.getString("xmlReformatter.seeOtherErrs",
177: message),
178: // i18n[xmlReformatter.xmlWarning5=XML Warning]
179: s_stringMgr.getString("xmlReformatter.xmlWarning5"),
180: JOptionPane.DEFAULT_OPTION,
181: JOptionPane.WARNING_MESSAGE, null, options, options[0]);
182:
183: if (0 != ret) {
184: _showWarningMessages = false;
185: }
186:
187: }
188:
189: private static ParseRes getParseRes(String xml, int pos) {
190: if (pos >= xml.length()) {
191: return null;
192: }
193:
194: pos = moveOverWhiteSpaces(xml, pos);
195:
196: int ltIndex = xml.indexOf("<", pos);
197: int gtIndex = xml.indexOf(">", pos);
198:
199: ParseRes ret = new ParseRes();
200:
201: if (pos == ltIndex) {
202: ret.item = xml.substring(ltIndex, gtIndex + 1);
203:
204: if (xml.length() > ltIndex + 1
205: && xml.charAt(ltIndex + 1) == '/') {
206: ret.type = ParseRes.END_TAG;
207: } else if (pos < gtIndex - 1
208: && xml.charAt(gtIndex - 1) == '/') {
209: ret.type = ParseRes.CLOSED_TAG;
210: } else {
211: ret.type = ParseRes.BEGIN_TAG;
212: }
213: ret.pos = gtIndex + 1;
214: } else {
215: // check for "malformed" XML, or text that happens to contain
216: // a "<" with no corresponding ">"
217: if (ltIndex == -1) {
218: int lengthToPrint = xml.length() - pos;
219: if (lengthToPrint > 40)
220: lengthToPrint = 40;
221:
222: // i18n[xmlReformatter.malformedXmlAt=Malformed XML. No ending tag seen for text starting at:\n{0}]
223: _message = s_stringMgr.getString(
224: "xmlReformatter.malformedXmlAt", xml.substring(
225: pos, pos + lengthToPrint));
226: return null;
227: }
228:
229: ret.type = ParseRes.TEXT;
230: ret.item = xml.substring(pos, ltIndex);
231: ret.pos = ltIndex;
232: }
233:
234: return ret;
235: }
236:
237: private static int moveOverWhiteSpaces(String xml, int pos) {
238: int ret = pos;
239:
240: while (Character.isWhitespace(xml.charAt(ret))) {
241: ++ret;
242: }
243: return ret;
244:
245: }
246:
247: private static String getIndent(int depth) {
248: StringBuffer ret = new StringBuffer("");
249: for (int i = 0; i < depth; ++i) {
250: ret.append(" ");
251: }
252: return ret.toString();
253: }
254:
255: static class ParseRes {
256: public static final int BEGIN_TAG = 0;
257: public static final int END_TAG = 1;
258: public static final int CLOSED_TAG = 2;
259: public static final int TEXT = 3;
260:
261: String item;
262: int type;
263: int pos;
264: }
265: }
|