cocoon-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Suzan Foster <suzan.fos...@nerocmediaware.nl>
Subject Re: How to return xml from a flowscript?
Date Fri, 06 Jan 2006 16:39:17 GMT
The problem however with using variables is that eXist can only operate 
on it's own persistent DOM implementation within the query. You need to 
create a temporary document to pass to the XQuery. I hit this problem 
when writing an extension function for processing the request as XML 
(sent by an XForm) and wrote the following implementation:

package com.nps.xquery.request;

import org.exist.dom.QName;
import org.exist.http.servlets.RequestWrapper;
import org.exist.xquery.functions.request.RequestModule;
import org.exist.xquery.XQueryContext;
import org.exist.xquery.BasicFunction;
import org.exist.xquery.Cardinality;
import org.exist.xquery.FunctionSignature;
import org.exist.xquery.XPathException;
import org.exist.xquery.Variable;
import org.exist.xquery.value.Sequence;
import org.exist.xquery.value.SequenceType;
import org.exist.xquery.value.Type;
import org.exist.xquery.value.JavaObjectValue;
import org.exist.dom.NodeProxy;
import org.exist.dom.DocumentImpl;
import org.exist.dom.NodeImpl;
import org.exist.memtree.MemTreeBuilder;
import org.exist.memtree.DocumentBuilderReceiver;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;

public class DocFunction extends BasicFunction {

    public final static FunctionSignature signature =
        new FunctionSignature(
            new QName("doc", Module.NAMESPACE_URI, Module.PREFIX),
            "",
            null,
            new SequenceType(Type.NODE, Cardinality.ZERO_OR_ONE)
        );
   
    public DocFunction(XQueryContext context) {
        super(context, signature);
    }

