Package org.apache.cocoon.transformation

Source Code of org.apache.cocoon.transformation.XIncludeTransformer

/*****************************************************************************
* Copyright (C) The Apache Software Foundation. All rights reserved.        *
* ------------------------------------------------------------------------- *
* This software is published under the terms of the Apache Software License *
* version 1.1, a copy of which has been included  with this distribution in *
* the LICENSE file.                                                         *
*****************************************************************************/
package org.apache.cocoon.transformation;

import org.apache.avalon.excalibur.pool.Recyclable;
import org.apache.avalon.framework.activity.Disposable;
import org.apache.avalon.framework.component.Component;
import org.apache.avalon.framework.component.ComponentException;
import org.apache.avalon.framework.component.ComponentManager;
import org.apache.avalon.framework.component.Composable;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.components.parser.Parser;
import org.apache.cocoon.components.xpath.XPathProcessor;
import org.apache.cocoon.environment.Source;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.cocoon.xml.IncludeXMLConsumer;
import org.apache.cocoon.xml.dom.DOMStreamer;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;

import java.io.*;
import java.net.MalformedURLException;
import java.util.Map;
import java.util.Stack;

/**
* My first pass at an XInclude transformation. Currently it should set the base URI
* from the SAX Locator's system id but allow it to be overridden by xml:base
* elements as the XInclude spec mandates. It's also got some untested code
* that should handle inclusion of text includes, but that method isn't called
* by the SAX event FSM yet.
*
* @author <a href="mailto:balld@webslingerZ.com">Donald Ball</a>
* @version CVS $Revision: 1.3 $ $Date: 2002/01/25 03:58:30 $ $Author: vgritsenko $
*/
public class XIncludeTransformer extends AbstractTransformer implements Composable, Recyclable, Disposable {

    private SourceResolver resolver;

    /** XPath Processor */
    private XPathProcessor processor = null;

    protected ComponentManager manager = null;

    public static final String XMLBASE_NAMESPACE_URI = "http://www.w3.org/XML/1998/namespace";
    public static final String XMLBASE_ATTRIBUTE = "base";

    public static final String XINCLUDE_NAMESPACE_URI = "http://www.w3.org/2001/XInclude";
    public static final String XINCLUDE_INCLUDE_ELEMENT = "include";
    public static final String XINCLUDE_INCLUDE_ELEMENT_HREF_ATTRIBUTE = "href";
    public static final String XINCLUDE_INCLUDE_ELEMENT_PARSE_ATTRIBUTE = "parse";

    protected Source base_xmlbase_uri = null;

    /** The current XMLBase URI. We start with an empty "dummy" URL. **/
    protected Source current_xmlbase_uri = null;

    /** This is a stack of xml:base attributes which belong to our ancestors **/
    protected Stack xmlbase_stack = new Stack();

    /** namespace uri of the last element which had an xml:base attribute **/
    protected String last_xmlbase_element_uri = "";

    protected Stack xmlbase_element_uri_stack = new Stack();

    /** name of the last element which had an xml:base attribute **/
    protected String last_xmlbase_element_name = "";

    protected Stack xmlbase_element_name_stack = new Stack();

    public void setup(SourceResolver resolver, Map objectModel,
                      String source, Parameters parameters)
            throws ProcessingException, SAXException, IOException {
        this.resolver = resolver;
    }

    public void compose(ComponentManager manager) {
        this.manager = manager;
        try {
            this.processor = (XPathProcessor)this.manager.lookup(XPathProcessor.ROLE);
        } catch (Exception e) {
            getLogger().error("cannot obtain XPathProcessor", e);
        }
    }

