changeset 6087:47775e3a8cf6

Datacage: Introduced <dc:virtual-column name="colname" type="type" expr="XPath"> dc:virtual-column can be used to virtual add or replace a column named 'colname' to the current result set. The value is determined by evaluating "XPath", the type is determined by "type" (possible values: number, bool, node, nodeset, string. defaults to string). Usage: <dc:virtual-column name="c" type="number" expr="$a+$b"> <dc:for-each> <dc:message>{$a} + {$b} = {$c}</dc:message> </dc:for-each> </dc:virtual-column> table a | b --+-- 1 | 2 3 | 4 will result in: 1 + 2 = 3 3 + 4 = 7
author Sascha L. Teichmann <teichmann@intevation.de>
date Fri, 24 May 2013 12:19:25 +0200
parents 46c18b687fdc
children 127cc609c12b
files artifacts/src/main/java/org/dive4elements/river/artifacts/datacage/templating/Builder.java artifacts/src/main/java/org/dive4elements/river/artifacts/datacage/templating/ResultData.java
diffstat 2 files changed, 123 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/datacage/templating/Builder.java	Fri May 24 10:06:58 2013 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/datacage/templating/Builder.java	Fri May 24 12:19:25 2013 +0200
@@ -453,6 +453,117 @@
                 : groupExprStack.peek();
         }
 
+        protected void virtualColumn(Node parent, Element current)
+        throws SQLException
+        {
+            log.debug("dc:virtual-column");
+
+            if (connectionsStack.isEmpty()) {
+                log.debug("dc:virtual-column without having results");
+                return;
+            }
+
+            NodeList subs = current.getChildNodes();
+            int S = subs.getLength();
+
+            if (S == 0) {
+                log.debug("dc:virtual-column has no children");
+                return;
+            }
+
+            String name = expand(current.getAttribute("name"));
+            String expr = current.getAttribute("expr").trim();
+            String type = current.getAttribute("type").trim();
+
+            QName returnType = typeToQName(type);
+
+            XPathExpression x;
+            try {
+                x = getXPathExpression(expr);
+            }
+            catch (XPathExpressionException xee) {
+                log.warn("Invalid expression '" + expr + "'.");
+                return;
+            }
+
+            Pair<Builder.NamedConnection, ResultData> pair =
+                connectionsStack.peek();
+
+            ResultData orig = connectionsStack.peek().getB();
+
+            int index = orig.indexOfColumn(name);
+
+            ResultData rd = index >= 0 // Already has column with this name?
+                ? replaceColumn(orig, index, x, returnType)
+                : addColumn(orig, name, x, returnType);
+
+            pair.setB(rd);
+            try {
+                for (int i = 0; i < S; ++i) {
+                    build(parent, subs.item(i));
+                }
+            }
+            finally {
+                pair.setB(orig);
+            }
+        }
+
+        protected ResultData addColumn(
+            ResultData      rd,
+            String          name,
+            XPathExpression expr,
+            QName           returnType
+        ) {
+            String [] origColumns = rd.getColumnLabels();
+            int index = origColumns.length;
+            String [] newColumns = Arrays.copyOf(origColumns, index+1);
+            ResultData result = new ResultData(newColumns);
+            fillResult(result, rd, index, index+1, expr, returnType);
+            return result;
+        }
+
+        protected ResultData replaceColumn(
+            ResultData      rd,
+            int             index,
+            XPathExpression expr,
+            QName           returnType
+        ) {
+            String [] columns = rd.getColumnLabels();
+            ResultData result = new ResultData(columns);
+            fillResult(result, rd, index, columns.length, expr, returnType);
+            return result;
+        }
+
+        protected void fillResult(
+            ResultData result,
+            ResultData rd,
+            int        index,
+            int size,
+            XPathExpression expr,
+            QName returnType
+        ) {
+            List<Object []> rows = rd.getRows();
+            String [] origColumns = rd.getColumnLabels();
+            for (int i = 0, R = rows.size(); i < R; ++i) {
+                Object [] row = rows.get(i);
+                frames.enter();
+                try {
+                    frames.put(origColumns, row);
+                    Object value = expr.evaluate(EVAL_DOCUMENT, returnType);
+                    Object [] copy = Arrays.copyOf(row, size);
+                    copy[index] = value;
+                    result.add(copy);
+                }
+                catch (XPathExpressionException xxe) {
+                    log.warn("unable to apply expression '" +
+                        expr + "' to dataset.", xxe);
+                }
+                finally {
+                    frames.leave();
+                }
+            }
+        }
+
         protected void iterate(Node parent, Element current)
         throws SQLException
         {
@@ -907,6 +1018,9 @@
                     else if ("group".equals(localName)) {
                         group(parent, curr);
                     }
+                    else if ("virtual-column".equals(localName)) {
+                        virtualColumn(parent, curr);
+                    }
                     else if ("text".equals(localName)) {
                         text(parent, curr);
                     }
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/datacage/templating/ResultData.java	Fri May 24 10:06:58 2013 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/datacage/templating/ResultData.java	Fri May 24 12:19:25 2013 +0200
@@ -77,6 +77,15 @@
         return this;
     }
 
+    public int indexOfColumn(String column) {
+        for (int i = 0; i < columns.length; ++i) {
+            if (columns[i].equalsIgnoreCase(column)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
     public void add(Object [] result) {
         rows.add(result);
     }

http://dive4elements.wald.intevation.org