Package org.exist.xslt

Source Code of org.exist.xslt.XSLStylesheet

/*
*  eXist Open Source Native XML Database
*  Copyright (C) 2008-2010 The eXist Project
*  http://exist-db.org
*  This program is free software; you can redistribute it and/or
*  modify it under the terms of the GNU Lesser General Public License
*  as published by the Free Software Foundation; either version 2
*  of the License, or (at your option) any later version.
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU Lesser General Public License for more details.
*  You should have received a copy of the GNU Lesser General Public License
*  along with this program; if not, write to the Free Software
*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*  $Id$
*/
package org.exist.xslt;

import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeSet;

import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;

import org.exist.security.xacml.XACMLSource;
import org.exist.xquery.AnalyzeContextInfo;
import org.exist.xquery.CompiledXQuery;
import org.exist.xquery.Expression;
import org.exist.xquery.XPathException;
import org.exist.xquery.value.Item;
import org.exist.xquery.value.Sequence;
import org.exist.xquery.value.SequenceIterator;
import org.exist.xquery.value.ValueSequence;
import org.exist.dom.DocumentAtExist;
import org.exist.dom.ElementAtExist;
import org.exist.dom.NodeAtExist;
import org.exist.dom.QName;
import org.exist.dom.NamespaceNodeAtExist;
import org.exist.dom.Validation;
import org.exist.interpreter.ContextAtExist;
import org.exist.xslt.expression.AttributeSet;
import org.exist.xslt.expression.Declaration;
import org.exist.xslt.expression.Param;
import org.exist.xslt.expression.Template;
import org.exist.xslt.expression.XSLExpression;
import org.exist.xslt.expression.i.Parameted;
import org.w3c.dom.Attr;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;