    public void startElement(String uri, String name, String raw, Attributes attr) throws SAXException {
        String value;
        if ((value = attr.getValue(XMLBASE_NAMESPACE_URI,XMLBASE_ATTRIBUTE)) != null) {
            try {
                startXMLBaseAttribute(uri,name,value);
            } catch (ProcessingException e) {
                getLogger().debug("Rethrowing exception", e);
                throw new SAXException(e);
            }
        }
        if (XINCLUDE_NAMESPACE_URI.equals(uri) && XINCLUDE_INCLUDE_ELEMENT.equals(name)) {
            String href = attr.getValue("",XINCLUDE_INCLUDE_ELEMENT_HREF_ATTRIBUTE);
            String parse = attr.getValue("",XINCLUDE_INCLUDE_ELEMENT_PARSE_ATTRIBUTE);

            if (null == parse) parse="xml";

            try {
                processXIncludeElement(href, parse);
            } catch (ProcessingException e) {
                getLogger().debug("Rethrowing exception", e);
                throw new SAXException(e);
            } catch (IOException e) {
                getLogger().debug("Rethrowing exception", e);
                throw new SAXException(e);
            }
            return;
        }
        super.startElement(uri,name,raw,attr);
    }

    public void endElement(String uri, String name, String raw) throws SAXException {
        if (last_xmlbase_element_uri.equals(uri) && last_xmlbase_element_name.equals(name)) {
            endXMLBaseAttribute();
        }
        if (uri != null && name != null && uri.equals(XINCLUDE_NAMESPACE_URI) && name.equals(XINCLUDE_INCLUDE_ELEMENT)) {
            return;
        }
        super.endElement(uri,name,raw);
    }

    public void setDocumentLocator(Locator locator) {
        try {
            if (getLogger().isDebugEnabled()) {
                getLogger().debug("setDocumentLocator called " + locator.getSystemId());
            }

            base_xmlbase_uri = this.resolver.resolve(locator.getSystemId());

            // If url ends with .xxx then truncate to dir
            if (base_xmlbase_uri.getSystemId().lastIndexOf('.') > base_xmlbase_uri.getSystemId().lastIndexOf('/')) {
               String uri = base_xmlbase_uri.getSystemId().substring(0,base_xmlbase_uri.getSystemId().lastIndexOf('/')+1);
               base_xmlbase_uri.recycle();
               base_xmlbase_uri = null;
               base_xmlbase_uri = this.resolver.resolve(uri);
            }

            if (current_xmlbase_uri == null) {
               current_xmlbase_uri = base_xmlbase_uri;
            }

        } catch (Exception e) {
            getLogger().debug("Exception ignored", e);
        }
        super.setDocumentLocator(locator);
    }

    protected void startXMLBaseAttribute(String uri, String name, String value) throws ProcessingException {
        String urlLoc = value;

        if (! urlLoc.endsWith("/")) {
            urlLoc += "/";
        }

        if (getLogger().isDebugEnabled()) {
            getLogger().debug("XMLBase = " + urlLoc);
        }

        if (current_xmlbase_uri != null) {
            xmlbase_stack.push(current_xmlbase_uri);
        }

        try {
            current_xmlbase_uri = this.resolver.resolve(urlLoc);
   
            xmlbase_element_uri_stack.push(last_xmlbase_element_uri);
            last_xmlbase_element_uri = uri;
   
            xmlbase_element_name_stack.push(last_xmlbase_element_name);
            last_xmlbase_element_name = name;
        } catch (ProcessingException e) {
            throw e;
        } catch (Exception e) {
            throw new ProcessingException("Could not resolve '" + urlLoc + "'", e);
        }
    }

    protected void endXMLBaseAttribute() {
        if (getLogger().isDebugEnabled()) {
            getLogger().debug("XMLBase ended");
        }

        if (xmlbase_stack.size() > 0) {
            current_xmlbase_uri = (Source)xmlbase_stack.pop();
        } else {
            current_xmlbase_uri = base_xmlbase_uri;
        }
        last_xmlbase_element_uri = (String)xmlbase_element_uri_stack.pop();
        last_xmlbase_element_name = (String)xmlbase_element_name_stack.pop();
    }

