Example usage for org.dom4j Node ELEMENT_NODE

List of usage examples for org.dom4j Node ELEMENT_NODE

Introduction

In this page you can find the example usage for org.dom4j Node ELEMENT_NODE.

Prototype

short ELEMENT_NODE

To view the source code for org.dom4j Node ELEMENT_NODE.

Click Source Link

Document

Matches Element nodes

Usage

From source file:org.orbeon.oxf.processor.pipeline.ast.ASTNodeContainer.java

License:Open Source License

/**
 * Use specified location if there is one.  Otherwise if a node has been provided use the
 * location of the node.  If no node and no location then return hull.
 *//* w  w  w  . jav  a 2s .c o  m*/
public LocationData getLocationData() {
    final LocationData ret;
    if (locationData != null) {
        ret = locationData;
    } else if (node == null) {
        ret = null;
    } else if (node.getNodeType() == org.dom4j.Node.ELEMENT_NODE) {
        ret = (LocationData) ((org.dom4j.Element) node).getData();
    } else if (node.getNodeType() == org.dom4j.Node.ATTRIBUTE_NODE) {
        ret = (LocationData) ((org.dom4j.Attribute) node).getData();
    } else {
        ret = null;
    }
    return ret;
}

From source file:org.orbeon.oxf.processor.pipeline.PipelineProcessor.java

License:Open Source License

public static PipelineConfig createConfigFromAST(ASTPipeline astPipeline) {

    // Perform sanity check on the connection in the pipeline
    astPipeline.getIdInfo();/*from  w  w w  .ja  va2s  .c  om*/

    // Create new configuration object
    final PipelineConfig config = new PipelineConfig();
    final PipelineBlock block = new PipelineBlock();

    // Create socket info for each param
    for (Iterator i = astPipeline.getParams().iterator(); i.hasNext();) {
        ASTParam param = (ASTParam) i.next();

        // Create internal top output/bottom input for this param
        if (param.getType() == ASTParam.INPUT) {
            final InternalTopOutput internalTopOutput = new InternalTopOutput(param.getName(),
                    param.getLocationData());
            block.declareOutput(param.getNode(), param.getName(), internalTopOutput);
            config.declareTopOutput(param.getName(), internalTopOutput);
            setDebugAndSchema(internalTopOutput, param);
        } else {
            final ProcessorInput internalBottomInput = new InternalBottomInput(param.getName());
            block.declareBottomInput(param.getNode(), param.getName(), internalBottomInput);
            config.declareBottomInput(param.getName(), internalBottomInput);
            setDebugAndSchema(internalBottomInput, param);
        }

        // Create socket
        // FIXME: when we implement the full delegation model, we'll have
        // here to create of pass the input/output information.
    }

    // Internally connect all processors / choose / for-each
    for (Iterator i = astPipeline.getStatements().iterator(); i.hasNext();) {
        Object statement = i.next();
        Processor processor = null;
        boolean foundOutput = false;

        if (statement instanceof ASTProcessorCall) {
            ASTProcessorCall processorCall = (ASTProcessorCall) statement;

            final LocationData processorLocationData = processorCall.getLocationData();
            final String processorNameOrURI = Dom4jUtils.qNameToExplodedQName(processorCall.getName());

            // Direct call
            if (processorCall.getProcessor() == null) {
                ProcessorFactory processorFactory = ProcessorFactoryRegistry.lookup(processorCall.getName());
                if (processorFactory == null) {
                    throw new ValidationException(
                            "Cannot find processor factory with name \"" + processorNameOrURI + "\"",
                            processorLocationData);
                }
                processor = processorFactory.createInstance();
            } else {
                processor = processorCall.getProcessor();
            }

            // Set info on processor
            processor.setId(processorCall.getId());
            processor.setLocationData(new ExtendedLocationData(processorLocationData, "executing processor",
                    (Element) processorCall.getNode(), new String[] { "name", processorNameOrURI }));

            // Process outputs
            for (Iterator j = processorCall.getOutputs().iterator(); j.hasNext();) {
                foundOutput = true;
                ASTOutput output = (ASTOutput) j.next();
                final String nm = output.getName();
                if (nm == null)
                    throw new OXFException("Name attribute is mandatory on output");
                final String id = output.getId();
                final String ref = output.getRef();
                if (id == null && ref == null)
                    throw new OXFException("Either one of id or ref must be specified on output " + nm);

                ProcessorOutput pout = processor.createOutput(nm);
                if (id != null)
                    block.declareOutput(output.getNode(), id, pout);
                if (ref != null)
                    block.connectProcessorToBottomInput(output.getNode(), nm, ref, pout);
                setDebugAndSchema(pout, output);
            }

            // Make sure at least one of the outputs is connected
            if (!foundOutput && processor.getOutputsInfo().size() > 0)
                throw new ValidationException("The processor output must be connected", processorLocationData);

            // Process inputs
            for (Iterator j = processorCall.getInputs().iterator(); j.hasNext();) {
                ASTInput input = (ASTInput) j.next();

                final ProcessorInput pin;
                LocationData inputLocationData = input.getLocationData();
                if (input.getHref() != null && input.getTransform() == null) {
                    // We just reference a URI
                    pin = block.connectProcessorToHref(input.getNode(), processor, input.getName(),
                            input.getHref());
                } else {
                    // We have some inline XML in the <input> tag
                    final Node inlineNode = input.getContent();

                    // Create inline document
                    final Document inlineDocument;
                    {
                        final int nodeType = inlineNode.getNodeType();
                        if (nodeType == Node.ELEMENT_NODE) {
                            final Element element = (Element) inlineNode;
                            inlineDocument = Dom4jUtils.createDocumentCopyParentNamespaces(element);
                        } else if (nodeType == Node.DOCUMENT_NODE) {
                            inlineDocument = (Document) inlineNode;
                        } else {
                            throw new OXFException(
                                    "Invalid type for inline document: " + inlineNode.getClass().getName());
                        }
                    }

                    // Create generator for the inline document
                    final DOMGenerator domGenerator;
                    {
                        final Object validity = astPipeline.getValidity();
                        final LocationData pipelineLocationData = astPipeline.getLocationData();
                        String systemId = (pipelineLocationData == null) ? DOMGenerator.DefaultContext
                                : pipelineLocationData.getSystemID();
                        if (systemId == null)
                            systemId = DOMGenerator.DefaultContext;
                        domGenerator = PipelineUtils.createDOMGenerator(inlineDocument, "inline input",
                                validity, systemId);
                    }

                    final ProcessorOutput domProcessorDataOutput = domGenerator.createOutput(OUTPUT_DATA);

                    // Check if there is an inline transformation
                    final QName transform = input.getTransform();
                    if (transform != null) {
                        //XPathUtils.selectBooleanValue(inlineDocument, "/*/@*[local-name() = 'version' and namespace-uri() = 'http://www.w3.org/1999/XSL/Transform'] = '2.0'").booleanValue()
                        // Instanciate processor
                        final Processor transformProcessor;
                        {
                            final ProcessorFactory processorFactory = ProcessorFactoryRegistry
                                    .lookup(transform);
                            if (processorFactory == null) {
                                throw new ValidationException("Cannot find processor factory with JNDI name \""
                                        + transform.getQualifiedName() + "\"", inputLocationData);
                            }
                            transformProcessor = processorFactory.createInstance();
                        }

                        // Add transformation to this pipeline/block, so it is appropriately reset if the block runs multiple times
                        config.addProcessor(transformProcessor);

                        // Set info on processor
                        //processor.setId(processorCall.getId()); // what id, if any?
                        transformProcessor.setLocationData(inputLocationData);

                        // Connect config input
                        final ProcessorInput transformConfigInput = transformProcessor
                                .createInput(INPUT_CONFIG);
                        domProcessorDataOutput.setInput(transformConfigInput);
                        transformConfigInput.setOutput(domProcessorDataOutput);

                        // Connect transform processor data input
                        pin = block.connectProcessorToHref(input.getNode(), transformProcessor, INPUT_DATA,
                                input.getHref());

                        // Connect transform processor data output
                        final ProcessorOutput transformDataOutput = transformProcessor
                                .createOutput(OUTPUT_DATA);
                        final ProcessorInput processorDataInput = processor.createInput(input.getName());
                        transformDataOutput.setInput(processorDataInput);
                        processorDataInput.setOutput(transformDataOutput);
                    } else {
                        // It is regular static text: connect directly
                        pin = processor.createInput(input.getName());
                        domProcessorDataOutput.setInput(pin);
                        pin.setOutput(domProcessorDataOutput);
                    }
                }
                setDebugAndSchema(pin, input);
            }

        } else if (statement instanceof ASTChoose) {

            // Instantiate processor
            ASTChoose choose = (ASTChoose) statement;
            AbstractProcessor chooseAbstractProcessor = new AbstractChooseProcessor(choose,
                    astPipeline.getValidity());
            ConcreteChooseProcessor chooseProcessor = (ConcreteChooseProcessor) chooseAbstractProcessor
                    .createInstance();
            processor = chooseProcessor;

            // Connect special $data input (document on which the decision is made, or iterated on)
            ProcessorInput pin = block.connectProcessorToHref(choose.getNode(), processor,
                    AbstractChooseProcessor.CHOOSE_DATA_INPUT, choose.getHref());
            setDebugAndSchema(pin, choose);

            // Go through inputs/outputs and connect to the rest of the pipeline
            for (Iterator j = processor.getInputsInfo().iterator(); j.hasNext();) {
                // We reference a previously declared output
                String inputName = ((ProcessorInputOutputInfo) j.next()).getName();
                if (!inputName.equals(AbstractChooseProcessor.CHOOSE_DATA_INPUT)) {
                    ASTHrefId hrefId = new ASTHrefId();
                    hrefId.setId(inputName);
                    block.connectProcessorToHref(choose.getNode(), processor, inputName, hrefId);
                }
            }
            for (Iterator j = processor.getOutputsInfo().iterator(); j.hasNext();) {
                String outputName = ((ProcessorInputOutputInfo) j.next()).getName();
                foundOutput = true;
                ProcessorOutput pout = processor.createOutput(outputName);
                if (chooseProcessor.getOutputsById().contains(outputName))
                    block.declareOutput(choose.getNode(), outputName, pout);
                if (chooseProcessor.getOutputsByParamRef().contains(outputName))
                    block.connectProcessorToBottomInput(choose.getNode(), outputName, outputName, pout);
            }

        } else if (statement instanceof ASTForEach) {

            // Instantiate processor
            final ASTForEach forEach = (ASTForEach) statement;
            final LocationData forEachLocationData = forEach.getLocationData();
            final AbstractProcessor forEachAbstractProcessor = new AbstractForEachProcessor(forEach,
                    astPipeline.getValidity());

            processor = (ConcreteForEachProcessor) forEachAbstractProcessor.createInstance();

            // Connect special $data input (document on which the decision is made, or iterated on)
            final ProcessorInput pin = block.connectProcessorToHref(forEach.getNode(), processor,
                    AbstractForEachProcessor.FOR_EACH_DATA_INPUT, forEach.getHref());
            setDebugAndSchema(pin, forEach, forEachLocationData, forEach.getInputSchemaUri(),
                    forEach.getInputSchemaHref(), forEach.getInputDebug());

            // Go through inputs and connect to the rest of the pipeline
            for (Iterator j = processor.getInputsInfo().iterator(); j.hasNext();) {
                // We reference a previously declared output
                final String inputName = ((ProcessorInputOutputInfo) j.next()).getName();
                if (!inputName.equals(AbstractForEachProcessor.FOR_EACH_DATA_INPUT)) {
                    final ASTHrefId hrefId = new ASTHrefId();
                    hrefId.setId(inputName);
                    // NOTE: Force creation of a tee so that inputs of p:for-each are not read multiple times
                    block.connectProcessorToHref(forEach.getNode(), processor, inputName, hrefId, true);
                }
            }

            // Connect output
            final String outputName = forEach.getId() != null ? forEach.getId() : forEach.getRef();
            if (outputName != null) {
                foundOutput = true;
                final ProcessorOutput forEachOutput = processor.createOutput(outputName);
                if (forEach.getId() != null)
                    block.declareOutput(forEach.getNode(), forEach.getId(), forEachOutput);
                if (forEach.getRef() != null)
                    block.connectProcessorToBottomInput(forEach.getNode(), forEach.getId(), forEach.getRef(),
                            forEachOutput);
                setDebugAndSchema(processor.getOutputByName(outputName), forEach, forEachLocationData,
                        forEach.getOutputSchemaUri(), forEach.getOutputSchemaHref(), forEach.getOutputDebug());
            }
        }

        // Remember all processors and processor with no output (need to be started)
        if (processor != null) {
            config.addProcessor(processor);
            if (!foundOutput) {
                config.addProcessorToStart(processor);
            }
        }
    }

    // Check that all bottom inputs are connected
    for (Iterator i = astPipeline.getParams().iterator(); i.hasNext();) {
        ASTParam param = (ASTParam) i.next();
        if (param.getType() == ASTParam.OUTPUT) {
            if (!block.isBottomInputConnected(param.getName()))
                throw new ValidationException(
                        "No processor in pipeline is connected to pipeline output '" + param.getName() + "'",
                        param.getLocationData());
        }
    }

    // Add processors created for connection reasons
    for (Iterator i = block.getCreatedProcessors().iterator(); i.hasNext();)
        config.addProcessor((Processor) i.next());

    return config;
}

