blob: 2eaff8b7dd0569dc2173de8462eb60343a0a50ce [file] [log] [blame]
Joachim Bingel5c93f902013-11-19 14:49:04 +00001package de.ids_mannheim.korap.query.serialize;
2
3import java.util.ArrayList;
Joachim Bingeld5161a12014-01-08 11:15:49 +00004import java.util.Arrays;
Joachim Bingel5c93f902013-11-19 14:49:04 +00005import java.util.LinkedHashMap;
6import java.util.LinkedList;
7import java.util.List;
8import java.util.Map;
Joachim Bingel5c93f902013-11-19 14:49:04 +00009
10import org.antlr.runtime.ANTLRStringStream;
11import org.antlr.runtime.RecognitionException;
12import org.antlr.runtime.tree.Tree;
Joachim Bingelb5f7bf02014-01-07 16:36:54 +000013import org.antlr.v4.runtime.tree.ParseTree;
14import org.slf4j.Logger;
15import org.slf4j.LoggerFactory;
Joachim Bingel5c93f902013-11-19 14:49:04 +000016
17import de.ids_mannheim.korap.query.cosmas2.c2psLexer;
18import de.ids_mannheim.korap.query.cosmas2.c2psParser;
Joachim Bingelb5f7bf02014-01-07 16:36:54 +000019import de.ids_mannheim.korap.query.serialize.AbstractSyntaxTree;
Joachim Bingele98d0882014-01-21 12:58:54 +000020import de.ids_mannheim.korap.query.serialize.util.CosmasCondition;
Joachim Bingel87480d02014-01-17 14:07:46 +000021import de.ids_mannheim.korap.util.QueryException;
Joachim Bingel5c93f902013-11-19 14:49:04 +000022
23/**
24 * Map representation of CosmasII syntax tree as returned by ANTLR
25 * @author joachim
26 *
27 */
28public class CosmasTree extends AbstractSyntaxTree {
29
Joachim Bingelb5f7bf02014-01-07 16:36:54 +000030 Logger log = LoggerFactory.getLogger(CosmasTree.class);
31
Joachim Bingel5c93f902013-11-19 14:49:04 +000032 private static c2psParser cosmasParser;
33 /*
34 * Following collections have the following functions:
35 * - the request is a map with two keys (meta/query): {meta=[], query=[]}
36 * - the query is a list of token group maps: {meta=[], query=[tg1=[], tg2=[]]}
37 * - each token group is a list of tokens: {meta=[], query=[tg1=[t1_1, t1_2], tg2=[t2_1, t2_2, t2_3]]}
38 * - each token corresponds to a single 'fields' linked list {meta=[], query=[tg1=[t1_1=[], t1_2=[]], ... ]}
39 * - each fields list contains a logical operator and 'field maps' defining attributes and values
40 * {meta=[], query=[tg1=[t1_1=[[disj, {base=foo}, {base=bar}]], t1_2=[]], ... ]}
41 */
42 String query;
43 LinkedHashMap<String,Object> requestMap = new LinkedHashMap<String,Object>();
Joachim Bingelb5f7bf02014-01-07 16:36:54 +000044 /**
45 * Keeps track of active object.
46 */
47 LinkedList<LinkedHashMap<String,Object>> objectStack = new LinkedList<LinkedHashMap<String,Object>>();
48 /**
Joachim Bingel5c93f902013-11-19 14:49:04 +000049 * Makes it possible to store several distantTokenGroups
50 */
51 LinkedList<ArrayList<List<Object>>> distantTokensStack = new LinkedList<ArrayList<List<Object>>>();
52 /**
53 * Field for repetition query (Kleene + or * operations, or min/max queries: {2,4}
54 */
55 String repetition = "";
Joachim Bingel5c93f902013-11-19 14:49:04 +000056 /**
57 * Keeps track of open node categories
58 */
59 LinkedList<String> openNodeCats = new LinkedList<String>();
60 /**
61 * Global control structure for fieldGroups, keeps track of open fieldGroups.
62 */
63 LinkedList<ArrayList<Object>> openFieldGroups = new LinkedList<ArrayList<Object>>();
64 /**
Joachim Bingelb5f7bf02014-01-07 16:36:54 +000065 * Keeps track of how many objects there are to pop after every recursion of {@link #processNode(ParseTree)}
Joachim Bingel5c93f902013-11-19 14:49:04 +000066 */
Joachim Bingelb5f7bf02014-01-07 16:36:54 +000067 LinkedList<Integer> objectsToPop = new LinkedList<Integer>();
Joachim Bingel5c93f902013-11-19 14:49:04 +000068 /**
69 * Flag that indicates whether token fields or meta fields are currently being processed
70 */
71 boolean inMeta = false;
72 boolean negate = false;
73
74 Tree cosmasTree;
75
76 LinkedHashMap<String,Object> treeMap = new LinkedHashMap<String,Object>();
77 /**
78 * Keeps track of all visited nodes in a tree
79 */
80 List<Tree> visited = new ArrayList<Tree>();
Joachim Bingelb5f7bf02014-01-07 16:36:54 +000081
82 Integer stackedObjects = 0;
83
84 private static boolean debug = false;
Joachim Bingeld5161a12014-01-08 11:15:49 +000085 /**
86 * A list of node categories that can be sequenced (i.e. which can be in a sequence with any number of other nodes in this list)
87 */
88 private final List<String> sequentiableCats = Arrays.asList(new String[] {"OPWF", "OPLEM", "OPMORPH", "OPBEG", "OPEND", "OPIN"});
89 /**
90 * Keeps track of sequenced nodes, i.e. nodes that implicitly govern a sequence, as in (C2PQ (OPWF der) (OPWF Mann)).
91 * This is necessary in order to know when to take the sequence off the object stack, as the sequence is introduced by the
92 * first child but cannot be closed after this first child in order not to lose its siblings
93 */
94 private LinkedList<Tree> sequencedNodes = new LinkedList<Tree>();
Joachim Bingeleecc7652014-01-11 17:21:07 +000095
96 private boolean hasSequentiableSiblings;
97
Joachim Bingeleecc7652014-01-11 17:21:07 +000098 /**
99 * Keeps track of operands lists that are to be serialised in an inverted
100 * order (e.g. the IN() operator) compared to their AST representation.
101 */
Joachim Bingelcc1dc242014-01-15 09:32:38 +0000102 private LinkedList<ArrayList<Object>> invertedOperandsLists = new LinkedList<ArrayList<Object>>();
Joachim Bingele98d0882014-01-21 12:58:54 +0000103
104 private LinkedList<ArrayList<ArrayList<Object>>> distributedOperandsLists = new LinkedList<ArrayList<ArrayList<Object>>>();
Joachim Bingel5c93f902013-11-19 14:49:04 +0000105 /**
106 *
107 * @param tree The syntax tree as returned by ANTLR
108 * @param parser The ANTLR parser instance that generated the parse tree
Joachim Bingel87480d02014-01-17 14:07:46 +0000109 * @throws QueryException
Joachim Bingel5c93f902013-11-19 14:49:04 +0000110 */
Joachim Bingel87480d02014-01-17 14:07:46 +0000111 public CosmasTree(String query) throws QueryException {
Joachim Bingel5c93f902013-11-19 14:49:04 +0000112 this.query = query;
113 process(query);
Joachim Bingelb5f7bf02014-01-07 16:36:54 +0000114 System.out.println(requestMap.get("query"));
Joachim Bingel5c93f902013-11-19 14:49:04 +0000115 }
116
117 @Override
118 public Map<String, Object> getRequestMap() {
119 return this.requestMap;
120 }
121
Joachim Bingelb5f7bf02014-01-07 16:36:54 +0000122 private void prepareContext() {
123 LinkedHashMap<String,Object> context = new LinkedHashMap<String,Object>();
124 LinkedHashMap<String,Object> operands = new LinkedHashMap<String,Object>();
125 LinkedHashMap<String,Object> relation = new LinkedHashMap<String,Object>();
126 LinkedHashMap<String,Object> classMap = new LinkedHashMap<String,Object>();
127
128 operands.put("@id", "korap:operands");
129 operands.put("@container", "@list");
130
131 relation.put("@id", "korap:relation");
132 relation.put("@type", "korap:relation#types");
133
134 classMap.put("@id", "korap:class");
135 classMap.put("@type", "xsd:integer");
136
137 context.put("korap", "http://korap.ids-mannheim.de/ns/query");
138 context.put("@language", "de");
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000139 context.put("@operands", operands);
140 context.put("@relation", relation);
Joachim Bingelb5f7bf02014-01-07 16:36:54 +0000141 context.put("class", classMap);
142 context.put("query", "korap:query");
143 context.put("filter", "korap:filter");
144 context.put("meta", "korap:meta");
145
146 requestMap.put("@context", context);
147 }
148
Joachim Bingel5c93f902013-11-19 14:49:04 +0000149 @Override
Joachim Bingel87480d02014-01-17 14:07:46 +0000150 public void process(String query) throws QueryException {
151 Tree tree = null;
152 try {
153 tree = parseCosmasQuery(query);
154 } catch (RecognitionException e) {
155 throw new QueryException("Your query could not be processed. Please make sure it is well-formed.");
156 } catch (NullPointerException e) {
157 throw new QueryException("Your query could not be processed. Please make sure it is well-formed.");
158 }
159
Joachim Bingel5c93f902013-11-19 14:49:04 +0000160 System.out.println("Processing Cosmas");
Joachim Bingelb5f7bf02014-01-07 16:36:54 +0000161 prepareContext();
Joachim Bingel5c93f902013-11-19 14:49:04 +0000162 processNode(tree);
163 }
164
165 private void processNode(Tree node) {
166
167 // Top-down processing
168 if (visited.contains(node)) return;
169 else visited.add(node);
170
171
Joachim Bingelb5f7bf02014-01-07 16:36:54 +0000172 String nodeCat = QueryUtils.getNodeCat(node);
Joachim Bingel5c93f902013-11-19 14:49:04 +0000173 openNodeCats.push(nodeCat);
174
Joachim Bingelb5f7bf02014-01-07 16:36:54 +0000175 stackedObjects = 0;
Joachim Bingel5c93f902013-11-19 14:49:04 +0000176
Joachim Bingelb5f7bf02014-01-07 16:36:54 +0000177 if (debug) {
Joachim Bingelb5f7bf02014-01-07 16:36:54 +0000178 System.err.println(" "+objectStack);
179 System.out.println(openNodeCats);
180 }
Joachim Bingel5c93f902013-11-19 14:49:04 +0000181
Joachim Bingel5c93f902013-11-19 14:49:04 +0000182
183 /* ***************************************
184 * Processing individual node categories *
185 *****************************************/
Joachim Bingeld5161a12014-01-08 11:15:49 +0000186
187
188 // Check for potential implicit sequences as in (C2PQ (OPWF der) (OPWF Mann)). The sequence is introduced
189 // by the first child if it (and its siblings) is sequentiable.
190 if (sequentiableCats.contains(nodeCat)) {
191 // for each node, check if parent has more than one child (-> could be implicit sequence)
Joachim Bingeleecc7652014-01-11 17:21:07 +0000192 Tree parent = node.getParent();
193 if (parent.getChildCount()>1) {
Joachim Bingeld5161a12014-01-08 11:15:49 +0000194 // if node is first child of parent...
Joachim Bingeleecc7652014-01-11 17:21:07 +0000195 if (node == parent.getChild(0)) {
196 hasSequentiableSiblings = false;
197 for (int i=1; i<parent.getChildCount() ;i++) {
198 if (sequentiableCats.contains(QueryUtils.getNodeCat(parent.getChild(i)))) {
199 hasSequentiableSiblings = true;
200 }
Joachim Bingeld5161a12014-01-08 11:15:49 +0000201 }
Joachim Bingeleecc7652014-01-11 17:21:07 +0000202 if (hasSequentiableSiblings) {
203 // Step I: create sequence
204 LinkedHashMap<String, Object> sequence = new LinkedHashMap<String, Object>();
205 sequence.put("@type", "korap:sequence");
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000206 sequence.put("@operands", new ArrayList<Object>());
Joachim Bingeleecc7652014-01-11 17:21:07 +0000207 // push sequence on object stack but don't increment stackedObjects counter since
208 // we've got to wait until the parent node is processed - therefore, add the parent
209 // to the sequencedNodes list and remove the sequence from the stack when the parent
210 // has been processed
211 objectStack.push(sequence);
212 sequencedNodes.push(parent);
213 // Step II: decide where to put sequence
Joachim Bingelcc1dc242014-01-15 09:32:38 +0000214 putIntoSuperObject(sequence, 1);
Joachim Bingeleecc7652014-01-11 17:21:07 +0000215 }
Joachim Bingeld5161a12014-01-08 11:15:49 +0000216 }
217 }
218 }
219
Joachim Bingel5c93f902013-11-19 14:49:04 +0000220 // Nodes introducing tokens. Process all in the same manner, except for the fieldMap entry
Joachim Bingelffd65e32014-01-22 14:22:57 +0000221 if (nodeCat.equals("OPWF") || nodeCat.equals("OPLEM")) {
Joachim Bingel5c93f902013-11-19 14:49:04 +0000222
Joachim Bingelb5f7bf02014-01-07 16:36:54 +0000223 //Step I: get info
224 LinkedHashMap<String, Object> token = new LinkedHashMap<String, Object>();
225 token.put("@type", "korap:token");
Joachim Bingelb5f7bf02014-01-07 16:36:54 +0000226 objectStack.push(token);
227 stackedObjects++;
Joachim Bingelb5f7bf02014-01-07 16:36:54 +0000228 LinkedHashMap<String, Object> fieldMap = new LinkedHashMap<String, Object>();
229 token.put("@value", fieldMap);
Joachim Bingel5c93f902013-11-19 14:49:04 +0000230
Joachim Bingelb5f7bf02014-01-07 16:36:54 +0000231 fieldMap.put("@type", "korap:term");
Joachim Bingel5c93f902013-11-19 14:49:04 +0000232 // make category-specific fieldMap entry
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000233 String attr = nodeCat.equals("OPWF") ? "orth" : "lemma";
234 String value = node.getChild(0).toStringTree().replaceAll("\"", "");
Joachim Bingelb5f7bf02014-01-07 16:36:54 +0000235 fieldMap.put("@value", value);
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000236 fieldMap.put("@attr", attr);
Joachim Bingelffd65e32014-01-22 14:22:57 +0000237
Joachim Bingel5c93f902013-11-19 14:49:04 +0000238 // negate field (see above)
239 if (negate) {
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000240 fieldMap.put("@relation", "!=");
Joachim Bingelb5f7bf02014-01-07 16:36:54 +0000241 } else {
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000242 fieldMap.put("@relation", "=");
Joachim Bingel5c93f902013-11-19 14:49:04 +0000243 }
Joachim Bingelb5f7bf02014-01-07 16:36:54 +0000244 //Step II: decide where to put
Joachim Bingelcc1dc242014-01-15 09:32:38 +0000245 putIntoSuperObject(token, 1);
Joachim Bingelb5f7bf02014-01-07 16:36:54 +0000246 }
247
Joachim Bingelffd65e32014-01-22 14:22:57 +0000248 if (nodeCat.equals("OPMORPH")) {
249 //Step I: get info
250 LinkedHashMap<String, Object> token = new LinkedHashMap<String, Object>();
251 token.put("@type", "korap:token");
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000252 LinkedHashMap<String, Object> fieldMap = new LinkedHashMap<String, Object>();
253 token.put("@value", fieldMap);
Joachim Bingelffd65e32014-01-22 14:22:57 +0000254
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000255 fieldMap.put("@type", "korap:term");
256// fieldMap.put("@value", "morph:"+node.getChild(0).toString().replace(" ", "_"));
257 fieldMap.put("@value", node.getChild(0).toString().replace(" ", "_"));
258 // make category-specific fieldMap entry
259 // negate field (see above)
260 if (negate) {
261 fieldMap.put("@relation", "!=");
Joachim Bingelffd65e32014-01-22 14:22:57 +0000262 } else {
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000263 fieldMap.put("@relation", "=");
Joachim Bingelffd65e32014-01-22 14:22:57 +0000264 }
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000265// List<String> morphValues = QueryUtils.parseMorph(node.getChild(0).toStringTree());
266// System.err.println(morphValues);
267// if (morphValues.size() == 1) {
268// LinkedHashMap<String, Object> fieldMap = new LinkedHashMap<String, Object>();
269// token.put("@value", fieldMap);
270//
271// fieldMap.put("@type", "korap:term");
272// fieldMap.put("@value", morphValues.get(0));
273// // make category-specific fieldMap entry
274// // negate field (see above)
275// if (negate) {
276// fieldMap.put("@relation", "!=");
277// } else {
278// fieldMap.put("@relation", "=");
279// }
280// } else {
281// LinkedHashMap<String, Object> conjGroup = new LinkedHashMap<String, Object>();
282// token.put("@value", conjGroup);
283// ArrayList<Object> conjOperands = new ArrayList<Object>();
284// conjGroup.put("@type", "korap:group");
285// conjGroup.put("@relation", "and");
286// conjGroup.put("@operands", conjOperands);
287// for (String value : morphValues) {
288// LinkedHashMap<String, Object> fieldMap = new LinkedHashMap<String, Object>();
289// token.put("@value", fieldMap);
290//
291// fieldMap.put("@type", "korap:term");
292// fieldMap.put("@value", value);
293// // make category-specific fieldMap entry
294// // negate field (see above)
295// if (negate) {
296// fieldMap.put("@relation", "!=");
297// } else {
298// fieldMap.put("@relation", "=");
299// }
300// }
301// }
Joachim Bingelffd65e32014-01-22 14:22:57 +0000302
303
304 //Step II: decide where to put
305 putIntoSuperObject(token, 0);
306 }
307
Joachim Bingeleecc7652014-01-11 17:21:07 +0000308 if (nodeCat.equals("OPELEM")) {
309 // Step I: create element
310 LinkedHashMap<String, Object> elem = new LinkedHashMap<String, Object>();
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000311 elem.put("@type", "korap:span");
Joachim Bingeleecc7652014-01-11 17:21:07 +0000312 elem.put("@value", node.getChild(0).getChild(0).toStringTree().toLowerCase());
313 //Step II: decide where to put
Joachim Bingelcc1dc242014-01-15 09:32:38 +0000314 putIntoSuperObject(elem);
315 }
Joachim Bingeleecc7652014-01-11 17:21:07 +0000316
Joachim Bingelb5f7bf02014-01-07 16:36:54 +0000317 if (nodeCat.equals("OPLABEL")) {
318 // Step I: create element
319 LinkedHashMap<String, Object> elem = new LinkedHashMap<String, Object>();
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000320 elem.put("@type", "korap:span");
Joachim Bingelb5f7bf02014-01-07 16:36:54 +0000321 elem.put("@value", node.getChild(0).toStringTree().replaceAll("<|>", ""));
322 //Step II: decide where to put
Joachim Bingelcc1dc242014-01-15 09:32:38 +0000323 putIntoSuperObject(elem);
Joachim Bingel5c93f902013-11-19 14:49:04 +0000324 }
325
Joachim Bingel3a9f7932014-01-07 17:11:31 +0000326 if (nodeCat.equals("OPOR") || nodeCat.equals("OPAND") || nodeCat.equals("OPNOT")) {
Joachim Bingelb5f7bf02014-01-07 16:36:54 +0000327 // Step I: create group
328 LinkedHashMap<String, Object> disjunction = new LinkedHashMap<String, Object>();
329 disjunction.put("@type", "korap:group");
Joachim Bingel3a9f7932014-01-07 17:11:31 +0000330 String relation = "or";
331 if (nodeCat.equals("OPAND")) relation = "and";
332 if (nodeCat.equals("OPNOT")) relation = "not";
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000333 disjunction.put("@relation", relation);
334 disjunction.put("@operands", new ArrayList<Object>());
Joachim Bingelb5f7bf02014-01-07 16:36:54 +0000335 objectStack.push(disjunction);
336 stackedObjects++;
Joachim Bingelb5f7bf02014-01-07 16:36:54 +0000337 // Step II: decide where to put
Joachim Bingelcc1dc242014-01-15 09:32:38 +0000338 putIntoSuperObject(disjunction, 1);
Joachim Bingel5c93f902013-11-19 14:49:04 +0000339 }
340
341 if (nodeCat.equals("OPPROX")) {
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000342 //TODO direction "both": wrap in "or" group with operands once flipped, once not
Joachim Bingelb5f7bf02014-01-07 16:36:54 +0000343 // collect info
Joachim Bingel5c93f902013-11-19 14:49:04 +0000344 Tree prox_opts = node.getChild(0);
345 Tree typ = prox_opts.getChild(0);
Joachim Bingel5c93f902013-11-19 14:49:04 +0000346 Tree dist_list = prox_opts.getChild(1);
Joachim Bingel89cceac2014-01-08 15:51:08 +0000347 // Step I: create group
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000348 LinkedHashMap<String, Object> proxSequence = new LinkedHashMap<String, Object>();
349 proxSequence.put("@type", "korap:sequence");
350 objectStack.push(proxSequence);
Joachim Bingelb5f7bf02014-01-07 16:36:54 +0000351 stackedObjects++;
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000352// if (openNodeCats.get(1).equals("OPALL")) proxSequence.put("match", "all");
353// else if (openNodeCats.get(1).equals("OPNHIT")) proxSequence.put("match", "between");
354// else proxSequence.put("match", "operands");
Joachim Bingel89cceac2014-01-08 15:51:08 +0000355 ArrayList<Object> constraints = new ArrayList<Object>();
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000356 boolean exclusion = ! typ.getChild(0).toStringTree().equals("PROX");
357
358 String inOrder = "true";
359 proxSequence.put("@inOrder", inOrder);
360 proxSequence.put("@constraints", constraints);
361
Joachim Bingel3f0850c2014-01-17 16:50:10 +0000362 ArrayList<Object> operands = new ArrayList<Object>();
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000363 proxSequence.put("@operands", operands);
Joachim Bingel89cceac2014-01-08 15:51:08 +0000364
365 // if only one dist_info, put directly into constraints
366 if (dist_list.getChildCount()==1) {
367 String direction = dist_list.getChild(0).getChild(0).getChild(0).toStringTree().toLowerCase();
368 String min = dist_list.getChild(0).getChild(1).getChild(0).toStringTree();
369 String max = dist_list.getChild(0).getChild(1).getChild(1).toStringTree();
370 String meas = dist_list.getChild(0).getChild(2).getChild(0).toStringTree();
371 if (min.equals("VAL0")) {
Joachim Bingel87480d02014-01-17 14:07:46 +0000372 min="0";
Joachim Bingel89cceac2014-01-08 15:51:08 +0000373 }
Joachim Bingel3f0850c2014-01-17 16:50:10 +0000374 if (direction.equals("minus")) {
375 direction = "plus";
376 invertedOperandsLists.add(operands);
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000377 } else if (direction.equals("both")) {
378 inOrder="false";
Joachim Bingel3f0850c2014-01-17 16:50:10 +0000379 }
Joachim Bingel89cceac2014-01-08 15:51:08 +0000380 LinkedHashMap<String, Object> distance = new LinkedHashMap<String, Object>();
381 distance.put("@type", "korap:distance");
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000382 distance.put("@measure", meas);
383 distance.put("@min", Integer.parseInt(min));
384 distance.put("@max", Integer.parseInt(max));
385 if (exclusion) {
386 distance.put("@exclude", exclusion);
387 }
Joachim Bingel89cceac2014-01-08 15:51:08 +0000388 constraints.add(distance);
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000389 proxSequence.put("@inOrder", inOrder);
Joachim Bingel89cceac2014-01-08 15:51:08 +0000390 }
391 // otherwise, create group and add info there
392 else {
393 LinkedHashMap<String, Object> distanceGroup = new LinkedHashMap<String, Object>();
394 ArrayList<Object> groupOperands = new ArrayList<Object>();
395 distanceGroup.put("@type", "korap:group");
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000396 distanceGroup.put("@relation", "and");
397 distanceGroup.put("@operands", groupOperands);
Joachim Bingel89cceac2014-01-08 15:51:08 +0000398 constraints.add(distanceGroup);
399 for (int i=0; i<dist_list.getChildCount(); i++) {
400 String direction = dist_list.getChild(i).getChild(0).getChild(0).toStringTree().toLowerCase();
401 String min = dist_list.getChild(i).getChild(1).getChild(0).toStringTree();
402 String max = dist_list.getChild(i).getChild(1).getChild(1).toStringTree();
403 String meas = dist_list.getChild(i).getChild(2).getChild(0).toStringTree();
404 if (min.equals("VAL0")) {
405 min=max;
406 }
407 LinkedHashMap<String, Object> distance = new LinkedHashMap<String, Object>();
408 distance.put("@type", "korap:distance");
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000409 distance.put("@measure", meas);
410 distance.put("@min", min);
411 distance.put("@max", max);
412 if (exclusion) {
413 distance.put("@exclude", exclusion);
414 }
Joachim Bingel89cceac2014-01-08 15:51:08 +0000415 groupOperands.add(distance);
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000416 if (direction.equals("plus")) {
417 inOrder="true";
418 } else if (direction.equals("minus")) {
419 inOrder="true";
420 invertedOperandsLists.add(operands);
421 }
Joachim Bingel89cceac2014-01-08 15:51:08 +0000422 }
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000423 proxSequence.put("@inOrder", inOrder);
424
Joachim Bingel89cceac2014-01-08 15:51:08 +0000425 }
Joachim Bingelb5f7bf02014-01-07 16:36:54 +0000426 // Step II: decide where to put
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000427 putIntoSuperObject(proxSequence, 1);
Joachim Bingel5c93f902013-11-19 14:49:04 +0000428 }
429
Joachim Bingeld5161a12014-01-08 11:15:49 +0000430 // inlcusion or overlap
431 if (nodeCat.equals("OPIN") || nodeCat.equals("OPOV")) {
Joachim Bingelb5f7bf02014-01-07 16:36:54 +0000432 // Step I: create group
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000433 LinkedHashMap<String, Object> submatchgroup = new LinkedHashMap<String, Object>();
434 submatchgroup.put("@type", "korap:group");
435 submatchgroup.put("@relation", "submatch");
436 submatchgroup.put("@classRef", "1");
Joachim Bingeleecc7652014-01-11 17:21:07 +0000437
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000438 ArrayList<Object> submatchoperands = new ArrayList<Object>();
Joachim Bingeleecc7652014-01-11 17:21:07 +0000439 LinkedHashMap<String, Object> posgroup = new LinkedHashMap<String, Object>();
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000440 submatchgroup.put("@operands", submatchoperands);
441 submatchoperands.add(posgroup);
Joachim Bingeleecc7652014-01-11 17:21:07 +0000442 posgroup.put("@type", "korap:group");
Joachim Bingel84e33df2014-01-31 14:02:46 +0000443// String relation = nodeCat.equals("OPIN") ? "position" : "overlaps";
444 posgroup.put("@relation", "position");
Joachim Bingeleecc7652014-01-11 17:21:07 +0000445
Joachim Bingel87480d02014-01-17 14:07:46 +0000446 if (nodeCat.equals("OPIN")) {
447 parseOPINOptions(node, posgroup);
Joachim Bingelcc1dc242014-01-15 09:32:38 +0000448 } else {
Joachim Bingel87480d02014-01-17 14:07:46 +0000449 parseOPOVOptions(node, posgroup);
Joachim Bingeld5161a12014-01-08 11:15:49 +0000450 }
Joachim Bingel87480d02014-01-17 14:07:46 +0000451
452
Joachim Bingelcc1dc242014-01-15 09:32:38 +0000453 ArrayList<Object> posoperands = new ArrayList<Object>();
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000454 posgroup.put("@operands", posoperands);
Joachim Bingeleecc7652014-01-11 17:21:07 +0000455 objectStack.push(posgroup);
Joachim Bingelcc1dc242014-01-15 09:32:38 +0000456 // mark this an inverted list
457 invertedOperandsLists.push(posoperands);
Joachim Bingeld5161a12014-01-08 11:15:49 +0000458 stackedObjects++;
459
460 // Step II: decide where to put
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000461 putIntoSuperObject(submatchgroup, 1);
Joachim Bingeld5161a12014-01-08 11:15:49 +0000462 }
463
Joachim Bingel87480d02014-01-17 14:07:46 +0000464
465 // Wrap the first argument of an #IN operator in a class group
Joachim Bingelcc1dc242014-01-15 09:32:38 +0000466 if (nodeCat.equals("ARG1") && (openNodeCats.get(1).equals("OPIN") || openNodeCats.get(1).equals("OPOV"))) {
467 // Step I: create group
468 LinkedHashMap<String, Object> classGroup = new LinkedHashMap<String, Object>();
469 classGroup.put("@type", "korap:group");
470 classGroup.put("class", "1");
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000471 classGroup.put("@operands", new ArrayList<Object>());
Joachim Bingelcc1dc242014-01-15 09:32:38 +0000472 objectStack.push(classGroup);
473 stackedObjects++;
474 // Step II: decide where to put
475 putIntoSuperObject(classGroup, 1);
476 }
477
478
Joachim Bingel89cceac2014-01-08 15:51:08 +0000479 if (nodeCat.equals("OPALL") || nodeCat.equals("OPNHIT")) {
Joachim Bingel87480d02014-01-17 14:07:46 +0000480// proxGroupMatching = nodeCat.equals("OPALL") ? "all" : "exlcude";
Joachim Bingel89cceac2014-01-08 15:51:08 +0000481 }
482
Joachim Bingeld5161a12014-01-08 11:15:49 +0000483 if (nodeCat.equals("OPEND") || nodeCat.equals("OPBEG")) {
484 // Step I: create group
Joachim Bingel3f0850c2014-01-17 16:50:10 +0000485 LinkedHashMap<String, Object> beggroup = new LinkedHashMap<String, Object>();
486 beggroup.put("@type", "korap:group");
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000487 beggroup.put("@relation", "submatch");
488 ArrayList<Integer> spanRef = new ArrayList<Integer>();
489 if (nodeCat.equals("OPBEG")) {
490 spanRef.add(0); spanRef.add(1);
491 } else {
492 spanRef.add(-1); spanRef.add(1);
493 }
494 beggroup.put("@spanRef", spanRef);
495 beggroup.put("@operands", new ArrayList<Object>());
Joachim Bingel3f0850c2014-01-17 16:50:10 +0000496 objectStack.push(beggroup);
Joachim Bingelb5f7bf02014-01-07 16:36:54 +0000497 stackedObjects++;
498
499 // Step II: decide where to put
Joachim Bingel3f0850c2014-01-17 16:50:10 +0000500 putIntoSuperObject(beggroup, 1);
Joachim Bingelb5f7bf02014-01-07 16:36:54 +0000501 }
Joachim Bingel5c93f902013-11-19 14:49:04 +0000502
Joachim Bingeleecc7652014-01-11 17:21:07 +0000503 if (nodeCat.equals("OPBED")) {
504 // Step I: create group
Joachim Bingeleecc7652014-01-11 17:21:07 +0000505 int optsChild = node.getChildCount()-1;
Joachim Bingele98d0882014-01-21 12:58:54 +0000506 Tree conditions = node.getChild(optsChild).getChild(0);
507 // Distinguish two cases. Normal case: query has just one condition, like #BED(XY, sa) ...
Joachim Bingel3f0850c2014-01-17 16:50:10 +0000508 if (conditions.getChildCount()==1) {
509 LinkedHashMap<String, Object> posgroup = new LinkedHashMap<String, Object>();
510 posgroup.put("@type", "korap:group");
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000511 posgroup.put("@relation", "position");
Joachim Bingele98d0882014-01-21 12:58:54 +0000512 CosmasCondition c = new CosmasCondition(conditions.getChild(0));
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000513 posgroup.put("@position", c.position);
514 if (c.negated) posgroup.put("@relation", "!=");
Joachim Bingele98d0882014-01-21 12:58:54 +0000515 ArrayList<Object> operands = new ArrayList<Object>();
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000516 posgroup.put("@operands", operands);
Joachim Bingele98d0882014-01-21 12:58:54 +0000517 LinkedHashMap<String, Object> bedElem = new LinkedHashMap<String, Object>();
518 operands.add(bedElem);
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000519 bedElem.put("@type", "korap:span");
Joachim Bingele98d0882014-01-21 12:58:54 +0000520 bedElem.put("@value", c.elem);
Joachim Bingel3f0850c2014-01-17 16:50:10 +0000521 objectStack.push(posgroup);
522 stackedObjects++;
523 // Step II: decide where to put
524 putIntoSuperObject(posgroup, 1);
Joachim Bingele98d0882014-01-21 12:58:54 +0000525 // ... or the query has several conditions specified, like #BED(XY, sa,-pa). In that case,
526 // create an 'and' group and embed the position groups in its operands
Joachim Bingel3f0850c2014-01-17 16:50:10 +0000527 } else {
528 // node has several conditions (like 'sa, -pa')
529 // -> create 'and' group and embed all position groups there
530 LinkedHashMap<String, Object> conjunct = new LinkedHashMap<String, Object>();
531 conjunct.put("@type", "korap:group");
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000532 conjunct.put("@relation", "and");
Joachim Bingel3f0850c2014-01-17 16:50:10 +0000533 ArrayList<Object> operands = new ArrayList<Object>();
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000534 conjunct.put("@operands", operands);
Joachim Bingele98d0882014-01-21 12:58:54 +0000535 ArrayList<ArrayList<Object>> distributedOperands = new ArrayList<ArrayList<Object>>();
536
Joachim Bingel3f0850c2014-01-17 16:50:10 +0000537 for (int i=0; i<conditions.getChildCount(); i++) {
Joachim Bingele98d0882014-01-21 12:58:54 +0000538 // for each condition, create a position group. problem: how to get argument into every operands list?
539 // -> use distributedOperandsLists
540 LinkedHashMap<String, Object> posGroup = new LinkedHashMap<String, Object>();
541 operands.add(posGroup);
542
543 CosmasCondition c = new CosmasCondition(conditions.getChild(i));
544 posGroup.put("@type", "korap:group");
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000545 posGroup.put("@relation", "position");
546 posGroup.put("@position", c.position);
547 if (c.negated) posGroup.put("@exclude", "true");
Joachim Bingele98d0882014-01-21 12:58:54 +0000548 ArrayList<Object> posOperands = new ArrayList<Object>();
549 distributedOperands.add(posOperands);
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000550 posGroup.put("@operands", posOperands);
Joachim Bingele98d0882014-01-21 12:58:54 +0000551 LinkedHashMap<String, Object> bedElem = new LinkedHashMap<String, Object>();
552 posOperands.add(bedElem);
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000553 bedElem.put("@type", "korap:span");
Joachim Bingele98d0882014-01-21 12:58:54 +0000554 bedElem.put("@value", c.elem);
555
556
Joachim Bingel3f0850c2014-01-17 16:50:10 +0000557 }
Joachim Bingele98d0882014-01-21 12:58:54 +0000558 putIntoSuperObject(conjunct, 0);
559 distributedOperandsLists.push(distributedOperands);
Joachim Bingel3f0850c2014-01-17 16:50:10 +0000560 }
561
Joachim Bingeleecc7652014-01-11 17:21:07 +0000562 }
563
Joachim Bingelcc1dc242014-01-15 09:32:38 +0000564
Joachim Bingelb5f7bf02014-01-07 16:36:54 +0000565 objectsToPop.push(stackedObjects);
566
Joachim Bingel87480d02014-01-17 14:07:46 +0000567 /*
568 ****************************************************************
569 ****************************************************************
570 * recursion until 'request' node (root of tree) is processed *
571 ****************************************************************
572 ****************************************************************
573 */
Joachim Bingel5c93f902013-11-19 14:49:04 +0000574 for (int i=0; i<node.getChildCount(); i++) {
575 Tree child = node.getChild(i);
576 processNode(child);
577 }
578
Joachim Bingel87480d02014-01-17 14:07:46 +0000579 /*
580 **************************************************************
581 * Stuff that happens after processing the children of a node *
582 **************************************************************
583 */
584
Joachim Bingeld5161a12014-01-08 11:15:49 +0000585 // remove sequence from object stack if node is implicitly sequenced
586 if (sequencedNodes.size()>0) {
587 if (node == sequencedNodes.getFirst()) {
588 objectStack.pop();
589 sequencedNodes.pop();
590 }
591 }
592
Joachim Bingeleecc7652014-01-11 17:21:07 +0000593 for (int i=0; i<objectsToPop.get(0); i++) {
594 objectStack.pop();
595 }
596 objectsToPop.pop();
597
Joachim Bingel5c93f902013-11-19 14:49:04 +0000598 if (nodeCat.equals("ARG2") && openNodeCats.get(1).equals("OPNOT")) {
599 negate = false;
600 }
601
Joachim Bingel5c93f902013-11-19 14:49:04 +0000602 openNodeCats.pop();
603
604 }
605
Joachim Bingel87480d02014-01-17 14:07:46 +0000606
Joachim Bingelffd65e32014-01-22 14:22:57 +0000607
608
Joachim Bingel87480d02014-01-17 14:07:46 +0000609 private void parseOPINOptions(Tree node, LinkedHashMap<String, Object> posgroup) {
610 Tree posnode = QueryUtils.getFirstChildWithCat(node, "POS");
611 Tree rangenode = QueryUtils.getFirstChildWithCat(node, "RANGE");
612 Tree exclnode = QueryUtils.getFirstChildWithCat(node, "EXCL");
613 Tree groupnode = QueryUtils.getFirstChildWithCat(node, "GROUP");
614 boolean negatePosition = false;
615
616 String position = "";
617 if (posnode != null) {
618 String value = posnode.getChild(0).toStringTree();
Joachim Bingel84e33df2014-01-31 14:02:46 +0000619 position = translateTextAreaArgument(value, "in");
Joachim Bingel87480d02014-01-17 14:07:46 +0000620 if (value.equals("N")) {
621 negatePosition = !negatePosition;
622 }
623 } else {
624 position = "contains";
625 }
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000626 posgroup.put("@position", position);
Joachim Bingel87480d02014-01-17 14:07:46 +0000627 position = openNodeCats.get(1).equals("OPIN") ? "contains" : "full";
628
629 if (rangenode != null) {
630 String range = rangenode.getChild(0).toStringTree();
631 posgroup.put("range", range.toLowerCase());
632 }
633
634 if (exclnode != null) {
635 if (exclnode.getChild(0).toStringTree().equals("YES")) {
636 negatePosition = !negatePosition;
637 }
638 }
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000639 System.err.println(negatePosition);
Joachim Bingel87480d02014-01-17 14:07:46 +0000640 if (negatePosition) {
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000641 posgroup.put("@exclude", "true");
642// negate = !negate;
Joachim Bingel87480d02014-01-17 14:07:46 +0000643 }
644
645 if (groupnode != null) {
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000646 String grouping = groupnode.getChild(0).toStringTree().equals("max") ? "true" : "false";
Joachim Bingel87480d02014-01-17 14:07:46 +0000647 posgroup.put("grouping", grouping);
648 }
649 }
650
651 private void parseOPOVOptions(Tree node, LinkedHashMap<String, Object> posgroup) {
652 Tree posnode = QueryUtils.getFirstChildWithCat(node, "POS");
653 Tree exclnode = QueryUtils.getFirstChildWithCat(node, "EXCL");
654 Tree groupnode = QueryUtils.getFirstChildWithCat(node, "GROUP");
655
656 String position = "";
657 if (posnode != null) {
658 String value = posnode.getChild(0).toStringTree();
Joachim Bingel84e33df2014-01-31 14:02:46 +0000659 position = "-"+translateTextAreaArgument(value, "ov");
Joachim Bingel87480d02014-01-17 14:07:46 +0000660 }
Joachim Bingel84e33df2014-01-31 14:02:46 +0000661 posgroup.put("@position", "overlaps"+position);
Joachim Bingel87480d02014-01-17 14:07:46 +0000662
663 if (exclnode != null) {
664 if (exclnode.getChild(0).toStringTree().equals("YES")) {
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000665 posgroup.put("@relation", "!=");
Joachim Bingel87480d02014-01-17 14:07:46 +0000666 }
667 }
668 if (groupnode != null) {
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000669 String grouping = groupnode.getChild(0).toStringTree().equals("@max") ? "true" : "false";
Joachim Bingel87480d02014-01-17 14:07:46 +0000670 posgroup.put("grouping", grouping);
671 }
672
673 }
674
675 /**
676 * Translates the text area specifications (position option arguments) to terms used in serealisation.
677 * For the allowed argument types and their values for OPIN and OPOV, see
678 * http://www.ids-mannheim.de/cosmas2/win-app/hilfe/suchanfrage/eingabe-grafisch/syntax/ARGUMENT_I.html or
679 * http://www.ids-mannheim.de/cosmas2/win-app/hilfe/suchanfrage/eingabe-grafisch/syntax/ARGUMENT_O.html, respectively.
680 * @param argument
Joachim Bingel84e33df2014-01-31 14:02:46 +0000681 * @param mode
Joachim Bingel87480d02014-01-17 14:07:46 +0000682 * @return
683 */
Joachim Bingel84e33df2014-01-31 14:02:46 +0000684 private String translateTextAreaArgument(String argument, String mode) {
Joachim Bingel87480d02014-01-17 14:07:46 +0000685 String position = "";
686 switch (argument) {
687 case "L":
Joachim Bingel84e33df2014-01-31 14:02:46 +0000688 position = mode.equals("in") ? "startswith" : "left";
Joachim Bingel87480d02014-01-17 14:07:46 +0000689 break;
690 case "R":
Joachim Bingel84e33df2014-01-31 14:02:46 +0000691 position = mode.equals("in") ? "endswith" : "right";
Joachim Bingel87480d02014-01-17 14:07:46 +0000692 break;
693 case "F":
694 position = "leftrightmatch";
695 break;
696 case "FE":
Joachim Bingel84e33df2014-01-31 14:02:46 +0000697 position = "matches";
Joachim Bingel87480d02014-01-17 14:07:46 +0000698 break;
699 case "FI":
700 position = "leftrightmatch-noident";
701 break;
702 case "N": // for OPIN only - exclusion constraint formulated in parseOPINOptions
703 position = "leftrightmatch";
704 break;
705 case "X": // for OPOV only
706 position = "residual";
707 break;
708 }
709 return position;
710 }
711
Joachim Bingelcc1dc242014-01-15 09:32:38 +0000712 @SuppressWarnings("unchecked")
713 private void putIntoSuperObject(LinkedHashMap<String, Object> object, int objStackPosition) {
Joachim Bingele98d0882014-01-21 12:58:54 +0000714 if (distributedOperandsLists.size()>0) {
715 ArrayList<ArrayList<Object>> distributedOperands = distributedOperandsLists.pop();
716 for (ArrayList<Object> operands : distributedOperands) {
717 operands.add(object);
718 }
719 } else if (objectStack.size()>objStackPosition) {
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000720 ArrayList<Object> topObjectOperands = (ArrayList<Object>) objectStack.get(objStackPosition).get("@operands");
Joachim Bingelcc1dc242014-01-15 09:32:38 +0000721 if (!invertedOperandsLists.contains(topObjectOperands)) {
722 topObjectOperands.add(object);
723 } else {
724 topObjectOperands.add(0, object);
725 }
726
727 } else {
728 requestMap.put("query", object);
729 }
730 }
731
732 private void putIntoSuperObject(LinkedHashMap<String, Object> object) {
733 putIntoSuperObject(object, 0);
734 }
Joachim Bingel5c93f902013-11-19 14:49:04 +0000735
Joachim Bingelb5f7bf02014-01-07 16:36:54 +0000736
Joachim Bingel87480d02014-01-17 14:07:46 +0000737 private static Tree parseCosmasQuery(String p) throws RecognitionException {
Joachim Bingel5c93f902013-11-19 14:49:04 +0000738 Tree tree = null;
Joachim Bingel87480d02014-01-17 14:07:46 +0000739 ANTLRStringStream ss = new ANTLRStringStream(p);
740 c2psLexer lex = new c2psLexer(ss);
741 org.antlr.runtime.CommonTokenStream tokens = new org.antlr.runtime.CommonTokenStream(lex); //v3
Joachim Bingel5c93f902013-11-19 14:49:04 +0000742 cosmasParser = new c2psParser(tokens);
Joachim Bingel87480d02014-01-17 14:07:46 +0000743 c2psParser.c2ps_query_return c2Return = cosmasParser.c2ps_query(); // statt t().
Joachim Bingel5c93f902013-11-19 14:49:04 +0000744 // AST Tree anzeigen:
745 tree = (Tree)c2Return.getTree();
Joachim Bingel87480d02014-01-17 14:07:46 +0000746
747 String treestring = tree.toStringTree();
748 if (treestring.contains("<mismatched token") || treestring.contains("<error") || treestring.contains("<unexpected")) {
749 throw new RecognitionException();
750 }
Joachim Bingel5c93f902013-11-19 14:49:04 +0000751 return tree;
752 }
753
754 /**
755 * @param args
756 */
757 public static void main(String[] args) {
758 /*
Joachim Bingel87480d02014-01-17 14:07:46 +0000759 * For debugging
Joachim Bingel5c93f902013-11-19 14:49:04 +0000760 */
761 String[] queries = new String[] {
762 /* COSMAS 2 */
Joachim Bingelba9a0ab2014-01-29 10:12:25 +0000763 "MORPH(V)",
764 "MORPH(V PRES)",
765 "wegen #IN(%, L) <s>",
766 "wegen #IN(%) <s>",
767 "(Mann oder Frau) #IN <s>",
Joachim Bingel84e33df2014-01-31 14:02:46 +0000768 "#BEG(der /w3:5 Mann) /+w10 kommt",
769 "&würde /w0 MORPH(V)"
Joachim Bingel5c93f902013-11-19 14:49:04 +0000770 };
Joachim Bingelb5f7bf02014-01-07 16:36:54 +0000771 CosmasTree.debug=true;
Joachim Bingel5c93f902013-11-19 14:49:04 +0000772 for (String q : queries) {
773 try {
774 System.out.println(q);
Joachim Bingel87480d02014-01-17 14:07:46 +0000775 try {
776 System.out.println(parseCosmasQuery(q).toStringTree());
777 @SuppressWarnings("unused")
778 CosmasTree act = new CosmasTree(q);
779 } catch (RecognitionException e) {
780 e.printStackTrace();
781 } catch (QueryException e) {
782 e.printStackTrace();
783 }
Joachim Bingel5c93f902013-11-19 14:49:04 +0000784 System.out.println();
785
786 } catch (NullPointerException npe) {
787 npe.printStackTrace();
788 System.out.println("null\n");
789 }
790 }
791 }
792}