Hi,

I have done something similar when I wanted access to the parts of the output within the same transformation. What I did was that I copied the Xalan Redirect Extension called It RedirectToMem and modified the source to create a ByteArrayOutputStream instead of a file - and then maintaining a Map of named ByteArrayOutputStreams. I can the get the content of each stream within the transformation with a "contentOf(..)" extension method that simply returns the contents of a named
ByteArrayOutputStream as text.

Source of RediectToMem is attached.
(Beware that it has not been documented for public consumption....)

example use:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; version="1.0"
    xmlns:xalan="http://xml.apache.org/xalan";
    xmlns:redirectmem="http://xml.apache.org/xalan/redirectmem";
    extension-element-prefixes="redirectmem">

<xalan:component prefix="redirectmem"
        functions="contentOf" elements="write">
<xalan:script lang="javaclass" src="xalan://dk.callis.xalanext.RedirectToMem"/>
</xalan:component>
.....
<redirectmem:write file="name">
<xsl:apply-templates select="."/>
</redirectmem:write>
<xsl:variable name="textRep" select="redirectmem:contentOf('name')"/>
<redirectmem:remove file="name"/>

.....


I hope this example might inspire you

Best regards
Christoffer Bruun

On 01-09-2009 21:55, TenzoR wrote:
Hello,

I want to know if I am going at this the right way or not. Any hint would be
appreciated as well.

My End Goal is to take XML Data, transform it with XSLT and split it
accordingly to multiple Java StringBuffer.

My Input: StringBuffer (XML data)

My Output: Multiple StringBuffers

So far what I've tried are
1. Splitting inputted XML to multiple XML files using the Xalan Redirect
technique.
2. Transform a XML file and outputting it to a StringBuffer.

All test are simple, but I'm just not sure if it's feasible to do what I
want to do ...

package dk.callis.xalanext;

import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.Hashtable;

import javax.xml.transform.TransformerException;
import javax.xml.transform.stream.StreamResult;

import org.apache.xalan.extensions.XSLProcessorContext;
import org.apache.xalan.res.XSLTErrorResources;
import org.apache.xalan.templates.ElemExtensionCall;
import org.apache.xalan.templates.OutputProperties;
import org.apache.xalan.transformer.TransformerImpl;
import org.apache.xml.serializer.SerializationHandler;
import org.apache.xpath.XPath;
import org.apache.xpath.objects.XObject;
import org.xml.sax.ContentHandler;

/**
 * Implements three extension elements to allow an XSLT transformation to
 * redirect its output to multiple output files.
 * 
 * It is accessed by specifying a namespace URI as follows:
 * 
 * <pre>
 *    xmlns:redirect=&quot;http://xml.apache.org/xalan/redirect&quot;
 * </pre>
 * 
 * <p>
 * You can either just use redirect:write, in which case the file will be opened
 * and immediately closed after the write, or you can bracket the write calls by
 * redirect:open and redirect:close, in which case the file will be kept open
 * for multiple writes until the close call is encountered. Calls can be nested.
 * 
 * <p>
 * Calls can take a 'file' attribute and/or a 'select' attribute in order to get
 * the filename. If a select attribute is encountered, it will evaluate that
 * expression for a string that indicates the filename. If the string evaluates
 * to empty, it will attempt to use the 'file' attribute as a default. Filenames
 * can be relative or absolute. If they are relative, the base directory will be
 * the same as the base directory for the output document. This is obtained by
 * calling getOutputTarget() on the TransformerImpl. You can set this base
 * directory by calling TransformerImpl.setOutputTarget() or it is automatically
 * set when using the two argument form of transform() or transformNode().
 * 
 * <p>
 * Calls to redirect:write and redirect:open also take an optional attribute
 * append="true|yes", which will attempt to simply append to an existing file
 * instead of always opening a new file. The default behavior of always
 * overwriting the file still happens if you do not specify append.
 * <p>
 * <b>Note:</b> this may give unexpected results when using xml or html output
 * methods, since this is <b>not</b> coordinated with the serializers - hence,
 * you may get extra xml decls in the middle of your file after appending to it.
 * 
 * <p>
 * Example:
 * </p>
 * 
 * <PRE>
 * &lt;?xml version=&quot;1.0&quot;?&gt;
 * &lt;xsl:stylesheet 
xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot; 
 *                 version=&quot;1.0&quot;
 *                 
xmlns:redirect=&quot;http://xml.apache.org/xalan/redirect&quot;
 *                 extension-element-prefixes=&quot;redirect&quot;&gt;
 * 
 *   &lt;xsl:template match=&quot;/&quot;&gt;
 *     &lt;out&gt;
 *       default output.
 *     &lt;/out&gt;
 *     &lt;redirect:open file=&quot;doc3.out&quot;/&gt;
 *     &lt;redirect:write file=&quot;doc3.out&quot;&gt;
 *       &lt;out&gt;
 *         &lt;redirect:write file=&quot;doc1.out&quot;&gt;
 *           &lt;out&gt;
 *             doc1 output.
 *             &lt;redirect:write file=&quot;doc3.out&quot;&gt;
 *               Some text to doc3
 *             &lt;/redirect:write&gt;
 *           &lt;/out&gt;
 *         &lt;/redirect:write&gt;
 *         &lt;redirect:write file=&quot;doc2.out&quot;&gt;
 *           &lt;out&gt;
 *             doc2 output.
 *             &lt;redirect:write file=&quot;doc3.out&quot;&gt;
 *               Some more text to doc3
 *               &lt;redirect:write select=&quot;doc/foo&quot;&gt;
 *                 text for doc4
 *               &lt;/redirect:write&gt;
 *             &lt;/redirect:write&gt;
 *           &lt;/out&gt;
 *         &lt;/redirect:write&gt;
 *       &lt;/out&gt;
 *     &lt;/redirect:write&gt;
 *     &lt;redirect:close file=&quot;doc3.out&quot;/&gt;
 *   &lt;/xsl:template&gt;
 * 
 * &lt;/xsl:stylesheet&gt;
 * </PRE>
 * 
 * @author Scott Boag
 * @version 1.0
 * @see <a href="../../../../../../extensions.html#ex-redirect"
 *      target="_top">Example with Redirect extension</a>
 */