From source file:org.orbeon.oxf.processor.transformer.xslt.XSLTTransformer.java

License:Open Source License

@Override
public ProcessorOutput createOutput(final String name) {
    final ProcessorOutput output = new CacheableTransformerOutputImpl(XSLTTransformer.this, name) {
        public void readImpl(PipelineContext pipelineContext, XMLReceiver xmlReceiver) {
            makeSureStateIsSet(pipelineContext);

            final XSLTTransformerState state = (XSLTTransformerState) getState(pipelineContext);

            if (!state.hasTransformationRun) {

                state.hasTransformationRun = true;

                // Get URI references from cache
                final KeyValidity configKeyValidity = getInputKeyValidity(pipelineContext, INPUT_CONFIG);
                final URIReferences uriReferences = getURIReferences(pipelineContext, configKeyValidity);

                // Get transformer from cache
                TemplatesInfo templatesInfo = null;
                if (uriReferences != null) {
                    // FIXME: this won't depend on the transformer input.
                    final KeyValidity stylesheetKeyValidity = createStyleSheetKeyValidity(pipelineContext,
                            configKeyValidity, uriReferences);
                    if (stylesheetKeyValidity != null)
                        templatesInfo = (TemplatesInfo) ObjectCache.instance()
                                .findValid(stylesheetKeyValidity.key, stylesheetKeyValidity.validity);
                }//  w  ww. jav  a2  s  .co m

                // Get transformer attributes if any
                final Map<String, Boolean> attributesFromProperties;
                // Read optional attributes input only if connected
                if (getConnectedInputs().get(INPUT_ATTRIBUTES) != null) {
                    // Read input as an attribute Map and cache it
                    attributesFromProperties = readCacheInputAsObject(pipelineContext,
                            getInputByName(INPUT_ATTRIBUTES), new CacheableInputReader<Map<String, Boolean>>() {
                                public Map<String, Boolean> read(PipelineContext context,
                                        ProcessorInput input) {
                                    final Document preferencesDocument = readInputAsDOM4J(context, input);
                                    final PropertyStore propertyStore = new PropertyStore(preferencesDocument);
                                    final PropertySet propertySet = propertyStore.getGlobalPropertySet();
                                    return propertySet.getBooleanProperties();
                                }
                            });
                } else
                    attributesFromProperties = Collections.emptyMap();

                // Output location mode
                final String outputLocationMode = getPropertySet().getString(OUTPUT_LOCATION_MODE_PROPERTY,
                        OUTPUT_LOCATION_MODE_DEFAULT);
                final boolean isDumbOutputLocation = OUTPUT_LOCATION_DUMB.equals(outputLocationMode);
                final boolean isSmartOutputLocation = OUTPUT_LOCATION_SMART.equals(outputLocationMode);
                final Map<String, Boolean> attributes;
                if (isSmartOutputLocation) {
                    // Create new HashMap as we don't want to change the one in cache
                    attributes = new HashMap<String, Boolean>(attributesFromProperties);
                    // Set attributes for Saxon source location
                    attributes.put(FeatureKeys.LINE_NUMBERING, Boolean.TRUE);
                    attributes.put(FeatureKeys.COMPILE_WITH_TRACING, Boolean.TRUE);
                } else
                    attributes = attributesFromProperties;

                // Create transformer if we did not find one in cache
                if (templatesInfo == null) {
                    // Get transformer configuration
                    final Node config = readCacheInputAsDOM4J(pipelineContext, INPUT_TRANSFORMER);
                    final String transformerClass = XPathUtils.selectStringValueNormalize(config,
                            "/config/class");
                    // Create transformer
                    // NOTE: createTransformer() handles its own exceptions
                    templatesInfo = createTransformer(pipelineContext, transformerClass, attributes);
                }

                // At this point, we have a templatesInfo, so run the transformation

                // Find which receiver to use
                final XMLReceiver outputReceiver;
                if (name.equals(OUTPUT_DATA)) {
                    // The first output called is the main output: output directly
                    outputReceiver = xmlReceiver;
                } else {
                    // The first output called is not the main output: store main result
                    final SAXStore store = new SAXStore();
                    state.addOutputDocument(OUTPUT_DATA, store);
                    outputReceiver = store;

                    // First output will stream out
                    state.setFirstXMLReceiver(name, xmlReceiver);
                }

                runTransformer(pipelineContext, state, outputReceiver, templatesInfo, attributes,
                        isDumbOutputLocation, isSmartOutputLocation);
            } else {
                // Transformation has run already, replay output
                if (state.outputDocuments == null)
                    throw new OXFException("Attempt to read non-existing output: " + name);
                try {
                    final SAXStore outputStore = state.outputDocuments.get(name);
                    if (outputStore == null)
                        throw new OXFException("Attempt to read non-existing output: " + name);
                    outputStore.replay(xmlReceiver);
                    state.outputDocuments.remove(name);
                } catch (SAXException e) {
                    throw new OXFException(e);
                }
            }
        }

        private void runTransformer(final PipelineContext pipelineContext, final XSLTTransformerState state,
                final XMLReceiver xmlReceiver, TemplatesInfo templatesInfo, Map<String, Boolean> attributes,
                final boolean dumbOutputLocation, final boolean smartOutputLocation) {

            StringBuilderWriter saxonStringBuilderWriter = null;
            try {
                // Create transformer handler and set output writer for Saxon
                final StringErrorListener errorListener = new StringErrorListener(logger);
                final TransformerHandler transformerHandler = TransformerUtils.getTransformerHandler(
                        templatesInfo.templates, templatesInfo.transformerClass, attributes,
                        createXSLTConfiguration());

                // Set handler for xsl:result-document
                if (transformerHandler instanceof TransformerHandlerImpl) {
                    final TransformerHandlerImpl saxonTransformerHandler = (TransformerHandlerImpl) transformerHandler;
                    ((Controller) saxonTransformerHandler.getTransformer())
                            .setOutputURIResolver(new OutputURIResolver() {
                                public Result resolve(String href, String base) throws TransformerException {

                                    final String outputName = getProcessorOutputSchemeInputName(href);
                                    if (outputName == null) {
                                        // Regular URL
                                        try {
                                            final URL url = URLFactory.createURL(base, href);
                                            final StreamResult result;
                                            if (url.getProtocol().equals("file")) {
                                                // Special handling of file as URLConnection does not support writing to a file
                                                result = new StreamResult(
                                                        new FileOutputStream(new File(url.toURI())));
                                            } else {
                                                // Other protocols
                                                final URLConnection urlConnection = url.openConnection();
                                                urlConnection.setDoOutput(true);
                                                result = new StreamResult(urlConnection.getOutputStream());
                                            }
                                            result.setSystemId(url.toExternalForm());
                                            return result;
                                        } catch (Exception e) {
                                            throw new OXFException(e);
                                        }
                                    } else {
                                        // output:*
                                        final XMLReceiver outputReceiver;
                                        if (outputName.equals(state.firstOutputName)) {
                                            // Stream through first receiver
                                            outputReceiver = state.firstXMLReceiver;
                                        } else {
                                            // Store
                                            final SAXStore store = new SAXStore();
                                            state.addOutputDocument(outputName, store);

                                            outputReceiver = store;
                                        }

                                        final SAXResult result = new SAXResult(outputReceiver);
                                        result.setLexicalHandler(outputReceiver);
                                        result.setSystemId(href);

                                        return result;
                                    }
                                }

                                public void close(Result result) throws TransformerException {
                                    // Free information from the state
                                    final String outputName = getProcessorOutputSchemeInputName(
                                            result.getSystemId());
                                    if (outputName == null) {
                                        // Regular URL
                                        if (result instanceof StreamResult) {
                                            final OutputStream os = ((StreamResult) result).getOutputStream();
                                            if (os != null)
                                                try {
                                                    os.close();
                                                } catch (IOException e) {
                                                    throw new OXFException(e);
                                                }
                                        }
                                    } else {
                                        // output:*
                                        if (outputName.equals(state.firstOutputName)) {
                                            state.firstOutputName = null;
                                            state.firstXMLReceiver = null;
                                        }
                                    }
                                }
                            });
                }

                final Transformer transformer = transformerHandler.getTransformer();
                final TransformerURIResolver transformerURIResolver = new TransformerURIResolver(
                        XSLTTransformer.this, pipelineContext, INPUT_DATA, XMLUtils.ParserConfiguration.PLAIN);
                transformer.setURIResolver(transformerURIResolver);
                transformer.setErrorListener(errorListener);
                if (smartOutputLocation)
                    transformer.setOutputProperty(SaxonOutputKeys.SUPPLY_SOURCE_LOCATOR, "yes");

                // Create writer for transformation errors
                saxonStringBuilderWriter = createErrorStringBuilderWriter(transformerHandler);

                // Fallback location data
                final LocationData processorLocationData = getLocationData();

                // Output filter to fix-up SAX stream and handle location data if needed
                final XMLReceiver outputReceiver = new SimpleForwardingXMLReceiver(xmlReceiver) {

                    private Locator inputLocator;
                    private OutputLocator outputLocator;
                    private Stack<LocationData> startElementLocationStack;

                    class OutputLocator implements Locator {

                        private LocationData currentLocationData;

                        public String getPublicId() {
                            return null;
                        }

                        public String getSystemId() {
                            return (currentLocationData != null) ? currentLocationData.getSystemID()
                                    : inputLocator.getSystemId();
                        }

                        public int getLineNumber() {
                            return (currentLocationData != null) ? currentLocationData.getLine()
                                    : inputLocator.getLineNumber();
                        }

                        public int getColumnNumber() {
                            return (currentLocationData != null) ? currentLocationData.getCol()
                                    : inputLocator.getColumnNumber();
                        }

                        public void setLocationData(LocationData locationData) {
                            this.currentLocationData = locationData;
                        }
                    }

                    @Override
                    public void setDocumentLocator(final Locator locator) {
                        this.inputLocator = locator;
                        if (smartOutputLocation) {
                            this.outputLocator = new OutputLocator();
                            this.startElementLocationStack = new Stack<LocationData>();
                            super.setDocumentLocator(this.outputLocator);
                        } else if (dumbOutputLocation) {
                            super.setDocumentLocator(this.inputLocator);
                        } else {
                            // NOP: don't set a locator
                        }
                    }

                    @Override
                    public void startDocument() throws SAXException {
                        // Try to set fallback Locator
                        if (((outputLocator != null && outputLocator.getSystemId() == null)
                                || (inputLocator != null && inputLocator.getSystemId() == null))
                                && processorLocationData != null && dumbOutputLocation) {
                            final Locator locator = new ConstantLocator(processorLocationData);
                            super.setDocumentLocator(locator);
                        }
                        super.startDocument();
                    }

                    @Override
                    public void endDocument() throws SAXException {
                        if (endDocumentCalled()) {
                            // Hack to test if Saxon outputs more than one endDocument() event
                            logger.warn("XSLT transformer attempted to call endDocument() more than once.");
                            return;
                        }
                        super.endDocument();
                    }

                    @Override
                    public void startElement(String uri, String localname, String qName, Attributes attributes)
                            throws SAXException {
                        if (outputLocator != null) {
                            final LocationData locationData = findSourceElementLocationData(uri, localname);
                            outputLocator.setLocationData(locationData);
                            startElementLocationStack.push(locationData);
                            super.startElement(uri, localname, qName, attributes);
                            outputLocator.setLocationData(null);
                        } else {
                            super.startElement(uri, localname, qName, attributes);
                        }
                    }

                    @Override
                    public void endElement(String uri, String localname, String qName) throws SAXException {
                        if (outputLocator != null) {
                            // Here we do a funny thing: since Saxon does not provide location data on endElement(), we use that of startElement()
                            final LocationData locationData = startElementLocationStack.peek();
                            outputLocator.setLocationData(locationData);
                            super.endElement(uri, localname, qName);
                            outputLocator.setLocationData(null);
                            startElementLocationStack.pop();
                        } else {
                            super.endElement(uri, localname, qName);
                        }
                    }

                    @Override
                    public void characters(char[] chars, int start, int length) throws SAXException {
                        if (outputLocator != null) {
                            final LocationData locationData = findSourceCharacterLocationData();
                            outputLocator.setLocationData(locationData);
                            super.characters(chars, start, length);
                            outputLocator.setLocationData(null);
                        } else {
                            super.characters(chars, start, length);
                        }
                    }

                    private LocationData findSourceElementLocationData(String uri, String localname) {
                        if (inputLocator instanceof ContentHandlerProxyLocator) {
                            final Stack stack = ((ContentHandlerProxyLocator) inputLocator)
                                    .getContextItemStack();

                            for (int i = stack.size() - 1; i >= 0; i--) {
                                final Item currentItem = (Item) stack.get(i);
                                if (currentItem instanceof NodeInfo) {
                                    final NodeInfo currentNodeInfo = (NodeInfo) currentItem;
                                    if (currentNodeInfo.getNodeKind() == org.w3c.dom.Node.ELEMENT_NODE
                                            && currentNodeInfo.getLocalPart().equals(localname)
                                            && currentNodeInfo.getURI().equals(uri)) {
                                        // Very probable match...
                                        return new LocationData(currentNodeInfo.getSystemId(),
                                                currentNodeInfo.getLineNumber(), -1);
                                    }
                                }
                            }
                        }
                        return null;
                    }

                    private LocationData findSourceCharacterLocationData() {
                        if (inputLocator instanceof ContentHandlerProxyLocator) {
                            final Stack stack = ((ContentHandlerProxyLocator) inputLocator)
                                    .getContextItemStack();
                            if (stack != null) {
                                for (int i = stack.size() - 1; i >= 0; i--) {
                                    final Item currentItem = (Item) stack.get(i);
                                    if (currentItem instanceof NodeInfo) {
                                        final NodeInfo currentNodeInfo = (NodeInfo) currentItem;
                                        //                                        if (currentNodeInfo.getNodeKind() == org.w3c.dom.Node.TEXT_NODE) {
                                        // Possible match
                                        return new LocationData(currentNodeInfo.getSystemId(),
                                                currentNodeInfo.getLineNumber(), -1);
                                        //                                        }
                                    }
                                }
                            }
                        }
                        return null;
                    }
                };

                // Create result, also setting LexicalHandler to handle comments
                final SAXResult saxResult = new SAXResult(outputReceiver);
                saxResult.setLexicalHandler(outputReceiver);

                if (processorLocationData != null) {
                    final String processorSystemId = processorLocationData.getSystemID();
                    //saxResult.setSystemId(sysID); // NOT SURE WHY WE DID THIS
                    // TODO: use source document system ID, not stylesheet system ID
                    transformerHandler.setSystemId(processorSystemId);
                }
                transformerHandler.setResult(saxResult);

                // Execute transformation
                try {
                    if (XSLTTransformer.this.getConnectedInputs().size() > 4) {
                        // The default inputs are data, config, transformer, and attributes. When other inputs
                        // (i.e. more than 4) are connected, they can be read with the doc() function in XSLT.
                        // Reading those documents might happen before the whole input document is read, which
                        // is not compatible with our processing model. So in this case, we first read the
                        // data in a SAX store.
                        final SAXStore dataSaxStore = new SAXStore();
                        readInputAsSAX(pipelineContext, INPUT_DATA, dataSaxStore);
                        dataSaxStore.replay(new ForwardingXMLReceiver(transformerHandler, transformerHandler));
                    } else {
                        readInputAsSAX(pipelineContext, INPUT_DATA,
                                new ForwardingXMLReceiver(transformerHandler, transformerHandler));
                    }
                } finally {

                    // Log message from Saxon
                    if (saxonStringBuilderWriter != null) {
                        String message = saxonStringBuilderWriter.toString();
                        if (message.length() > 0)
                            logger.info(message);
                    }

                    // Make sure we don't keep stale references to URI resolver objects
                    transformer.setURIResolver(null);
                    transformerURIResolver.destroy();
                }

                // Check whether some errors were added
                if (errorListener.hasErrors()) {
                    final List errors = errorListener.getErrors();
                    if (errors != null) {
                        ValidationException ve = null;
                        for (Iterator i = errors.iterator(); i.hasNext();) {
                            final LocationData currentLocationData = (LocationData) i.next();

                            if (ve == null)
                                ve = new ValidationException("Errors while executing transformation",
                                        currentLocationData);
                            else
                                ve.addLocationData(currentLocationData);
                        }
                    }
                }
            } catch (Exception e) {

                final Throwable rootCause = Exceptions.getRootThrowable(e);
                if (rootCause instanceof TransformerException) {
                    final TransformerException transformerException = (TransformerException) rootCause;

                    // Add location data of TransformerException if possible
                    final LocationData locationData = (transformerException.getLocator() != null
                            && transformerException.getLocator().getSystemId() != null)
                                    ? new LocationData(transformerException.getLocator())
                                    : (templatesInfo.systemId != null)
                                            ? new LocationData(templatesInfo.systemId, -1, -1)
                                            : null;

                    if (rootCause instanceof TerminationException) {
                        // Saxon-specific exception thrown by xsl:message terminate="yes"
                        final ValidationException customException = new ValidationException(
                                "Processing terminated by xsl:message: " + saxonStringBuilderWriter.toString(),
                                locationData);
                        throw new ValidationException(customException,
                                new ExtendedLocationData(locationData, "executing XSLT transformation"));
                    } else {
                        // Other transformation error
                        throw new ValidationException(rootCause,
                                new ExtendedLocationData(locationData, "executing XSLT transformation"));
                    }
                } else {
                    // Add template location data if possible
                    final LocationData templatesLocationData = (templatesInfo.systemId != null)
                            ? new LocationData(templatesInfo.systemId, -1, -1)
                            : null;
                    throw OrbeonLocationException.wrapException(rootCause,
                            new ExtendedLocationData(templatesLocationData, "executing XSLT transformation"));
                }
            }
        }

        @Override
        protected boolean supportsLocalKeyValidity() {
            return true;
        }

        @Override
        protected CacheKey getLocalKey(PipelineContext context) {
            makeSureStateIsSet(context);

            final KeyValidity configKeyValidity = getInputKeyValidity(context, INPUT_CONFIG);
            URIReferences uriReferences = getURIReferences(context, configKeyValidity);
            if (uriReferences == null || uriReferences.hasDynamicDocumentReferences)
                return null;
            final List<CacheKey> keys = new ArrayList<CacheKey>();
            keys.add(configKeyValidity.key);
            final List<URIReference> allURIReferences = new ArrayList<URIReference>();
            allURIReferences.addAll(uriReferences.stylesheetReferences);
            allURIReferences.addAll(uriReferences.documentReferences);
            for (Iterator<URIReference> i = allURIReferences.iterator(); i.hasNext();) {
                final URIReference uriReference = i.next();
                keys.add(new InternalCacheKey(XSLTTransformer.this, "xsltURLReference",
                        URLFactory.createURL(uriReference.context, uriReference.spec).toExternalForm()));
            }
            return new InternalCacheKey(XSLTTransformer.this, keys);
        }

        @Override
        protected Object getLocalValidity(PipelineContext context) {
            makeSureStateIsSet(context);

            final KeyValidity configKeyValidity = getInputKeyValidity(context, INPUT_CONFIG);
            final URIReferences uriReferences = getURIReferences(context, configKeyValidity);
            if (uriReferences == null || uriReferences.hasDynamicDocumentReferences)
                return null;
            final List validities = new ArrayList();
            validities.add(configKeyValidity.validity);
            final List<URIReference> allURIReferences = new ArrayList<URIReference>();
            allURIReferences.addAll(uriReferences.stylesheetReferences);
            allURIReferences.addAll(uriReferences.documentReferences);
            for (Iterator<URIReference> i = allURIReferences.iterator(); i.hasNext();) {
                final URIReference uriReference = i.next();
                final Processor urlGenerator = new URLGenerator(
                        URLFactory.createURL(uriReference.context, uriReference.spec));
                validities.add(
                        ((ProcessorOutputImpl) urlGenerator.createOutput(OUTPUT_DATA)).getValidity(context));
            }
            return validities;
        }

        private URIReferences getURIReferences(PipelineContext context, KeyValidity configKeyValidity) {
            if (configKeyValidity == null)
                return null;
            return (URIReferences) ObjectCache.instance().findValid(configKeyValidity.key,
                    configKeyValidity.validity);
        }

        private KeyValidity createStyleSheetKeyValidity(PipelineContext context, KeyValidity configKeyValidity,
                URIReferences uriReferences) {
            if (configKeyValidity == null)
                return null;

            final List<CacheKey> keys = new ArrayList<CacheKey>();
            final List<Object> validities = new ArrayList<Object>();
            keys.add(configKeyValidity.key);
            validities.add(configKeyValidity.validity);
            for (Iterator<URIReference> i = uriReferences.stylesheetReferences.iterator(); i.hasNext();) {
                final URIReference uriReference = i.next();
                final URL url = URLFactory.createURL(uriReference.context, uriReference.spec);
                keys.add(new InternalCacheKey(XSLTTransformer.this, "xsltURLReference", url.toExternalForm()));
                final Processor urlGenerator = new URLGenerator(url);
                validities.add(
                        ((ProcessorOutputImpl) urlGenerator.createOutput(OUTPUT_DATA)).getValidity(context));//FIXME: can we do better? See URL generator.
            }

            return new KeyValidity(new InternalCacheKey(XSLTTransformer.this, keys), validities);
        }

        // Create a Saxon Configuration which adds the Orbeon pipeline function library
        private Configuration createXSLTConfiguration() {
            final Configuration newConfiguration = new Configuration();
            final FunctionLibrary javaFunctionLibrary = newConfiguration.getExtensionBinder("java");

            final FunctionLibraryList functionLibraryList = new FunctionLibraryList();
            functionLibraryList.addFunctionLibrary(javaFunctionLibrary);
            functionLibraryList.addFunctionLibrary(org.orbeon.oxf.pipeline.api.FunctionLibrary.instance());

            newConfiguration.setExtensionBinder("java", functionLibraryList);

            return newConfiguration;
        }

        /**
         * Reads the input and creates the JAXP Templates object (wrapped in a Transformer object). While reading
         * the input, figures out the direct dependencies on other files (URIReferences object), and stores these
         * two mappings in cache:
         *
         * configKey        -> uriReferences
         * uriReferencesKey -> transformer
         */
        private TemplatesInfo createTransformer(PipelineContext pipelineContext, String transformerClass,
                Map<String, Boolean> attributes) {
            StringErrorListener errorListener = new StringErrorListener(logger);
            final StylesheetForwardingXMLReceiver topStylesheetXMLReceiver = new StylesheetForwardingXMLReceiver();
            try {
                // Create transformer
                final TemplatesInfo templatesInfo = new TemplatesInfo();
                final List<StylesheetForwardingXMLReceiver> xsltXMLReceivers = new ArrayList<StylesheetForwardingXMLReceiver>();
                {
                    // Create SAXSource adding our forwarding receiver
                    final SAXSource stylesheetSAXSource;
                    {
                        xsltXMLReceivers.add(topStylesheetXMLReceiver);
                        final XMLReader xmlReader = new ProcessorOutputXMLReader(pipelineContext,
                                getInputByName(INPUT_CONFIG).getOutput()) {
                            @Override
                            public void setContentHandler(ContentHandler handler) {
                                super.setContentHandler(new TeeXMLReceiver(Arrays.asList(
                                        topStylesheetXMLReceiver, new SimpleForwardingXMLReceiver(handler))));
                            }
                        };
                        stylesheetSAXSource = new SAXSource(xmlReader, new InputSource());
                    }

                    // Put listener in context that will be called by URI resolved
                    pipelineContext.setAttribute(XSLT_STYLESHEET_URI_LISTENER, new URIResolverListener() {
                        public XMLReceiver getXMLReceiver() {
                            StylesheetForwardingXMLReceiver xmlReceiver = new StylesheetForwardingXMLReceiver();
                            xsltXMLReceivers.add(xmlReceiver);
                            return xmlReceiver;
                        }
                    });
                    final TransformerURIResolver uriResolver = new TransformerURIResolver(XSLTTransformer.this,
                            pipelineContext, INPUT_DATA, XMLUtils.ParserConfiguration.PLAIN);
                    templatesInfo.templates = TransformerUtils.getTemplates(stylesheetSAXSource,
                            transformerClass, attributes, createXSLTConfiguration(), errorListener,
                            uriResolver);
                    uriResolver.destroy();
                    templatesInfo.transformerClass = transformerClass;
                    templatesInfo.systemId = topStylesheetXMLReceiver.getSystemId();
                }

                // Update cache
                {
                    // Create uriReferences
                    URIReferences uriReferences = new URIReferences();
                    for (final StylesheetForwardingXMLReceiver xsltXMLReceiver : xsltXMLReceivers) {
                        uriReferences.hasDynamicDocumentReferences = uriReferences.hasDynamicDocumentReferences
                                || xsltXMLReceiver.getURIReferences().hasDynamicDocumentReferences;
                        uriReferences.stylesheetReferences
                                .addAll(xsltXMLReceiver.getURIReferences().stylesheetReferences);
                        uriReferences.documentReferences
                                .addAll(xsltXMLReceiver.getURIReferences().documentReferences);
                    }

                    // Put in cache: configKey -> uriReferences
                    final KeyValidity configKeyValidity = getInputKeyValidity(pipelineContext, INPUT_CONFIG);
                    if (configKeyValidity != null)
                        ObjectCache.instance().add(configKeyValidity.key, configKeyValidity.validity,
                                uriReferences);

                    // Put in cache: (configKey, uriReferences.stylesheetReferences) -> transformer
                    final KeyValidity stylesheetKeyValidity = createStyleSheetKeyValidity(pipelineContext,
                            configKeyValidity, uriReferences);
                    if (stylesheetKeyValidity != null)
                        ObjectCache.instance().add(stylesheetKeyValidity.key, stylesheetKeyValidity.validity,
                                templatesInfo);
                }

                return templatesInfo;

            } catch (TransformerException e) {
                if (errorListener.hasErrors()) {
                    // Use error messages information and provide location data of first error
                    final ValidationException validationException = new ValidationException(
                            errorListener.getMessages(), errorListener.getErrors().get(0));
                    // If possible add location of top-level stylesheet
                    if (topStylesheetXMLReceiver.getSystemId() != null)
                        validationException.addLocationData(new ExtendedLocationData(
                                new LocationData(topStylesheetXMLReceiver.getSystemId(), -1, -1),
                                "creating XSLT transformer"));
                    throw validationException;
                } else {
                    // No XSLT errors are available
                    final LocationData transformerExceptionLocationData = StringErrorListener
                            .getTransformerExceptionLocationData(e, topStylesheetXMLReceiver.getSystemId());
                    if (transformerExceptionLocationData.getSystemID() != null)
                        throw OrbeonLocationException.wrapException(e, new ExtendedLocationData(
                                transformerExceptionLocationData, "creating XSLT transformer"));
                    else
                        throw new OXFException(e);
                }

                //                    final ExtendedLocationData extendedLocationData
                //                            = StringErrorListener.getTransformerExceptionLocationData(e, topStylesheetContentHandler.getSystemId());
                //
                //                    final ValidationException ve = new ValidationException(e.getMessage() + " " + errorListener.getMessages(), e, extendedLocationData);
                //
                //                    // Append location data gathered from error listener
                //                    if (errorListener.hasErrors()) {
                //                        final List errors = errorListener.getErrors();
                //                        if (errors != null) {
                //                            for (Iterator i = errors.iterator(); i.hasNext();) {
                //                                final LocationData currentLocationData = (LocationData) i.next();
                //                                ve.addLocationData(currentLocationData);
                //                            }
                //                        }
                //                    }
                //                    throw ve;
            } catch (Exception e) {
                if (topStylesheetXMLReceiver.getSystemId() != null) {
                    throw OrbeonLocationException.wrapException(e, new ExtendedLocationData(
                            topStylesheetXMLReceiver.getSystemId(), -1, -1, "creating XSLT transformer"));
                } else {
                    throw new OXFException(e);
                }
            }
        }

    };
    addOutput(name, output);
    return output;
}

