List of usage examples for org.dom4j Node ELEMENT_NODE
short ELEMENT_NODE
To view the source code for org.dom4j Node ELEMENT_NODE.
Click Source Link
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; }