comparison artifacts/src/main/java/org/dive4elements/river/artifacts/datacage/templating/Builder.java @ 5890:6ea004d51203

Datacage: Introduced <dc:group epxr="xpath" type="type"> ... </dc:group> and XPath function dc:group-key(). This splits the current result set into groups formed by expr. The type defaults to string. Afterwards all these groups are iterated by there natural order. The dc:group-key() gives access to the result of the grouping expression that forms a group. Say, you have a result set like this: name | description -----+------------ a | foo a | bar b | baz b | bla c | blub you can use: <dc:group expr="$name"> <group name="{dc:group-key()}"> <dc:for-each> <description value="{$description}"/> </dc:for-each> </group> </dc:group> to create: <group name="a"> <description name="foo"/> <description name="bar"/> </group> <group name="b"> <description name="baz"/> <description name="bla"/> </group> <group name="c"> <description name="blub"/> </group>
author Sascha L. Teichmann <teichmann@intevation.de>
date Thu, 02 May 2013 20:52:18 +0200
parents 88fca576e9e6
children 9a3ca7532f2a
comparison
equal deleted inserted replaced
5888:a763fb7aa2e5 5890:6ea004d51203
15 import java.sql.Connection; 15 import java.sql.Connection;
16 import java.sql.SQLException; 16 import java.sql.SQLException;
17 17
18 import java.util.ArrayDeque; 18 import java.util.ArrayDeque;
19 import java.util.ArrayList; 19 import java.util.ArrayList;
20 import java.util.Collections;
20 import java.util.Deque; 21 import java.util.Deque;
21 import java.util.HashMap; 22 import java.util.HashMap;
22 import java.util.List; 23 import java.util.List;
23 import java.util.Map; 24 import java.util.Map;
25 import java.util.TreeMap;
24 26
25 import java.util.regex.Matcher; 27 import java.util.regex.Matcher;
26 import java.util.regex.Pattern; 28 import java.util.regex.Pattern;
27 29
28 import javax.xml.namespace.QName; 30 import javax.xml.namespace.QName;
104 protected StackFrames frames; 106 protected StackFrames frames;
105 protected List<NamedConnection> connections; 107 protected List<NamedConnection> connections;
106 protected Map<String, CompiledStatement.Instance> statements; 108 protected Map<String, CompiledStatement.Instance> statements;
107 protected Deque<Pair<NamedConnection, ResultData>> connectionsStack; 109 protected Deque<Pair<NamedConnection, ResultData>> connectionsStack;
108 protected Deque<NodeList> macroBodies; 110 protected Deque<NodeList> macroBodies;
111 protected Deque<Object> groupExprStack;
109 protected FunctionResolver functionResolver; 112 protected FunctionResolver functionResolver;
110 protected Map<String, XPathExpression> expressions; 113 protected Map<String, XPathExpression> expressions;
111 114
112 115
113 public BuildHelper( 116 public BuildHelper(
124 new ArrayDeque<Pair<NamedConnection, ResultData>>(); 127 new ArrayDeque<Pair<NamedConnection, ResultData>>();
125 this.output = output; 128 this.output = output;
126 frames = new StackFrames(parameters); 129 frames = new StackFrames(parameters);
127 owner = getOwnerDocument(output); 130 owner = getOwnerDocument(output);
128 macroBodies = new ArrayDeque<NodeList>(); 131 macroBodies = new ArrayDeque<NodeList>();
132 groupExprStack = new ArrayDeque<Object>();
129 functionResolver = new FunctionResolver(this); 133 functionResolver = new FunctionResolver(this);
130 expressions = new HashMap<String, XPathExpression>(); 134 expressions = new HashMap<String, XPathExpression>();
131 statements = 135 statements =
132 new HashMap<String, CompiledStatement.Instance>(); 136 new HashMap<String, CompiledStatement.Instance>();
133 } 137 }
323 pair.setB(orig); 327 pair.setB(orig);
324 } 328 }
325 } 329 }
326 } 330 }
327 331
332 protected Map<Object, ResultData> createGroupedResultData(
333 ResultData rd,
334 String expr,
335 String type
336 ) {
337
338 List<Object []> rows = rd.getRows();
339 String [] columns = rd.getColumnLabels();
340
341 XPathExpression x;
342 try {
343 x = getXPathExpression(expr);
344 }
345 catch (XPathExpressionException xee) {
346 log.warn("Invalid expression '" + expr + "'.");
347 return Collections.<Object, ResultData>emptyMap();
348 }
349
350 QName returnType = typeToQName(type);
351
352 Map<Object, ResultData> groups = new TreeMap<Object, ResultData>();
353
354 for (Object [] row: rows) {
355 frames.enter();
356 try {
357 frames.put(columns, row);
358
359 Object key = x.evaluate(EVAL_DOCUMENT, returnType);
360
361 ResultData group = groups.get(key);
362
363 if (group == null) {
364 group = new ResultData(rd.getColumnLabels());
365 groups.put(key, group);
366 }
367
368 group.add(row);
369 }
370 catch (XPathExpressionException xxe) {
371 log.warn("unable to apply expression '" +
372 expr + "' to dataset.");
373 }
374 finally {
375 frames.leave();
376 }
377 }
378 return groups;
379 }
380
381 protected void group(Node parent, Element current)
382 throws SQLException
383 {
384 log.debug("dc:group");
385
386 if (connectionsStack.isEmpty()) {
387 log.debug("dc:group without having results");
388 return;
389 }
390
391 NodeList subs = current.getChildNodes();
392 int S = subs.getLength();
393
394 if (S == 0) {
395 log.debug("dc:group has no children");
396 return;
397 }
398
399 String expr = current.getAttribute("expr").trim();
400 String type = current.getAttribute("type").trim();
401
402 Pair<Builder.NamedConnection, ResultData> pair =
403 connectionsStack.peek();
404
405 ResultData orig = connectionsStack.peek().getB();
406
407 Map<Object, ResultData> groups =
408 createGroupedResultData(orig, expr, type);
409
410 String [] columns = orig.getColumnLabels();
411
412 try {
413 for (Map.Entry<Object, ResultData> entry: groups.entrySet()) {
414 ResultData rd = entry.getValue();
415 pair.setB(rd);
416 groupExprStack.push(entry.getKey());
417 try {
418 for (Object [] row: rd.getRows()) {
419 frames.enter();
420 try {
421 frames.put(columns, row);
422 for (int i = 0; i < S; ++i) {
423 build(parent, subs.item(i));
424 }
425 }
426 finally {
427 frames.leave();
428 }
429 }
430 }
431 finally {
432 groupExprStack.pop();
433 }
434 }
435 }
436 finally {
437 pair.setB(orig);
438 }
439 }
440
441 public Object getGroupKey() {
442 return groupExprStack.isEmpty()
443 ? null
444 : groupExprStack.peek();
445 }
446
328 /** 447 /**
329 * Kind of foreach over results of a statement within a context. 448 * Kind of foreach over results of a statement within a context.
330 */ 449 */
331 protected void foreach(Node parent, Element current) 450 protected void foreach(Node parent, Element current)
332 throws SQLException 451 throws SQLException
706 else if ("for-each".equals(localName)) { 825 else if ("for-each".equals(localName)) {
707 foreach(parent, curr); 826 foreach(parent, curr);
708 } 827 }
709 else if ("filter".equals(localName)) { 828 else if ("filter".equals(localName)) {
710 filter(parent, curr); 829 filter(parent, curr);
830 }
831 else if ("group".equals(localName)) {
832 group(parent, curr);
711 } 833 }
712 else if ("text".equals(localName)) { 834 else if ("text".equals(localName)) {
713 text(parent, curr); 835 text(parent, curr);
714 } 836 }
715 else if ("variable".equals(localName)) { 837 else if ("variable".equals(localName)) {

http://dive4elements.wald.intevation.org