    protected void processXIncludeElement(String href, String parse) throws SAXException,ProcessingException,IOException {
        if (getLogger().isDebugEnabled()) {
            getLogger().debug("Processing XInclude element: href="+href+", parse="+parse);
            if(current_xmlbase_uri == null)
                getLogger().debug("Base URI: null");
            else
                getLogger().debug("Base URI: " + current_xmlbase_uri.getSystemId());
        }

        Source url = null;
        String suffix;
        try {
            int index = href.indexOf('#');
            if (index < 0) {
                if(current_xmlbase_uri == null)
                    url = this.resolver.resolve(href);
                else
                    url = this.resolver.resolve(current_xmlbase_uri.getSystemId() + href);
                suffix = "";
            } else {
                if(current_xmlbase_uri == null)
                    url = this.resolver.resolve(href.substring(0,index));
                else
                    url = this.resolver.resolve(current_xmlbase_uri.getSystemId() + href.substring(0,index));
                suffix = href.substring(index+1);
            }
            if (getLogger().isDebugEnabled()) {
                getLogger().debug("URL: "+url+"\nSuffix: "+suffix);
            }
       
            if (parse.equals("text")) {
                getLogger().debug("Parse type is text");
                InputStream input = url.getInputStream();
                Reader reader = new BufferedReader(new InputStreamReader(input));
                int read;
                char ary[] = new char[1024];
                if (reader != null) {
                    while ((read = reader.read(ary)) != -1) {
                        super.characters(ary,0,read);
                    }
                    reader.close();
                }
            } else if (parse.equals("xml")) {
                getLogger().debug("Parse type is XML");
                Parser parser = null;
                try {
                    parser = (Parser)manager.lookup(Parser.ROLE);
       
                    InputSource input = url.getInputSource();
       
                    if (suffix.startsWith("xpointer(") && suffix.endsWith(")")) {
                        String xpath = suffix.substring(9,suffix.length()-1);
                        getLogger().debug("XPath is "+xpath);
                        Document document = parser.parseDocument(input);
                        NodeList list = processor.selectNodeList(document,xpath);
                        DOMStreamer streamer = new DOMStreamer(super.contentHandler,super.lexicalHandler);
                        int length = list.getLength();
                        for (int i=0; i<length; i++) {
                            streamer.stream(list.item(i));
                        }
                    } else {
                        IncludeXMLConsumer xinclude_handler = new IncludeXMLConsumer(super.contentHandler,super.lexicalHandler);
                        xinclude_handler.setLogger(getLogger());
                        parser.setConsumer(xinclude_handler);
                        parser.parse(input);
                    }
                } catch(SAXException e) {
                    getLogger().error("Error in processXIncludeElement", e);
                    throw e;
                } catch(ProcessingException e) {
                    getLogger().error("Error in processXIncludeElement", e);
                    throw e;
                } catch(MalformedURLException e) {
                    getLogger().error("Error in processXIncludeElement", e);
                    throw e;
                } catch(IOException e) {
                    getLogger().error("Error in processXIncludeElement", e);
                    throw e;
                } catch(ComponentException e) {
                    getLogger().error("Error in processXIncludeElement", e);
                    throw new SAXException(e);
                } finally {
                    if(parser != null) this.manager.release(parser);
                }
            }
        } finally {
            if (url != null) url.recycle();
        }
    }

    public void recycle()
    {
        // Reset all variables to initial state.
        this.resolver = null;
        if (base_xmlbase_uri != null) base_xmlbase_uri.recycle();
        base_xmlbase_uri = null;
        if (current_xmlbase_uri != null) current_xmlbase_uri.recycle();
        current_xmlbase_uri = null;
        xmlbase_stack = new Stack();
        last_xmlbase_element_uri = "";
        xmlbase_element_uri_stack = new Stack();
        last_xmlbase_element_name = "";
        xmlbase_element_name_stack = new Stack();
        super.recycle();
    }

    public void dispose()
    {
        this.manager.release((Component)this.processor);
    }
}
TOP

Related Classes of org.apache.cocoon.transformation.XIncludeTransformer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.