public class RedirectToMem {
        /**
         * List of formatter listeners indexed by filename.
         */
        protected Hashtable m_formatterListeners = new Hashtable();

        /**
         * List of output streams indexed by filename.
         */
        protected Hashtable m_outputStreams = new Hashtable();

        /**
         * Default append mode for bare open calls. False for backwards
         * compatibility (I think).
         */
        public static final boolean DEFAULT_APPEND_OPEN = false;

        /**
         * Default append mode for bare write calls. False for backwards
         * compatibility.
         */
        public static final boolean DEFAULT_APPEND_WRITE = false;

        /**
         * Open the given file and put it in the XML, HTML, or Text formatter
         * listener's table.
         */
        public void open(XSLProcessorContext context, ElemExtensionCall elem)
                        throws java.net.MalformedURLException,
                        java.io.FileNotFoundException, java.io.IOException,
                        javax.xml.transform.TransformerException {
                String fileName = getFilename(context, elem);
                Object flistener = m_formatterListeners.get(fileName);
                if (null == flistener) {
                        // Whether to append to existing files or not, 
<jp...@iafrica.com>
                        String appendExpr = elem.getAttribute("append", context
                                        .getContextNode(), 
context.getTransformer());
                        boolean append = (appendExpr != null) ? 
(appendExpr.equals("true") || appendExpr
                                        .equals("yes"))
                                        : DEFAULT_APPEND_OPEN;

                        Object ignored = makeFormatterListener(context, elem, 
fileName,
                                        true, append);
                }
        }

        /**
         * Write the evalutation of the element children to the given file. Then
         * close the file unless it was opened with the open extension element 
and
         * is in the formatter listener's table.
         */
        public void write(XSLProcessorContext context, ElemExtensionCall elem)
                        throws java.net.MalformedURLException,
                        java.io.FileNotFoundException, java.io.IOException,
                        javax.xml.transform.TransformerException {
                String fileName = getFilename(context, elem);
                Object flObject = m_formatterListeners.get(fileName);
                ContentHandler formatter;
                boolean inTable = false;
                if (null == flObject) {

                        // Whether to append to existing files or not, 
<jp...@iafrica.com>
                        String appendExpr = elem.getAttribute("append", context
                                        .getContextNode(), 
context.getTransformer());
                        boolean append = (appendExpr != null) ? 
(appendExpr.equals("true") || appendExpr
                                        .equals("yes"))
                                        : DEFAULT_APPEND_WRITE;

                        formatter = makeFormatterListener(context, elem, 
fileName, true,
                                        append);
                } else {
                        inTable = true;
                        formatter = (ContentHandler) flObject;
                }

                TransformerImpl transf = context.getTransformer();

                startRedirection(transf, formatter); // for tracing only

                transf.executeChildTemplates(elem, context.getContextNode(), 
context
                                .getMode(), formatter);

                endRedirection(transf); // for tracing only

                if (!inTable) {
                        OutputStream ostream = (OutputStream) 
m_outputStreams.get(fileName);
                        if (null != ostream) {
                                try {
                                        formatter.endDocument();
                                } catch (org.xml.sax.SAXException se) {
                                        throw new TransformerException(se);
                                }
                                ostream.close();
                                // Keep it so we can ask for the contents later 
- use <XX:remove file=".."> to delete
                                // m_outputStreams.remove(fileName);
                                m_formatterListeners.remove(fileName);
                        }
                }
        }