From source file:org.orbeon.oxf.transformer.xupdate.TemplatesHandlerImpl.java

License:Open Source License

private Statement[] parseStatements(List nodes) {
    List statements = new ArrayList();
    for (Iterator i = nodes.iterator(); i.hasNext();) {
        Node node = (Node) i.next();
        if (node.getNodeType() == Node.TEXT_NODE) {
            if (!"".equals(node.getText().trim()))
                statements.add(new Text(node.getText().trim()));
        } else if (node.getNodeType() == Node.ELEMENT_NODE) {
            Element element = (Element) node;
            NamespaceContext namespaceContext = new SimpleNamespaceContext(
                    Dom4jUtils.getNamespaceContext(element));
            if (XUpdateConstants.XUPDATE_NAMESPACE_URI.equals(element.getNamespaceURI())) {
                if (element.getName().equals("remove")) {
                    statements.add(new Remove((LocationData) element.getData(),
                            element.attributeValue("select"), namespaceContext));
                } else if (element.getName().equals("update")) {
                    statements/*  www.j ava2 s.c  o  m*/
                            .add(new Update((LocationData) element.getData(), element.attributeValue("select"),
                                    namespaceContext, parseStatements(element.content())));
                } else if (element.getName().equals("append")) {
                    statements.add(new Append((LocationData) element.getData(),
                            element.attributeValue("select"), namespaceContext, element.attributeValue("child"),
                            parseStatements(element.content())));
                } else if (element.getName().equals("insert-before")) {
                    statements.add(
                            new InsertBefore((LocationData) element.getData(), element.attributeValue("select"),
                                    namespaceContext, parseStatements(element.content())));
                } else if (element.getName().equals("insert-after")) {
                    statements.add(
                            new InsertAfter((LocationData) element.getData(), element.attributeValue("select"),
                                    namespaceContext, parseStatements(element.content())));
                } else if (element.getName().equals("for-each")) {
                    statements
                            .add(new ForEach((LocationData) element.getData(), element.attributeValue("select"),
                                    namespaceContext, parseStatements(element.content())));
                } else if (element.getName().equals("while")) {
                    statements.add(new While((LocationData) element.getData(), element.attributeValue("select"),
                            namespaceContext, parseStatements(element.content())));
                } else if (element.getName().equals("value-of")) {
                    statements.add(new ValueOf((LocationData) element.getData(),
                            element.attributeValue("select"), namespaceContext));
                } else if (element.getName().equals("copy-of")) {
                    statements.add(new CopyOf((LocationData) element.getData(),
                            element.attributeValue("select"), namespaceContext));
                } else if (element.getName().equals("node-set")) {
                    statements.add(new NodeSet((LocationData) element.getData(),
                            element.attributeValue("select"), namespaceContext));
                } else if (element.getName().equals("attribute")) {
                    statements.add(new Attribute((LocationData) element.getData(), parseQName(element),
                            parseStatements(element.content())));
                } else if (element.getName().equals("namespace")) {
                    statements.add(new Namespace((LocationData) element.getData(),
                            element.attributeValue("name"), element.attributeValue("select"), namespaceContext,
                            parseStatements(element.content())));
                } else if (element.getName().equals("element")) {
                    statements.add(new DynamicElement((LocationData) element.getData(), parseQName(element),
                            parseStatements(element.content())));
                } else if (element.getName().equals("if")) {
                    statements.add(new If((LocationData) element.getData(), element.attributeValue("test"),
                            namespaceContext, parseStatements(element.content())));
                } else if (element.getName().equals("choose")) {
                    List whenTests = new ArrayList();
                    List whenNamespaceContext = new ArrayList();
                    List whenStatements = new ArrayList();
                    for (Iterator j = element.elements("when").iterator(); j.hasNext();) {
                        Element whenElement = (Element) j.next();
                        whenTests.add(whenElement.attributeValue("test"));
                        whenNamespaceContext
                                .add(new SimpleNamespaceContext(Dom4jUtils.getNamespaceContext(whenElement)));
                        whenStatements.add(parseStatements(whenElement.content()));
                    }
                    Element otherwiseElement = element.element("otherwise");
                    statements.add(new Choose((LocationData) element.getData(),
                            (String[]) whenTests.toArray(new String[whenTests.size()]),
                            (NamespaceContext[]) whenNamespaceContext
                                    .toArray(new NamespaceContext[whenNamespaceContext.size()]),
                            (Statement[][]) whenStatements.toArray(new Statement[whenStatements.size()][]),
                            otherwiseElement == null ? null : parseStatements(otherwiseElement.content())));
                } else if (element.getName().equals("variable")) {
                    statements.add(new Variable((LocationData) element.getData(), parseQName(element),
                            element.attributeValue("select"), namespaceContext,
                            parseStatements(element.content())));
                } else if (element.getName().equals("assign")) {
                    statements.add(new Assign((LocationData) element.getData(), parseQName(element),
                            element.attributeValue("select"), namespaceContext,
                            parseStatements(element.content())));
                } else if (element.getName().equals("function")) {
                    statements.add(new Function((LocationData) element.getData(), parseQName(element),
                            parseStatements(element.content())));
                } else if (element.getName().equals("param")) {
                    statements.add(new Param((LocationData) element.getData(), parseQName(element),
                            element.attributeValue("select"), namespaceContext,
                            parseStatements(element.content())));
                } else if (element.getName().equals("message")) {
                    statements.add(
                            new Message((LocationData) element.getData(), parseStatements(element.content())));
                } else if (element.getName().equals("error")) {
                    statements.add(
                            new Error((LocationData) element.getData(), parseStatements(element.content())));
                } else {
                    throw new ValidationException(
                            "Unsupported XUpdate element '" + element.getQualifiedName() + "'",
                            (LocationData) element.getData());
                }
            } else {
                Element staticElement = new NonLazyUserDataElement(element.getQName());
                List childNodes = new ArrayList();
                for (Iterator j = element.attributes().iterator(); j.hasNext();)
                    staticElement.add((org.dom4j.Attribute) ((org.dom4j.Attribute) j.next()).clone());
                for (Iterator j = element.content().iterator(); j.hasNext();) {
                    Node child = (Node) j.next();
                    if (child instanceof org.dom4j.Namespace) {
                        staticElement.add((Node) child.clone());
                    } else {
                        childNodes.add(child);
                    }
                }
                statements.add(new StaticElement((LocationData) element.getData(), staticElement,
                        parseStatements(childNodes)));
            }
        } else if (node.getNodeType() == Node.NAMESPACE_NODE) {
            // Ignore namespace declarations
        } else {
            throw new OXFException("Unsupported node: " + node.getNodeTypeName());
        }
    }
    return (Statement[]) statements.toArray(new Statement[statements.size()]);
}

