Mercurial > dive4elements > river
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)) { |