        public String contentOf(String fileName) {
                //System.out.println("fileName=" + fileName);
                ByteArrayOutputStream ostream = (ByteArrayOutputStream) 
m_outputStreams
                                .get(fileName);
                // TODO - fix selection of output encoding
                try {
                        return ostream.toString("UTF-8");
                } catch (UnsupportedEncodingException e) {

                        e.printStackTrace();
                }
                return null;
        }

        public void remove(XSLProcessorContext context, ElemExtensionCall elem)
                        throws TransformerException {

                String fileName = elem.getAttribute("file", 
context.getContextNode(),
                                context.getTransformer());

                String ignore = elem.getAttribute("ignore-missing", context
                                .getContextNode(), context.getTransformer());
                boolean ign = true;
                if (null == ignore || "false".equals(ignore)) {
                        ign = false;
                } else if ("true".equals(ignore)) {
                        ign = true;
                } else {
                        context.getTransformer().getMsgMgr().error(
                                                        elem,
                                                        elem,
                                                        
context.getContextNode(),
                                                        this.getClass()
                                                                        + " 
ignore-missing attribute can be only 'true' or 'false' - not: "
                                                                        + 
ignore);
                }

                if (null == fileName) {
                        context.getTransformer().getMsgMgr().error(
                                        elem,
                                        elem,
                                        context.getContextNode(),
                                        this.getClass()
                                                        + " missing file 
attribute in on remove element");
                } else {
                        ByteArrayOutputStream ostream = (ByteArrayOutputStream) 
m_outputStreams
                                        .get(fileName);
                        if (null == ostream) {
                                if (!ign) {
                                        
context.getTransformer().getMsgMgr().error(
                                                        elem,
                                                        elem,
                                                        
context.getContextNode(),
                                                        this.getClass() + " no 
file: " + fileName
                                                                        + " is 
unknown");
                                }
                        } else {
                                m_outputStreams.remove(fileName);
                        }
                }
        }

        /**
         * Close the given file and remove it from the formatter listener's 
table.
         */
        public void close(XSLProcessorContext context, ElemExtensionCall elem)
                        throws java.net.MalformedURLException,
                        java.io.FileNotFoundException, java.io.IOException,
                        javax.xml.transform.TransformerException {
                String fileName = getFilename(context, elem);
                Object formatterObj = m_formatterListeners.get(fileName);
                if (null != formatterObj) {
                        ContentHandler fl = (ContentHandler) formatterObj;
                        try {
                                fl.endDocument();
                        } catch (org.xml.sax.SAXException se) {
                                throw new TransformerException(se);
                        }
                        OutputStream ostream = (OutputStream) 
m_outputStreams.get(fileName);
                        if (null != ostream) {
                                ostream.close();
                                m_outputStreams.remove(fileName);
                        }
                        m_formatterListeners.remove(fileName);
                }
        }

        /**
         * Get the filename from the 'select' or the 'file' attribute.
         */
        private String getFilename(XSLProcessorContext context,
                        ElemExtensionCall elem) throws 
java.net.MalformedURLException,
                        java.io.FileNotFoundException, java.io.IOException,
                        javax.xml.transform.TransformerException {
                String fileName;
                String fileNameExpr = ((ElemExtensionCall) 
elem).getAttribute("select",
                                context.getContextNode(), 
context.getTransformer());
                if (null != fileNameExpr) {
                        org.apache.xpath.XPathContext xctxt = 
context.getTransformer()
                                        .getXPathContext();
                        XPath myxpath = new XPath(fileNameExpr, elem, xctxt
                                        .getNamespaceContext(), XPath.SELECT);
                        XObject xobj = myxpath.execute(xctxt, 
context.getContextNode(),
                                        elem);
                        fileName = xobj.str();
                        if ((null == fileName) || (fileName.length() == 0)) {
                                fileName = elem.getAttribute("file", 
context.getContextNode(),
                                                context.getTransformer());
                        }
                } else {
                        fileName = elem.getAttribute("file", 
context.getContextNode(),
                                        context.getTransformer());
                }
                if (null == fileName) {
                        context.getTransformer().getMsgMgr().error(elem, elem,
                                        context.getContextNode(),
                                        
XSLTErrorResources.ER_REDIRECT_COULDNT_GET_FILENAME);
                        // "Redirect extension: Could not get filename - file 
or select
                        // attribute must return vald string.");
                }
                return fileName;
        }

        /**
         * Create a new ContentHandler, based on attributes of the current
         * ContentHandler.
         */
        private ContentHandler makeFormatterListener(XSLProcessorContext 
context,
                        ElemExtensionCall elem, String fileName, boolean 
shouldPutInTable,
                        boolean append) throws java.net.MalformedURLException,
                        java.io.FileNotFoundException, java.io.IOException,
                        javax.xml.transform.TransformerException {
                TransformerImpl transformer = context.getTransformer();

                // This should be worked on so that the output format can be
                // defined by a first child of the redirect element.
                OutputProperties format = transformer.getOutputFormat();
                String omitXmlDecl = elem.getAttribute("omit-xml-declaration", 
context
                                .getContextNode(), context.getTransformer());
                if (null != omitXmlDecl) {
                        if ("true".equals(omitXmlDecl)) {
                                format.setBooleanProperty(
                                                
javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION,
                                                true);
                        } else if ("false".equals(omitXmlDecl)) {
                                format.setBooleanProperty(
                                                
javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION,
                                                false);
                        }
                } else {
                        format.setBooleanProperty(
                                        
javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, true);
                }
                // FileOutputStream ostream = new FileOutputStream(file);
                // Patch from above line to below by <jp...@iafrica.com>
                // Note that in JDK 1.2.2 at least, FileOutputStream(File)
                // is implemented as a call to
                // FileOutputStream(File.getPath, append), thus this should be
                // the equivalent instead of getAbsolutePath()
                ByteArrayOutputStream ostream = new ByteArrayOutputStream();

                try {
                        SerializationHandler flistener = 
createSerializationHandler(
                                        transformer, ostream, format);

                        try {
                                flistener.startDocument();

                        } catch (org.xml.sax.SAXException se) {
                                throw new TransformerException(se);
                        }
                        if (shouldPutInTable) {
                                m_outputStreams.put(fileName, ostream);
                                m_formatterListeners.put(fileName, flistener);
                        }
                        return flistener;
                } catch (TransformerException te) {
                        throw new javax.xml.transform.TransformerException(te);
                }

        }

        /**
         * A class that extends this class can over-ride this public method and
         * recieve a callback that redirection is about to start
         * 
         * @param transf
         *            The transformer.
         * @param formatter
         *            The handler that receives the redirected output
         */
        public void startRedirection(TransformerImpl transf,
                        ContentHandler formatter) {
                // A class that extends this class could provide a method body
        }

        /**
         * A class that extends this class can over-ride this public method and
         * receive a callback that redirection to the ContentHandler specified 
in
         * the startRedirection() call has ended
         * 
         * @param transf
         *            The transformer.
         */
        public void endRedirection(TransformerImpl transf) {
                // A class that extends this class could provide a method body
        }

        /**
         * A class that extends this one could over-ride this public method and
         * receive a callback for the creation of the serializer used in the
         * redirection.
         * 
         * @param transformer
         *            The transformer
         * @param ostream
         *            The output stream that the serializer wraps
         * @param file
         *            The file associated with the ostream
         * @param format
         *            The format parameter used to create the serializer
         * @return the serializer that the redirection will go to.
         * 
         * @throws java.io.IOException
         * @throws TransformerException
         */
        public SerializationHandler createSerializationHandler(
                        TransformerImpl transformer, OutputStream ostream,
                        OutputProperties format) throws java.io.IOException,
                        TransformerException {

                SerializationHandler serializer = transformer
                                .createSerializationHandler(new 
StreamResult(ostream), format);
                return serializer;
        }
}

Reply via email to