From source file:org.orbeon.oxf.xforms.action.actions.XFormsInsertAction.java

License:Open Source License

public static List<NodeInfo> doInsert(XFormsContainingDocument containingDocument,
        IndentedLogger indentedLogger, String positionAttribute, List collectionToBeUpdated,
        NodeInfo insertContextNodeInfo, List<Item> originItems, int insertionIndex, boolean doClone,
        boolean doDispatch) {

    final boolean isEmptyNodesetBinding = collectionToBeUpdated == null || collectionToBeUpdated.size() == 0;

    // "3. The origin node-set is determined."
    // "5. Each node in the origin node-set is cloned in the order it appears in the origin node-set."
    final List<Node> sourceNodes;
    final List<Node> clonedNodes;
    {/*from   w ww . java  2  s.  c om*/
        final List<Node> clonedNodesTemp;
        if (originItems == null) {
            // There are no explicitly specified origin objects, use node from Node Set Binding node-set

            // "If the origin attribute is not given and the Node Set Binding node-set is empty, then the origin
            // node-set is the empty node-set. [...] The insert action is terminated with no effect if the
            // origin node-set is the empty node-set."

            if (isEmptyNodesetBinding) {
                if (indentedLogger != null && indentedLogger.isDebugEnabled())
                    indentedLogger.logDebug("xf:insert",
                            "origin node-set from node-set binding is empty, terminating");
                return Collections.EMPTY_LIST;
            }

            // "Otherwise, if the origin attribute is not given, then the origin node-set consists of the last
            // node of the Node Set Binding node-set."
            final Node singleSourceNode = XFormsUtils.getNodeFromNodeInfoConvert(
                    (NodeInfo) collectionToBeUpdated.get(collectionToBeUpdated.size() - 1));
            // TODO: check namespace handling might be incorrect. Should use copyElementCopyParentNamespaces() instead?
            final Node singleClonedNode = Dom4jUtils.createCopy(singleSourceNode);

            sourceNodes = Collections.singletonList(singleSourceNode);
            clonedNodesTemp = Collections.singletonList(singleClonedNode);
        } else {
            // There are explicitly specified origin objects

            // "The insert action is terminated with no effect if the origin node-set is the empty node-set."
            if (originItems.size() == 0) {
                if (indentedLogger != null && indentedLogger.isDebugEnabled())
                    indentedLogger.logDebug("xf:insert", "origin node-set is empty, terminating");
                return Collections.EMPTY_LIST;
            }

            // "Each node in the origin node-set is cloned in the order it appears in the origin node-set."

            sourceNodes = new ArrayList<Node>(originItems.size()); // set to max possible size
            clonedNodesTemp = new ArrayList<Node>(originItems.size());

            for (final Object currentObject : originItems) {
                if (currentObject instanceof NodeInfo) {
                    // This is the regular case covered by XForms 1.1 / XPath 1.0

                    // NOTE: Don't clone nodes if doClone == false
                    final Node sourceNode = XFormsUtils.getNodeFromNodeInfoConvert((NodeInfo) currentObject);
                    final Node clonedNode = doClone
                            ? (sourceNode instanceof Element) ? ((Element) sourceNode).createCopy()
                                    : (Node) sourceNode.clone()
                            : sourceNode;

                    sourceNodes.add(sourceNode);
                    clonedNodesTemp.add(clonedNode);

                } else if (currentObject instanceof AtomicValue) {
                    // This is an extension: support sequences containing atomic values

                    // Convert the result to a text node
                    final String stringValue = ((Item) currentObject).getStringValue();
                    final Text textNode = Dom4jUtils.createText(stringValue);

                    sourceNodes.add(null); // there is no source node for this cloned node, it's a source item
                    clonedNodesTemp.add(textNode);
                } else
                    throw new IllegalStateException();
            }
        }

        // Remove instance data from cloned nodes and perform Document node adjustment
        for (int i = 0; i < clonedNodesTemp.size(); i++) {
            final Node clonedNodeTemp = clonedNodesTemp.get(i);

            if (clonedNodeTemp instanceof Element) {
                // Element node
                InstanceData.remove(clonedNodeTemp);
                clonedNodeTemp.detach();
            } else if (clonedNodeTemp instanceof Attribute) {
                // Attribute node
                InstanceData.remove(clonedNodeTemp);
                clonedNodeTemp.detach();
            } else if (clonedNodeTemp instanceof Document) {
                // Document node
                final Element clonedNodeTempRootElement = clonedNodeTemp.getDocument().getRootElement();

                if (clonedNodeTempRootElement == null) {
                    // Can be null in rare cases of documents without root element
                    clonedNodesTemp.set(i, null); // we support having a null node further below, so set this to null
                } else {
                    InstanceData.remove(clonedNodeTempRootElement);
                    // We can never really insert a document into anything at this point, but we assume that this means the root element
                    clonedNodesTemp.set(i, clonedNodeTempRootElement.detach());
                }
            } else {
                // Other nodes
                clonedNodeTemp.detach();
            }
        }
        clonedNodes = clonedNodesTemp;
    }

    // "6. The target location of each cloned node or nodes is determined"
    // "7. The cloned node or nodes are inserted in the order they were cloned at their target location
    // depending on their node type."

    // Identify the instance that actually changes
    final XFormsInstance modifiedInstance;
    // Find actual insertion point and insert
    final NodeInfo insertLocationNodeInfo;
    final List<Node> insertedNodes;
    final String beforeAfterInto;
    if (isEmptyNodesetBinding) {
        // Insert INTO a node

        // "If the Node Set Binding node-set is not specified or empty, the insert location node is the insert
        // context node."

        // "a. If the Node Set Binding node-set is not specified or empty, the target location depends on the
        // node type of the cloned node. If the cloned node is an attribute, then the target location is before
        // the first attribute of the insert location node. If the cloned node is not an attribute, then the
        // target location is before the first child of the insert location node."

        modifiedInstance = (containingDocument != null)
                ? containingDocument.getInstanceForNode(insertContextNodeInfo)
                : null;
        insertLocationNodeInfo = insertContextNodeInfo;
        final Node insertLocationNode = XFormsUtils.getNodeFromNodeInfo(insertContextNodeInfo,
                CANNOT_INSERT_READONLY_MESSAGE);
        insertedNodes = doInsert(insertLocationNode, clonedNodes, modifiedInstance, doDispatch);
        beforeAfterInto = "into";

        // Normalize text nodes if needed to respect XPath 1.0 constraint
        {
            boolean hasTextNode = false;
            for (Node clonedNode : clonedNodes) {
                hasTextNode |= clonedNode != null && clonedNode.getNodeType() == Node.TEXT_NODE;
            }
            if (hasTextNode)
                Dom4jUtils.normalizeTextNodes(insertLocationNode);
        }
    } else {
        // Insert BEFORE or AFTER a node
        insertLocationNodeInfo = (NodeInfo) collectionToBeUpdated.get(insertionIndex - 1);
        final Node insertLocationNode = XFormsUtils.getNodeFromNodeInfo(insertLocationNodeInfo,
                CANNOT_INSERT_READONLY_MESSAGE);
        modifiedInstance = (containingDocument != null)
                ? containingDocument.getInstanceForNode(insertLocationNodeInfo)
                : null;

        final Document insertLocationNodeDocument = insertLocationNode.getDocument();
        if (insertLocationNodeDocument != null
                && insertLocationNodeDocument.getRootElement() == insertLocationNode) {

            // "c. if insert location node is the root element of an instance, then that instance root element
            // location is the target location. If there is more than one cloned node to insert, only the
            // first node that does not cause a conflict is considered."

            insertedNodes = doInsert(insertLocationNode.getDocument(), clonedNodes, modifiedInstance,
                    doDispatch);
            beforeAfterInto = positionAttribute; // TODO: ideally normalize to "into document node"?

            // NOTE: Don't need to normalize text nodes in this case, as no new text node is inserted
        } else {
            // "d. Otherwise, the target location is immediately before or after the insert location
            // node, based on the position attribute setting or its default."

            if (insertLocationNode.getNodeType() == Node.ATTRIBUTE_NODE) {
                // Special case for "next to an attribute"

                // NOTE: In XML, attributes are unordered. dom4j handles them as a list so has order, but
                // the XForms spec shouldn't rely on attribute order. We could try to keep the order, but it
                // is harder as we have to deal with removing duplicate attributes and find a reasonable
                // insertion strategy.

                // TODO: Don't think we should even do this now in XForms 1.1
                insertedNodes = doInsert(insertLocationNode.getParent(), clonedNodes, modifiedInstance,
                        doDispatch);

            } else {
                // Other node types
                final Element parentNode = insertLocationNode.getParent();
                final List<Node> siblingElements = Dom4jUtils.content(parentNode);
                final int actualIndex = siblingElements.indexOf(insertLocationNode);

                // Prepare insertion of new element
                final int actualInsertionIndex;
                if ("before".equals(positionAttribute)) {
                    actualInsertionIndex = actualIndex;
                } else {
                    // "after"
                    actualInsertionIndex = actualIndex + 1;
                }

                // "7. The cloned node or nodes are inserted in the order they were cloned at their target
                // location depending on their node type."

                boolean hasTextNode = false;
                int addIndex = 0;
                insertedNodes = new ArrayList<Node>(clonedNodes.size());
                for (Node clonedNode : clonedNodes) {

                    if (clonedNode != null) {// NOTE: we allow passing some null nodes so we check on null
                        if (!(clonedNode instanceof Attribute || clonedNode instanceof Namespace)) {
                            // Element, text, comment, processing instruction node
                            siblingElements.add(actualInsertionIndex + addIndex, clonedNode);
                            insertedNodes.add(clonedNode);
                            hasTextNode |= clonedNode.getNodeType() == Node.TEXT_NODE;
                            addIndex++;
                        } else {
                            // We never insert attributes or namespace nodes as siblings
                            if (indentedLogger != null && indentedLogger.isDebugEnabled())
                                indentedLogger.logDebug("xf:insert",
                                        "skipping insertion of node as sibling in element content", "type",
                                        clonedNode.getNodeTypeName(), "node",
                                        clonedNode instanceof Attribute
                                                ? Dom4jUtils.attributeToDebugString((Attribute) clonedNode)
                                                : clonedNode.toString());
                        }
                    }
                }

                // Normalize text nodes if needed to respect XPath 1.0 constraint
                if (hasTextNode)
                    Dom4jUtils.normalizeTextNodes(parentNode);
            }

            beforeAfterInto = positionAttribute;
        }
    }

    // Whether some nodes were inserted
    final boolean didInsertNodes = insertedNodes != null && insertedNodes.size() > 0;

    // Log stuff
    if (indentedLogger != null && indentedLogger.isDebugEnabled()) {
        if (didInsertNodes)
            indentedLogger.logDebug("xf:insert", "inserted nodes", "count",
                    Integer.toString(insertedNodes.size()), "instance",
                    (modifiedInstance != null) ? modifiedInstance.getEffectiveId() : null);
        else
            indentedLogger.logDebug("xf:insert", "no node inserted");
    }

    // "XForms Actions that change the tree structure of instance data result in setting all four flags to true"
    if (didInsertNodes && modifiedInstance != null) {
        // NOTE: Can be null if document into which delete is performed is not in an instance, e.g. in a variable
        modifiedInstance.markModified();
        modifiedInstance.model().markStructuralChange(modifiedInstance);
    }

    // Gather list of modified nodes
    final List<NodeInfo> insertedNodeInfos;
    if (didInsertNodes && modifiedInstance != null) {
        // Can be null if document into which delete is performed is not in an instance, e.g. in a variable
        final DocumentWrapper documentWrapper = (DocumentWrapper) modifiedInstance.documentInfo();
        insertedNodeInfos = new ArrayList<NodeInfo>(insertedNodes.size());
        for (Object insertedNode : insertedNodes)
            insertedNodeInfos.add(documentWrapper.wrap(insertedNode));
    } else {
        insertedNodeInfos = Collections.emptyList();
    }

    // "4. If the insert is successful, the event xforms-insert is dispatched."
    // XFormsInstance handles index and repeat items updates 
    if (doDispatch && didInsertNodes && modifiedInstance != null) {

        // Adjust insert location node and before/after/into in case the root element was replaced
        final NodeInfo adjustedInsertLocationNodeInfo;
        final String adjustedBeforeAfterInto;

        final NodeInfo parent = insertedNodeInfos.get(0).getNodeKind() == org.w3c.dom.Node.ELEMENT_NODE
                ? insertedNodeInfos.get(0).getParent()
                : null;
        if (parent != null && parent.equals(parent.getDocumentRoot())) {
            // Node was inserted under document node
            adjustedInsertLocationNodeInfo = parent.getDocumentRoot();
            adjustedBeforeAfterInto = "into";
        } else {
            adjustedInsertLocationNodeInfo = insertLocationNodeInfo;
            adjustedBeforeAfterInto = beforeAfterInto;
        }

        Dispatch.dispatchEvent(new XFormsInsertEvent(modifiedInstance, insertedNodeInfos, originItems,
                adjustedInsertLocationNodeInfo, adjustedBeforeAfterInto));
    }

    return insertedNodeInfos;
}

