/** * Copyright (C) 2010 Orbeon, Inc. * * This program is free software; you can redistribute it and/or modify it under the terms of the * GNU Lesser General Public License as published by the Free Software Foundation; either version * 2.1 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The full text of the license is available at http://www.gnu.org/copyleft/lesser.html */ package org.orbeon.oxf.processor; import org.orbeon.dom.*; import org.orbeon.oxf.common.OXFException; import org.orbeon.oxf.pipeline.api.PipelineContext; import org.orbeon.oxf.xml.SAXUtils; import org.orbeon.oxf.xml.XMLReceiver; import org.orbeon.oxf.util.PooledXPathExpression; import org.orbeon.oxf.util.XPathCache; import org.orbeon.oxf.xforms.XFormsUtils; import org.orbeon.oxf.xml.NamespaceMapping; import org.orbeon.oxf.xml.dom4j.Dom4jUtils; import org.orbeon.oxf.xml.dom4j.LocationData; import org.orbeon.dom.saxon.DocumentWrapper; import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; import java.util.*; /** * Convert an XForms instance into a list of parameters. * * A filter can be provided. It contains XPath references to nodes that should not be included in * the result. The format of the filter comes directly from the native document created in the WAC, * for example: * * <params xmlns="http://www.orbeon.com/oxf/controller"> * <param ref="/form/x"/> * <param ref="/form/y"/> * <param ref="/form/z"/> * </params> */ public class InstanceToParametersProcessor extends ProcessorImpl { public static final String PARAMETERS_ELEMENT = "parameters"; public static final String PARAMETER_ELEMENT = "parameter"; public static final String NAME_ELEMENT = "name"; public static final String VALUE_ELEMENT = "value"; private static final String INPUT_INSTANCE = "instance"; private static final String INPUT_FILTER = "filter"; protected InstanceToParametersProcessor() { addInputInfo(new ProcessorInputOutputInfo(INPUT_INSTANCE)); addInputInfo(new ProcessorInputOutputInfo(INPUT_FILTER)); addOutputInfo(new ProcessorInputOutputInfo(OUTPUT_DATA)); } public ProcessorOutput createOutput(String name) { final ProcessorOutput output = new ProcessorOutputImpl(InstanceToParametersProcessor.this, name) { public void readImpl(PipelineContext pipelineContext, final XMLReceiver xmlReceiver) { try { final Element filterElement = readInputAsOrbeonDom(pipelineContext, INPUT_FILTER).getRootElement(); final Document instance = ( Document ) readInputAsOrbeonDom( pipelineContext, INPUT_INSTANCE ).clone(); final LocationData locationData = ((LocationData) instance.getRootElement().getData()); final DocumentWrapper instanceWrapper = new DocumentWrapper( instance, (locationData != null) ? locationData.file() : null, org.orbeon.oxf.util.XPath.GlobalConfiguration() ); // Mark all nodes referenced by XPath expressions final Set<Object> markedNodes = new HashSet<Object>(); for (Iterator i = filterElement.elements().iterator(); i.hasNext();) { final Element paramElement = (Element) i.next(); final Attribute refAttribute = paramElement.attribute("ref"); final String excludeRef = refAttribute.getValue(); final PooledXPathExpression xpath = XPathCache.getXPathExpression( instanceWrapper.getConfiguration(), instanceWrapper.wrap(instance), excludeRef, new NamespaceMapping(Dom4jUtils.getNamespaceContextNoDefault(paramElement)), getLocationData() ); markedNodes.add(xpath.evaluateSingleToJavaReturnToPoolOrNull()); } // See if all nodes are marked final boolean[] allMarked = { true }; instance.accept(new VisitorSupport() { public void visit(Element node) { super.visit(node); if (node.elements().size() == 0 && !markedNodes.contains(node)) allMarked[0] = false; } public void visit(Attribute node) { super.visit(node); if (!markedNodes.contains(node)) allMarked[0] = false; } }); // Output as SAX xmlReceiver.startDocument(); xmlReceiver.startElement("", PARAMETERS_ELEMENT, PARAMETERS_ELEMENT, SAXUtils.EMPTY_ATTRIBUTES); if (!allMarked[0]) { // If all the nodes of the instance map to parameters, we don't output the instance parameter outputParameter("$instance", XFormsUtils.encodeXML(instance, false), xmlReceiver); } xmlReceiver.endElement("", PARAMETERS_ELEMENT, PARAMETERS_ELEMENT); xmlReceiver.endDocument(); } catch (Exception e) { throw new OXFException(e); } } }; addOutput(OUTPUT_DATA, output); return output; } private static void outputParameter(String name, String value, ContentHandler contentHandler) throws SAXException { contentHandler.startElement("", PARAMETER_ELEMENT, PARAMETER_ELEMENT, SAXUtils.EMPTY_ATTRIBUTES); outputElement(NAME_ELEMENT, name, contentHandler); outputElement(VALUE_ELEMENT, value, contentHandler); contentHandler.endElement("", PARAMETER_ELEMENT, PARAMETER_ELEMENT); } private static void outputElement(String name, String content, ContentHandler contentHandler) throws SAXException { contentHandler.startElement("", name, name, SAXUtils.EMPTY_ATTRIBUTES); contentHandler.characters(content.toCharArray(), 0, content.length()); contentHandler.endElement("", name, name); } }