/**
* <(xsl:stylesheet|xsl:transform)
*   id? = id
*   extension-element-prefixes? = tokens
*   exclude-result-prefixes? = tokens
*   version = number
*   xpath-default-namespace? = uri
*   default-validation? = "preserve" | "strip"
*   default-collation? = uri-list
*   input-type-annotations? = "preserve" | "strip" | "unspecified">
*   <!-- Content: (xsl:import*, other-declarations) -->
* </(xsl:stylesheet|xsl:transform)>
*
* @author <a href="mailto:shabanovd@gmail.com">Dmitriy Shabanov</a>
*
*/
public class XSLStylesheet extends Declaration
  implements CompiledXQuery, Templates, XSLExpression, Parameted {
 
  private Transformer transformer = null;
 
  public final double version = 2.0;

  private String id = null;
  private String extension_element_prefixes = null;
  private String exclude_result_prefixes = null;
  private String xpath_default_namespace = null;
  private int default_validation = Validation.STRIP;
  private String default_collation = null;
  private String input_type_annotations = null;
 
  private boolean simplified = false;
 
  protected Template rootTemplate = null;
  protected Set<Template> templates = new TreeSet<Template>();
  private Map<QName, Template> namedTemplates = new HashMap<QName, Template>();
 
  private Map<String, List<AttributeSet>> attributeSets =
    new HashMap<String, List<AttributeSet>>();
   
    private Map<QName, org.exist.xquery.Variable> params = null;

    private List<org.exist.xslt.expression.Variable> variables =
      new ArrayList<org.exist.xslt.expression.Variable>();
   
    private List<org.exist.xslt.expression.Function> functions =
      new ArrayList<org.exist.xslt.expression.Function>();

  public XSLStylesheet(XSLContext context) {
    super(context);
   
    //UNDERSTAND: may be better to set at eval???
    context.setXSLStylesheet(this);
    context.setStripWhitespace(true);
  }

  public XSLStylesheet(XSLContext context, boolean embedded) {
    this(context);
   
    this.simplified = embedded;
  }

  public void setToDefaults() {
    id = null;
    extension_element_prefixes = null;
    exclude_result_prefixes = null;
    xpath_default_namespace = null;
    default_validation = Validation.STRIP;
    default_collation = null;
    input_type_annotations = null;
  }

  public void prepareAttribute(ContextAtExist context, Attr attr) throws XPathException {
    String attr_name = attr.getLocalName();
    if (attr instanceof NamespaceNodeAtExist) {
      NamespaceNodeAtExist namespace = (NamespaceNodeAtExist) attr;
      if (attr_name.equals(""))
        context.setDefaultElementNamespace(namespace.getValue(), null);

      context.declareInScopeNamespace(attr_name, namespace.getValue());
      return;
    }
    if (attr_name.equals(ID)) {
      id = attr.getValue();
    } else if (attr_name.equals(EXTENSION_ELEMENT_PREFIXES)) {
      extension_element_prefixes = attr.getValue();
    } else if (attr_name.equals(EXCLUDE_RESULT_PREFIXES)) {
      exclude_result_prefixes = attr.getValue();
    } else if (attr_name.equals(VERSION)) {
      if (!Double.valueOf(attr.getValue()).equals(version)) {
       
      }
    } else if (attr_name.equals(XPATH_DEFAULT_NAMESPACE)) {
      xpath_default_namespace = attr.getValue();
    } else if (attr_name.equals(DEFAULT_VALIDATION)) {
      //XXX: fix -> default_validation = attr.getValue();
    } else if (attr_name.equals(DEFAULT_COLLATION)) {
      default_collation = attr.getValue();
    } else if (attr_name.equals(INPUT_TYPE_ANNOTATIONS)) {
      input_type_annotations = attr.getValue();
    }
  }
 
  /* (non-Javadoc)
   * @see javax.xml.transform.Templates#getOutputProperties()
   */
  public Properties getOutputProperties() {
      throw new RuntimeException("Not implemented: getOutputProperties() at "+this.getClass());
  }

  /* (non-Javadoc)
   * @see javax.xml.transform.Templates#newTransformer()
   */
  public Transformer newTransformer() throws TransformerConfigurationException {
        org.exist.xslt.TransformerImpl transformer = new org.exist.xslt.TransformerImpl();
        transformer.setPreparedStylesheet(this);
        return transformer;
  }

  @Override
  public void dump(Writer writer) {
      throw new RuntimeException("Not implemented: dump(Writer writer) at "+this.getClass());
   
  }

  @Override
  public XACMLSource getSource() {
      throw new RuntimeException("Not implemented: getSource() at "+this.getClass());
  }

  public boolean isValid() {
      throw new RuntimeException("Not implemented: isValid() at "+this.getClass());
  }

  @Override
  public void reset() {
      throw new RuntimeException("Not implemented: reset() at "+this.getClass());
  }

  public void setSource(XACMLSource source) {
      throw new RuntimeException("Not implemented: setSource(XACMLSource source) at "+this.getClass());
  }

  public void analyze(AnalyzeContextInfo contextInfo) throws XPathException {
    super.analyze(contextInfo);

    for (Expression expr : steps) {
      if (expr instanceof Template) {
        Template template = (Template) expr;
        if (template.isRootMatch()) {
          if (rootTemplate != null) {
            if (template.isPrioritySet() || rootTemplate.isPrioritySet()) {
              if (template.getPriority() == rootTemplate.getPriority()) {
                compileError("double root match");//XXX: put error code
              } else if (template.getPriority() > rootTemplate.getPriority()) {
                rootTemplate = template;
              }
              continue;
            }
            compileError("double root match");//XXX: put error code
          }
          rootTemplate = template;

          if (template.getName() != null)
            namedTemplates.put(template.getName(), template);//UNDERSTAND: check doubles?

        } else if (template.getName() == null) {
          templates.add(template);
        } else {
          namedTemplates.put(template.getName(), template);//UNDERSTAND: check doubles?
        }
      } else if (expr instanceof AttributeSet) {
        AttributeSet attributeSet = (AttributeSet) expr;
        if (attributeSets.containsKey(attributeSet.getName()))
          attributeSets.get(attributeSet.getName()).add(attributeSet);
        else {
          List<AttributeSet> list = new ArrayList<AttributeSet>();
          list.add(attributeSet);
          attributeSets.put(attributeSet.getName(), list);
        }
          
      } else if (expr instanceof org.exist.xslt.expression.Variable) {
        org.exist.xslt.expression.Variable variable = (org.exist.xslt.expression.Variable) expr;
        variables.add(variable);
      } else if (expr instanceof org.exist.xslt.expression.Function) {
        org.exist.xslt.expression.Function function = (org.exist.xslt.expression.Function) expr;
        functions.add(function);
      }
    }
  }

  public void validate() throws XPathException {
    super.validate();
  }
 
    public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathException {
      Sequence result;
      if (simplified)
        result = super.eval(contextSequence, null);
      else {
        variableDeclaration(contextSequence, contextItem);
        functionDeclaration(contextSequence, contextItem);
       
        result = templates(contextSequence, null);
      }
   
    if (result == null)
      result = Sequence.EMPTY_SEQUENCE;
   
    return result;
    }

    private void variableDeclaration(Sequence contextSequence, Item contextItem) throws XPathException {
      for (org.exist.xslt.expression.Variable variable : variables) {
        variable.eval(contextSequence, contextItem);
      }
  }

    private void functionDeclaration(Sequence contextSequence, Item contextItem) throws XPathException {
      for (org.exist.xslt.expression.Function function : functions) {
        //TODO: need interface for functions
        //context.declareFunction(function);
      }
  }

//    public Set<AttributeSet> getAttributeSet(String name) throws XPathException {
//      String[] names = name.split(" ");
//     
//      Set<AttributeSet> sets = new HashSet<AttributeSet>(names.length);
//     
//      String n;
//      for (int i = 0; i < names.length; i++) {
//        n = names[i];
//      if (attributeSets.containsKey(n)) {
//        sets.add(attributeSets.get(n));
//      } else {
//        //UNDERSTAND: error???
//      }
//      }
//     
//      return sets;
//    }

    public Sequence attributeSet(String name, Sequence contextSequence, Item contextItem) throws XPathException {
      Sequence result = new ValueSequence();
     
      String[] names = name.split(" ");
     
      String n;
      for (int i = 0; i < names.length; i++) {
        n = names[i];
        if (attributeSets.containsKey(n)) {
          List<AttributeSet> list = attributeSets.get(n);
          for (AttributeSet set : list) {
            result.addAll(set.eval(null, null));
          }
        } else {
          //UNDERSTAND: error???
        }
      }
     
      return result;
    }
   
    public Sequence templates(Sequence contextSequence, Item contextItem) throws XPathException {

    boolean matched = false;
    Sequence result = new ValueSequence();

    Sequence currentSequence = contextSequence;
   
    if (contextItem != null)
      currentSequence = contextItem.toSequence();
   
    int pos = context.getContextPosition();
   
//    for (Item item : currentSequence) {
    for (SequenceIterator iterInner = currentSequence.iterate(); iterInner.hasNext();) {
      Item item = iterInner.nextItem();
//      if (currentSequence == item)
//        item = null;

      //UNDERSTAND: work around
//      if (item instanceof org.w3c.dom.Document) {
//        org.w3c.dom.Document document = (org.w3c.dom.Document) item;
//        item = (Item) document.getDocumentElement();
//      }
     
      context.setContextSequencePosition(pos, currentSequence);
     
      if ((contextItem == null) && (rootTemplate != null)) {
        context.setContextSequencePosition(0, currentSequence);
        Sequence res = rootTemplate.eval(contextSequence, item);
        result.addAll(res);
        matched = true;
      }

      for (Template template : templates) {
        if (template.matched(contextSequence, item)) { //contextSequence
          matched = true;
         
          Sequence res = template.eval(contextSequence, item);
          result.addAll(res);
          if (res.getItemCount() > 0)
            break;
        }
      }
     
      //XXX: performance !?! how to get subelements sequence?? fast...
      if (!matched) {
        if (item instanceof ElementAtExist || item instanceof DocumentAtExist) {
          NodeAtExist node = (NodeAtExist) item;
         
          NodeList children = node.getChildNodes();
          for (int i=0; i<children.getLength(); i++) {
            NodeAtExist child = (NodeAtExist)children.item(i);
           
//            if (child instanceof Text) {
//                        MemTreeBuilder builder = context.getDocumentBuilder();
//                    builder.characters(item.getStringValue());
//                    result.add(item);
//            } else {
              Sequence res = templates((Sequence)node, (Item)child);
              if (res != null) {
                result.addAll(res);
                matched = true;
              }
//            }
          }
        }
      }
     
      pos++;
    }
   
    if (matched)
      return result;
   
    return null;
    }
   
    public Sequence template(QName name, Sequence contextSequence, Item contextItem) throws XPathException {
    if (!namedTemplates.containsKey(name))
      throw new XPathException("no template with given name = "+name);//TODO: error?
   
    Sequence result = new ValueSequence();

    Sequence currentSequence = contextSequence;
   
    if (contextItem != null)
      currentSequence = contextItem.toSequence();

    int pos = context.getContextPosition();

    Template template = namedTemplates.get(name);
    for (SequenceIterator iterInner = currentSequence.iterate(); iterInner.hasNext();) {
      Item item = iterInner.nextItem();  
     
      //UNDERSTAND: work around
//      if (item instanceof org.w3c.dom.Document) {
//        org.w3c.dom.Document document = (org.w3c.dom.Document) item;
//        item = (Item) document.getDocumentElement();
//      }
     
      context.setContextSequencePosition(pos, currentSequence);

      Sequence res = template.eval(contextSequence, item);
      result.addAll(res);
      if (res.getItemCount() > 0)
        break;

      pos++;
    }
   
    return result;
    }

    public Map<QName, org.exist.xquery.Variable> getXSLParams() {
      if (params == null)
        params = new HashMap<QName, org.exist.xquery.Variable>();
     
      return params;
    }
   
  /* (non-Javadoc)
   * @see org.exist.xslt.expression.i.Parameted#addXSLParam(org.exist.xslt.expression.Param)
   */
  public void addXSLParam(Param param) throws XPathException {
    Map<QName, org.exist.xquery.Variable> params = getXSLParams();
   
    if (params.containsKey(param.getName()))
      compileError(XSLExceptions.ERR_XTSE0580);

        context.declareGlobalVariable(param);
//        Variable variable = context.declareVariable(param.getName(), param);//UNDERSTAND: global
    params.put(param.getName(), param);
  }

  public void setTransformer(Transformer transformer) {
    this.transformer = transformer;
  }

  public Transformer getTransformer() {
    return transformer;
  }
}
TOP

Related Classes of org.exist.xslt.XSLStylesheet

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.