From source file:org.orbeon.oxf.xforms.function.xxforms.XXFormsCallXPL.java

License:Open Source License

public SequenceIterator iterate(XPathContext xpathContext) throws XPathException {

    try {//ww w.j  a  va2  s  . co  m
        // Get XPL URL
        final URL xplURL;
        {
            Expression xplURIExpression = argument[0];
            //xplURL = new URL(((AnyURIValue) xplURIExpression.evaluateItem(xpathContext)).getStringValue());
            if (getSystemId() == null)
                xplURL = URLFactory.createURL(xplURIExpression.evaluateAsString(xpathContext).toString());
            else
                xplURL = URLFactory.createURL(getSystemId(),
                        xplURIExpression.evaluateAsString(xpathContext).toString());
        }

        // Get list of input names
        final List<String> inputNames = new ArrayList<String>();
        {
            final Expression inputNamesExpression = argument[1];
            final SequenceIterator i = inputNamesExpression.iterate(xpathContext);

            Item currentItem;
            while ((currentItem = i.next()) != null) {
                inputNames.add(currentItem.getStringValue());
            }
        }

        // Get list of input documents
        final List<Item> inputNodeInfos = new ArrayList<Item>();
        {
            final Expression inputDocumentsExpression = argument[2];
            final SequenceIterator i = inputDocumentsExpression.iterate(xpathContext);

            Item currentItem;
            while ((currentItem = i.next()) != null) {
                inputNodeInfos.add(currentItem);
            }
        }

        if (inputNames.size() != inputNodeInfos.size())
            throw new OXFException("The length of sequence of input names (" + inputNames.size()
                    + ") must be equal to the length of the sequence of input nodes (" + inputNodeInfos.size()
                    + ").");//getDisplayName()

        // Get list of output names
        final List<String> outputNames = new ArrayList<String>();
        {
            final Expression inputNamesExpression = argument[3];
            final SequenceIterator i = inputNamesExpression.iterate(xpathContext);

            Item currentItem;
            while ((currentItem = i.next()) != null) {
                outputNames.add(currentItem.getStringValue());
            }
        }

        // Create processor definition and processor
        Processor processor;
        {
            ProcessorDefinition processorDefinition = new ProcessorDefinition();
            {
                processorDefinition.setName(new QName("pipeline", XMLConstants.OXF_PROCESSORS_NAMESPACE));
                processorDefinition.addInput("config", xplURL.toExternalForm());

                Iterator inputNodesIterator = inputNodeInfos.iterator();
                for (final String inputName : inputNames) {
                    final NodeInfo inputNodeInfo = (NodeInfo) inputNodesIterator.next();

                    if (!(inputNodeInfo.getNodeKind() == org.w3c.dom.Node.ELEMENT_NODE
                            || inputNodeInfo.getNodeKind() == org.w3c.dom.Node.DOCUMENT_NODE))
                        throw new OXFException(
                                "Input node must be a document or element for input name: " + inputName);

                    // TODO: We should be able to just pass inputNodeInfo to addInput() and avoid the conversions, but that doesn't work!

                    if (inputNodeInfo instanceof VirtualNode) {
                        // Get reference to dom4j node

                        final Element inputElement;
                        final Node inputNode = (Node) ((VirtualNode) inputNodeInfo).getUnderlyingNode();

                        if (inputNode instanceof Document)
                            inputElement = ((Document) inputNode).getRootElement();
                        else if (inputNode instanceof Element && inputNode.getParent() == null)
                            inputElement = (Element) inputNode;
                        else if (inputNode instanceof Element)
                            inputElement = Dom4jUtils.createDocumentCopyParentNamespaces((Element) inputNode)
                                    .getRootElement();
                        else
                            throw new OXFException(
                                    "Input node must be a document or element for input name: " + inputName);

                        processorDefinition.addInput(inputName, inputElement);
                    } else {
                        // Copy to dom4j

                        //                            final DocumentInfo inputDocumentInfo = TransformerUtils.readTinyTree(inputNodeInfo);
                        //                            processorDefinition.addInput(inputName, inputDocumentInfo);

                        final Document inputDocument = TransformerUtils.tinyTreeToDom4j(inputNodeInfo);
                        processorDefinition.addInput(inputName, inputDocument.getRootElement());
                    }
                }
            }
            processor = InitUtils.createProcessor(processorDefinition);
        }

        final PipelineContext pipelineContext = PipelineContext.get();
        processor.reset(pipelineContext);

        if (outputNames.size() == 0) {
            // Just run the processor
            processor.start(pipelineContext);
            return EmptyIterator.getInstance();
        } else {
            // Create all outputs to read
            List<ProcessorOutput> outputs = new ArrayList<ProcessorOutput>(outputNames.size());
            for (String outputName : outputNames) {
                ProcessorOutput output = processor.createOutput(outputName);
                outputs.add(output);
            }

            // Connect all DOM serializers
            List<DOMSerializer> domSerializers = new ArrayList<DOMSerializer>(outputNames.size());
            for (ProcessorOutput output : outputs) {
                DOMSerializer domSerializer = new DOMSerializer();
                PipelineUtils.connect(processor, output.getName(), domSerializer, "data");
                domSerializers.add(domSerializer);
            }

            // Read all outputs in sequence
            List<DocumentWrapper> results = new ArrayList<DocumentWrapper>(outputNames.size());
            for (DOMSerializer domSerializer : domSerializers) {
                results.add(new DocumentWrapper(
                        (Document) Dom4jUtils.normalizeTextNodes(domSerializer.runGetDocument(pipelineContext)),
                        null, xpathContext.getConfiguration()));
            }
            return new ListIterator(results);
        }
    } catch (XPathException e) {
        throw e;
    } catch (Exception e) {
        throw new OXFException(e);
    }
}

