001: /*
002: * <copyright>
003: *
004: * Copyright 1997-2004 BBNT Solutions, LLC
005: * under sponsorship of the Defense Advanced Research Projects
006: * Agency (DARPA).
007: *
008: * You can redistribute this software and/or modify it under the
009: * terms of the Cougaar Open Source License as published on the
010: * Cougaar Open Source Website (www.cougaar.org).
011: *
012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023: *
024: * </copyright>
025: */
026:
027: package org.cougaar.lib.contract.lang.parser;
028:
029: import java.io.*;
030: import java.util.*;
031:
032: import org.apache.xerces.parsers.DOMParser;
033:
034: import org.cougaar.lib.contract.lang.*;
035:
036: import org.w3c.dom.*;
037: import org.xml.sax.InputSource;
038:
039: /**
040: * An XML styled <code>Op</code> parser which can be used to control
041: * a <code>TreeVisitor</code>.
042: * <p>
043: * <pre>
044: * For example,<code>
045: * <and>
046: * <or>
047: * <isNull/>
048: * <true/>
049: * </or>
050: * <false>
051: * </and></code>
052: * becomes essentially<code>
053: * (and (or (isNull (true))) (false))</code></pre>
054: * <p>
055: * @see ParenParser for "semi-Lisp" implementation
056: */
057: public class XMLParser {
058:
059: private XMLParser() {
060: }
061:
062: public static void parse(TreeVisitor visitor, Object o)
063: throws ParseException {
064: // convert to DOM Element
065: Element elem;
066: if (o instanceof Element) {
067: elem = (Element) o;
068: } else {
069: if (o instanceof String) {
070: o = new StringReader((String) o);
071: }
072: if (o instanceof Reader) {
073: try {
074: DOMParser parser = new DOMParser();
075: parser.parse(new InputSource((Reader) o));
076: Document document = parser.getDocument();
077: elem = document.getDocumentElement();
078: } catch (Exception e) {
079: throw new ParseException(
080: "Unable to tokenize XML \"Reader\":\n" + e);
081: }
082: } else if (o instanceof InputStream) {
083: try {
084: DOMParser parser = new DOMParser();
085: parser.parse(new InputSource((InputStream) o));
086: Document document = parser.getDocument();
087: elem = document.getDocumentElement();
088: } catch (Exception e) {
089: throw new ParseException(
090: "Unable to tokenize XML \"InputStream\":\n"
091: + e);
092: }
093: } else {
094: throw new ParseException("Unable to convert "
095: + ((o != null) ? o.getClass().getName()
096: : "null"));
097: }
098: if (elem == null) {
099: throw new ParseException(
100: "Unable to parse XML! Element is null.");
101: }
102: }
103:
104: visitor.initialize();
105:
106: // parse the DOM
107: parseElem(visitor, elem);
108:
109: visitor.visitEndOfTree();
110: }
111:
112: /**
113: * recursive!
114: */
115: protected static void parseElem(TreeVisitor visitor, Element elem) {
116: String nodeName = elem.getNodeName();
117: if (nodeName.equals("const")) {
118: // special introduction of constant
119: parseConstElem(visitor, elem);
120: return;
121: }
122: visitor.visitWord(nodeName);
123: // add child nodes
124: NodeList nlist = elem.getChildNodes();
125: int nlength = nlist.getLength();
126: Node subNode = null;
127: for (int i = 0;; i++) {
128: if (i >= nlength) {
129: if (i == 1) {
130: // leaf
131: String leafVal = subNode.getNodeValue();
132: if (leafVal != null) {
133: leafVal = leafVal.trim();
134: if (leafVal.length() > 0) {
135: // single string argument, e.g. "<equals>foo</equals>",
136: // becomes "<equals><const value=\"foo\"/></equals>"
137: visitor.visitConstant(leafVal);
138: }
139: }
140: }
141: break;
142: }
143: subNode = (Node) nlist.item(i);
144: if (subNode.getNodeType() == Node.ELEMENT_NODE) {
145: // recurse!
146: parseElem(visitor, (Element) subNode);
147: }
148: }
149: // add tail paren
150: visitor.visitEnd();
151: }
152:
153: /**
154: * Special introduction of constant -- expecting single value.
155: */
156: protected static void parseConstElem(TreeVisitor visitor,
157: Element elem) {
158: // find optional attributes "type" and "value"
159: String constType = null;
160: String constVal = null;
161: NamedNodeMap attribs = elem.getAttributes();
162: if (attribs != null) {
163: int nAttribs = attribs.getLength();
164: for (int i = 0; i < nAttribs; i++) {
165: Node aNode = attribs.item(i);
166: String aName = aNode.getNodeName();
167: // examine attribute name
168: switch (aName.length()) {
169: case 1: {
170: char ch = aName.charAt(0);
171: if (ch == 't') {
172: // found type
173: constType = aNode.getNodeValue();
174: } else if (ch == 'v') {
175: // found value
176: constVal = aNode.getNodeValue();
177: }
178: break;
179: }
180: case 4:
181: if (aName.equalsIgnoreCase("type")) {
182: // found type
183: constType = aNode.getNodeValue();
184: }
185: break;
186: case 5:
187: if (aName.equalsIgnoreCase("value")) {
188: // found value
189: constVal = aNode.getNodeValue();
190: }
191: break;
192: case 0: /* fall-through */
193: case 2: /* fall-through */
194: case 3: /* fall-through */
195: default:
196: break;
197: }
198: }
199: }
200: // find the constant value
201: if (constVal == null) {
202: NodeList nlist = elem.getChildNodes();
203: if (nlist.getLength() == 1) {
204: Node subNode = (Node) nlist.item(0);
205: if (subNode.getNodeType() != Node.ELEMENT_NODE) {
206: String nval = subNode.getNodeValue();
207: if (nval != null) {
208: nval = nval.trim();
209: if (nval.length() > 0) {
210: // found the value
211: constVal = nval;
212: }
213: }
214: }
215: }
216: // check if the constant value was set
217: if (constVal == null) {
218: throw new IllegalArgumentException(
219: "Invalid \"const\" value! XML Element: "
220: + elem);
221: }
222: }
223: // append the constant
224: if (constType == null) {
225: // string
226: visitor.visitConstant(constVal);
227: } else {
228: // use given type
229: visitor.visitConstant(constType, constVal);
230: }
231: }
232:
233: public static StringVisitor getStringVisitor() {
234: return new XMLStringVisitor();
235: }
236:
237: public static XMLBuilderVisitor getXMLVisitor(Document doc) {
238: return new XMLBuilderVisitor(doc);
239: }
240:
241: public static String toString(VisitTokenizer visTokenizer) {
242: TreeVisitor visitor = getStringVisitor();
243: VisitReplayer.replay(visitor, visTokenizer);
244: return visitor.toString();
245: }
246:
247: public static void main(String[] args) {
248: String input = "<and><a/><const value=\"x\"/> "
249: + "<c> <const type=\"t\" value=\"v\"/> <e/></c></and>";
250: System.out.print("Given: " + input + "\nParsed: ");
251: try {
252: TreeVisitor strVis = XMLParser.getStringVisitor();
253: XMLParser.parse(strVis, input);
254: System.out.println(strVis.toString());
255: } catch (Exception e) {
256: System.out.println("\n######\n" + e);
257: e.printStackTrace();
258: }
259: }
260: }
|