Mercurial > dive4elements > river
changeset 6399:10fe6758dfb0
Datacage: Introduced <dc:container-context>.
It is an analogon to <dc:context> to fetch the data from a collection.
Usage:
<dc:container-context container="myContainer">
<dc:properties>
<dc:property name="a"/>
<dc:property name="b" alias="c"/>
</dc:properties>
<dc:for-each><!-- as usual --></dc:for-each>
</dc:container-context>
Iterates over the collection stored on stack with the name 'myContainer'
and fetched for each item via getA() and getB() the values to be stored
under 'a' and 'c'. dc:has-result() & Co work as expected.
author | Sascha L. Teichmann <teichmann@intevation.de> |
---|---|
date | Fri, 21 Jun 2013 20:02:15 +0200 |
parents | 13ecaf6c0f20 |
children | 25230bc3137c |
files | artifacts/src/main/java/org/dive4elements/river/artifacts/datacage/templating/Builder.java |
diffstat | 1 files changed, 137 insertions(+), 4 deletions(-) [+] |
line wrap: on
line diff
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/datacage/templating/Builder.java Fri Jun 21 18:09:53 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/datacage/templating/Builder.java Fri Jun 21 20:02:15 2013 +0200 @@ -12,6 +12,8 @@ import org.dive4elements.river.utils.Pair; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.sql.Connection; import java.sql.SQLException; @@ -164,6 +166,14 @@ * macros but not doing evaluation (e.g. of <dc:if>s). */ private Node findStatementNode(NodeList nodes) { + return findSelectNode(nodes, "statement"); + } + + private Node findPropertiesNode(NodeList nodes) { + return findSelectNode(nodes, "properties"); + } + + private Node findSelectNode(NodeList nodes, String selectName) { int S = nodes.getLength(); // Check direct children and take special care of macros. @@ -172,7 +182,7 @@ String ns; // Regular statement node. if (node.getNodeType() == Node.ELEMENT_NODE - && node.getLocalName().equals("statement") + && node.getLocalName().equals(selectName) && (ns = node.getNamespaceURI()) != null && ns.equals(DC_NAMESPACE_URI)) { return node; @@ -185,7 +195,7 @@ String macroName = ((Element)node).getAttribute("name"); Node inMacroNode = - findStatementNode(getMacroChildren(macroName)); + findSelectNode(getMacroChildren(macroName), selectName); if (inMacroNode != null) { return inMacroNode; } @@ -196,6 +206,127 @@ return null; } + private String[][] extractProperties(Element propertiesNode) { + ArrayList<String[]> props = new ArrayList<String[]>(); + NodeList list = propertiesNode.getElementsByTagNameNS( + DC_NAMESPACE_URI, "property"); + for (int i = 0, L = list.getLength(); i < L; ++i) { + Element property = (Element)list.item(i); + String name = property.getAttribute("name"); + if (name.isEmpty()) { + log.warn("dc:property without name"); + continue; + } + String alias = property.getAttribute("alias"); + if (alias.isEmpty()) { + alias = name; + } + props.add(new String [] { name, alias }); + } + return props.toArray(new String[props.size()][]); + } + + /** + * Handle a dc:context node. + */ + protected void containerContext(Node parent, Element current) + throws SQLException + { + log.debug("dc:container-context"); + + String container = expand(current.getAttribute("container")); + + if (container.isEmpty()) { + log.warn("dc:container-context: no 'container' attribute found"); + return; + } + + NodeList subs = current.getChildNodes(); + Node propertiesNode = findPropertiesNode(subs); + + if (propertiesNode == null) { + log.warn("dc:container-context: cannot find properties."); + return; + } + + String [][] properties = extractProperties((Element)propertiesNode); + + if (properties.length == 0) { + log.warn("dc:properties: No properties defined."); + } + + Object [] result = new Object[1]; + if (!frames.getStore(container, result)) { + log.warn("dc:container-context: cannot find container."); + return; + } + Object c = result[0]; + if (c instanceof Object []) { + c = Arrays.asList((Object [])c); + } + if (!(c instanceof Collection)) { + log.warn("dc:container-context: container is not a collection."); + return; + } + + String [] columnNames = new String[properties.length]; + for (int i = 0; i < columnNames.length; ++i) { + columnNames[i] = properties[i][1]; + } + + ResultData rd = new ResultData(columnNames); + + for (Object obj: (Collection<?>)c) { + Object [] row = new Object[properties.length]; + for (int i = 0; i < properties.length; ++i) { + row[i] = getProperty(obj, properties[i][0]); + } + rd.add(row); + } + + // only descent if there are results + if (!rd.isEmpty()) { + // A bit of a fake because the data is not from a + // real connection. + NamedConnection connection = connectionsStack.isEmpty() + ? connections.get(0) + : connectionsStack.peek().getA(); + + connectionsStack.push( + new Pair<NamedConnection, ResultData>(connection, rd)); + try { + for (int i = 0, S = subs.getLength(); i < S; ++i) { + build(parent, subs.item(i)); + } + } + finally { + connectionsStack.pop(); + } + } + } + + /** Poor man's bean access. */ + private Object getProperty(Object obj, String name) { + String mname = + "get" + Character.toUpperCase(name.charAt(0)) + + name.substring(1); + + try { + Method meth = obj.getClass().getMethod(mname); + return meth.invoke(obj); + } + catch (InvocationTargetException ite) { + log.warn(ite); + } + catch (IllegalAccessException iae) { + log.warn(iae); + } + catch (NoSuchMethodException nsme) { + log.warn(nsme); + } + return null; + } + /** * Handle a dc:context node. */ @@ -206,7 +337,6 @@ NodeList subs = current.getChildNodes(); Node stmntNode = findStatementNode(subs); - int S = subs.getLength(); if (stmntNode == null) { log.warn("dc:context: cannot find statement"); @@ -250,7 +380,7 @@ connectionsStack.push( new Pair<NamedConnection, ResultData>(connection, rd)); try { - for (int i = 0; i < S; ++i) { + for (int i = 0, S = subs.getLength(); i < S; ++i) { build(parent, subs.item(i)); } } @@ -973,6 +1103,9 @@ else if ("context".equals(localName)) { context(parent, curr); } + else if ("container-context".equals(localName)) { + containerContext(parent, curr); + } else if ("if".equals(localName)) { ifClause(parent, curr); }