From source file:org.orbeon.oxf.xforms.InstanceData.java

License:Open Source License

public static QName getType(NodeInfo nodeInfo) {

    // Try schema or bind type
    final InstanceData existingInstanceData = getLocalInstanceData(nodeInfo, false);
    if (existingInstanceData != null) {
        final QName schemaOrBindType = existingInstanceData.getSchemaOrBindType();
        if (schemaOrBindType != null)
            return schemaOrBindType;
    }//from  ww  w .  j a va 2  s .  c o m

    // No type was assigned by schema or MIP, try xsi:type
    if (nodeInfo.getNodeKind() == org.w3c.dom.Node.ELEMENT_NODE) {
        // Check for xsi:type attribute
        // NOTE: Saxon 9 has new code to resolve such QNames
        final String typeQName = nodeInfo.getAttributeValue(StandardNames.XSI_TYPE);
        if (typeQName != null) {
            try {
                final NameChecker checker = nodeInfo.getConfiguration().getNameChecker();
                final String[] parts = checker.getQNameParts(typeQName);

                // No prefix
                if (parts[0].equals("")) {
                    return QName.get(parts[1]);
                }

                // There is a prefix, resolve it
                final SequenceIterator namespaceNodes = nodeInfo.iterateAxis(Axis.NAMESPACE);
                while (true) {
                    final NodeInfo currentNamespaceNode = (NodeInfo) namespaceNodes.next();
                    if (currentNamespaceNode == null) {
                        break;
                    }
                    final String prefix = currentNamespaceNode.getLocalPart();
                    if (prefix.equals(parts[0])) {
                        return QName.get(parts[1], "", currentNamespaceNode.getStringValue());
                    }
                }
            } catch (Exception e) {
                throw new OXFException(e);
            }
        }
    }

    return null;
}