    public Sequence eval(Sequence[] arg0, Sequence arg1) throws 
XPathException {
        RequestModule requestModule =
            (RequestModule) context.getModule(RequestModule.NAMESPACE_URI);

        // request object is read from global variable $request
        Variable var = 
requestModule.resolveVariable(RequestModule.REQUEST_VAR);
        if(var == null)
            throw new XPathException("No request object found in the 
current XQuery context.");
        if (var.getValue().getItemType() != Type.JAVA_OBJECT)
            throw new XPathException("Variable $request is not bound to 
a Java object.");
        JavaObjectValue value = (JavaObjectValue) var.getValue().itemAt(0);
        if (value.getObject() instanceof RequestWrapper) {
            RequestWrapper request = (RequestWrapper)value.getObject();
            try {
                MemTreeBuilder builder = context.getDocumentBuilder();
                DocumentBuilderReceiver receiver = new 
DocumentBuilderReceiver(builder);
                SAXParserFactory factory = SAXParserFactory.newInstance();
                factory.setNamespaceAware(true);
                XMLReader reader = factory.newSAXParser().getXMLReader();
                reader.setContentHandler(receiver);
                reader.parse(new InputSource(request.getInputStream()));
                DocumentImpl doc = 
context.storeTemporaryDoc(builder.getDocument());
                NodeImpl node = 
(NodeImpl)doc.getDocumentElement().getFirstChild();
                return new NodeProxy(doc, node.getGID(), 
node.getInternalAddress());
            }
            catch (Exception e) {
                throw new XPathException(getASTNode(), e.getMessage(), e);
            }
        } else
            throw new XPathException("Variable $request is not bound to 
a Request object.");       
    }
}

I think it should be possible to use such a temporary document as 
context for the XQuery using XQueryService.query(XMLResource,  String).

Jean-Baptiste Quenot wrote:

>* Jonas Lundberg:
>
>  
>
>>That might work, but it is  not a good solution for me, although
>>it might work in other cases. My xqueries are very complex.  But
>>this can't end here, can it? Is there really no way of returning
>>XML in a parameter from a flowscript in Cocoon?
>>    
>>
>
>Sitemap parameters  are Strings, not  Objects.  You cannot  pass a
>DOM.  However you can execute an XQuery without the
>XQueryGenerator, Java snippet follows:
>
>        public static Node executeXQuery(Collection collection, Source inputSource, Map
variables, Logger logger) throws XMLDBException {
>                XQueryService service = (XQueryService) collection.getService(
>                                "XQueryService", "1.0");
>                service.setProperty(Serializer.GENERATE_DOC_EVENTS, "false");
>                if (variables != null) {
>                        if (logger != null) logger.debug("Executing " + inputSource.getURI()
+ " with variables " + variables);
>                        Iterator it = variables.entrySet().iterator();
>                        while (it.hasNext()) {
>                                Map.Entry entry = (Map.Entry)it.next();
>                                service.declareVariable((String)entry.getKey(), entry.getValue());
>                        }
>                } else {
>                        if (logger != null) logger.debug("Executing " + inputSource.getURI());
>                }
>                ResourceSet result = service.execute(new CocoonSource(inputSource, true));
>                if (result == null) {
>                        if (logger != null) logger.error("null result after executing
XQuery!");
>                        return null; // a DOM Node cannot be null so null can be used
safely for signaling errors
>                }
>                if (result.getSize() == 0) {
>                        if (logger != null) logger.error("empty XML result after executing
XQuery!");
>                        return null; // a DOM Node cannot be null so null can be used
safely for signaling errors
>                }
>                XMLResource resource = (XMLResource) result.getResource(0);
>                return resource.getContentAsDOM();
>        }
>
>But I think the best solution in order to save directly an XML
>document in the XML database is to use the XMLDBSource with
>saveDocumentToSource("xmldb:exist://localhost:8080/exist/xmlrpc/db/file.xml", document),
>FlowScript snippet follows:
>
>/*
> * Save XML document to source.
> * Parameters :
> *   outputMode : the desired output mode : 'html', 'xml', or 'text'
> *                Defaults to "xml"
> */
>function saveDocumentToSource(source, document, outputMode ) {
>        var tf = Packages.javax.xml.transform.TransformerFactory.newInstance();
>        var outputStream = null;
>
>        // If no mode is specified, we use XML
>        if(! outputMode) {
>                outputMode = 'xml';
>        }
>
>        try {
>                if (source instanceof Packages.org.apache.excalibur.source.ModifiableSource
>                        && tf.getFeature(Packages.javax.xml.transform.sax.SAXTransformerFactory.FEATURE))
{
>            outputStream = source.getOutputStream();
>                var transformer = tf.newTransformer();
>            transformer.setOutputProperty(Packages.javax.xml.transform.OutputKeys.INDENT,
"yes");
>            transformer.setOutputProperty(Packages.javax.xml.transform.OutputKeys.METHOD,
outputMode);
>                transformer.transform(
>                     new Packages.javax.xml.transform.dom.DOMSource(document),
>                         new Packages.javax.xml.transform.stream.StreamResult(outputStream));
>                } else {
>                        throw new Packages.org.apache.cocoon.ProcessingException("Cannot
write to source " + uri);
>                }
>        } finally {
>        if (outputStream != null) {
>            outputStream.flush();
>            outputStream.close();
>        }
>        }
>}
>
>Best regards,
>  
>


-- 

Met vriendelijke groet,

Suzan Foster
Software Engineer

*NEROC'MEDIAWARE *
De Run 1131
5503 LB Veldhoven
T +31 (0)40 258 66 66
F +31 (0)40 258 66 77

E suzan.foster@nerocmediaware.nl <mailto:suzan.foster@nerocmediaware.nl>

================================================
De informatie opgenomen in dit bericht kan vertrouwelijk zijn en
is uitsluitend bestemd voor de geadresseerde. Indien u dit bericht
onterecht ontvangt, wordt u verzocht de inhoud niet te gebruiken en
de afzender direct te informeren door het bericht te retourneren.
================================================
The information contained in this message may be confidential
and is intended to be exclusively for the addressee. Should you
receive this message unintentionally, please do not use the contents
herein and notify the sender immediately by return e-mail.

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@cocoon.apache.org
For additional commands, e-mail: users-help@cocoon.apache.org


Mime
View raw message