From source file:org.orbeon.oxf.xforms.submission.XFormsModelSubmission.java

License:Open Source License

public NodeInfo evaluateTargetRef(XPathCache.XPathContext xpathContext, XFormsInstance defaultReplaceInstance,
        Item submissionElementContextItem) {
    final Object destinationObject;
    if (targetref == null) {
        // There is no explicit @targetref, so the target is implicitly the root element of either the instance
        // pointed to by @ref, or the instance specified by @instance or @xxf:instance.
        destinationObject = defaultReplaceInstance.rootElement();
    } else {//from w w w.  ja  v  a  2 s.  co  m
        // There is an explicit @targetref, which must be evaluated.

        // "The in-scope evaluation context of the submission element is used to evaluate the expression." BUT ALSO "The
        // evaluation context for this attribute is the in-scope evaluation context for the submission element, except
        // the context node is modified to be the document element of the instance identified by the instance attribute
        // if it is specified."
        final boolean hasInstanceAttribute = xxfReplaceInstanceId != null || replaceInstanceId != null;
        final Item targetRefContextItem = hasInstanceAttribute ? defaultReplaceInstance.rootElement()
                : submissionElementContextItem;

        // Evaluate destination node
        // "This attribute is evaluated only once a successful submission response has been received and if the replace
        // attribute value is "instance" or "text". The first node rule is applied to the result."
        destinationObject = XPathCache.evaluateSingle(xpathContext, targetRefContextItem, targetref,
                containingDocument().getRequestStats().getReporter());
    }

    // TODO: Also detect readonly node/ancestor situation
    if (destinationObject instanceof NodeInfo
            && ((NodeInfo) destinationObject).getNodeKind() == org.w3c.dom.Node.ELEMENT_NODE)
        return (NodeInfo) destinationObject;
    else
        return null;
}

From source file:org.orbeon.oxf.xforms.submission.XFormsModelSubmission.java

License:Open Source License

private Document reRootAndPrune(final NodeInfo currentNodeInfo, boolean resolvedRelevant,
        String resolvedAnnotate) {

    final Document documentToSubmit;
    if (currentNodeInfo instanceof VirtualNode) {
        final Node currentNode = (Node) ((VirtualNode) currentNodeInfo).getUnderlyingNode();

        // "A node from the instance data is selected, based on attributes on the submission
        // element. The indicated node and all nodes for which it is an ancestor are considered for
        // the remainder of the submit process. "
        if (currentNode instanceof Element) {
            // Create subset of document
            documentToSubmit = Dom4jUtils.createDocumentCopyParentNamespaces((Element) currentNode);
        } else {//from  www .ja  va2 s  .  co  m
            // Use entire instance document
            documentToSubmit = Dom4jUtils.createDocumentCopyElement(currentNode.getDocument().getRootElement());
        }

        if (resolvedRelevant) {
            // "Any node which is considered not relevant as defined in 6.1.4 is removed."
            final Node[] nodeToDetach = new Node[1];
            do {
                // NOTE: This is not very efficient, but at least we avoid NPEs that we would get by
                // detaching elements within accept(). Should implement a more efficient algorithm to
                // prune non-relevant nodes.
                nodeToDetach[0] = null;
                documentToSubmit.accept(new VisitorSupport() {

                    public final void visit(Element element) {
                        checkInstanceData(element);
                    }

                    public final void visit(Attribute attribute) {
                        checkInstanceData(attribute);
                    }

                    private void checkInstanceData(Node node) {
                        if (nodeToDetach[0] == null) {
                            // Check "relevant" MIP and remove non-relevant nodes
                            if (!InstanceData.getInheritedRelevant(node))
                                nodeToDetach[0] = node;
                        }
                    }
                });
                if (nodeToDetach[0] != null)
                    nodeToDetach[0].detach();

            } while (nodeToDetach[0] != null);
        }

        // Annotate with alerts if needed
        if (StringUtils.isNotBlank(resolvedAnnotate))
            annotateWithAlerts(containingDocument, documentToSubmit, resolvedAnnotate);

        // TODO: handle includenamespaceprefixes
    } else {
        // Submitting read-only instance backed by TinyTree (no MIPs to check)
        if (currentNodeInfo.getNodeKind() == org.w3c.dom.Node.ELEMENT_NODE) {
            documentToSubmit = TransformerUtils.tinyTreeToDom4j(currentNodeInfo);
        } else {
            documentToSubmit = TransformerUtils.tinyTreeToDom4j(currentNodeInfo.getRoot());
        }
    }
    return documentToSubmit;
}

From source file:org.orbeon.oxf.xml.dom4j.Dom4jUtils.java

License:Open Source License

/**
 * Convert a dom4j node to a string./*from w  w w  .  ja  va 2s .  c om*/
 *
 * @param node  node to convert
 * @return      resulting string
 */
public static String nodeToString(final Node node) {
    final String ret;
    switch (node.getNodeType()) {
    case Node.DOCUMENT_NODE: {
        ret = domToString((Branch) ((Document) node).getRootElement());
        break;
    }
    case Node.ELEMENT_NODE: {
        ret = domToString((Branch) node);
        break;
    }
    case Node.TEXT_NODE: {
        ret = node.getText();
        break;
    }
    default:
        ret = domToString(node, null);
        break;
    }
    return ret;
}