Package org.apache.xalan.xslt

Source Code of org.apache.xalan.xslt.TemplateList$MatchPattern2

/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 1999 The Apache Software Foundation.  All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in
*    the documentation and/or other materials provided with the
*    distribution.
*
* 3. The end-user documentation included with the redistribution,
*    if any, must include the following acknowledgment:
*       "This product includes software developed by the
*        Apache Software Foundation (http://www.apache.org/)."
*    Alternately, this acknowledgment may appear in the software itself,
*    if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Xalan" and "Apache Software Foundation" must
*    not be used to endorse or promote products derived from this
*    software without prior written permission. For written
*    permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
*    nor may "Apache" appear in their name, without prior written
*    permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 1999, Lotus
* Development Corporation., http://www.lotus.com.  For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.xalan.xslt;

import java.util.Hashtable;
import org.w3c.dom.Node;
import org.apache.xalan.xpath.xml.QName;
import org.xml.sax.SAXException;
import java.util.Vector;
import java.io.Serializable;
import org.apache.xalan.xpath.XPath;
import org.apache.xalan.xslt.res.XSLTErrorResources;

/**
* <meta name="usage" content="advanced"/>
* Encapsulates a template list, and helps locate individual templates.
*/
public class TemplateList implements java.io.Serializable
{
  /**
   * Construct a TemplateList object.
   */
  TemplateList(Stylesheet stylesheet)
  {
    m_stylesheet = stylesheet;
  }

  /**
   * The stylesheet owner of the list.
   */
  Stylesheet m_stylesheet;
 
  /**
   * Get the stylesheet owner of the list.
   */
  public Stylesheet getStylesheet()
  {
    return m_stylesheet;
  }

  /**
   * The first template of the template children.
   * @serial
   */
  ElemTemplateElement m_firstTemplate = null;

  /**
   * Get the first template of the template children.
   */
  public ElemTemplateElement getFirstTemplate()
  {
    return m_firstTemplate;
  }

  /**
   * Set the first template of the template children.
   */
  public void setFirstTemplate(ElemTemplateElement v)
  {
    m_firstTemplate = v;
  }

  /**
   * Keyed on string macro names, and holding values
   * that are macro elements in the XSL DOM tree.
   * Initialized in initMacroLookupTable, and used in
   * findNamedTemplate.
   * @serial
   */
  Hashtable m_namedTemplates = new Hashtable();

  /**
   * Tells if the stylesheet is without an xsl:stylesheet
   * and xsl:template wrapper.
   * @serial
   */
  private boolean m_isWrapperless = false;

  /**
   * The manufactured template if there is no wrapper.
   * @serial
   */
  private ElemTemplate m_wrapperlessTemplate = null;

  /**
   * This table is keyed on the target elements
   * of patterns, and contains linked lists of
   * the actual patterns that match the target element
   * to some degree of specifity.
   * @serial
   */
  private Hashtable m_patternTable = new Hashtable();

  /**
   * Set if the stylesheet is without an xsl:stylesheet
   * and xsl:template wrapper.
   */
  void setIsWrapperless(boolean b)
  {
    m_isWrapperless = b;
  }

  /**
   * Get if the stylesheet is without an xsl:stylesheet
   * and xsl:template wrapper.
   */
  public boolean getIsWrapperless()
  {
    return m_isWrapperless;
  }

  /**
   * Set the manufactured template if there is no wrapper.
   * and xsl:template wrapper.
   */
  void setWrapperlessTemplate(ElemTemplate t)
  {
    m_wrapperlessTemplate = t;
  }

  /**
   * Get the manufactured template if there is no wrapper.
   * and xsl:template wrapper.
   */
  public ElemTemplate getWrapperlessTemplate()
  {
    return m_wrapperlessTemplate;
  }

  /**
   * Get table of named Templates.
   * These are keyed on string macro names, and holding values
   * that are template elements in the XSL DOM tree.
   */
  public Hashtable getNamedTemplates()
  {
    return m_namedTemplates;
  }

  /**
   * Set table of named Templates.
   * These are keyed on string macro names, and holding values
   * that are template elements in the XSL DOM tree.
   */
  public void setNamedTemplates(Hashtable v)
  {
    m_namedTemplates = v;
  }

  /**
   * Given a target element, find the template that best
   * matches in the given XSL document, according
   * to the rules specified in the xsl draft.
   * @param stylesheetTree Where the XSL rules are to be found.
   * @param sourceTree Where the targetElem is to be found.
   * @param targetElem The element that needs a rule.
   * @param mode A string indicating the display mode.
   * @param useImports means that this is an xsl:apply-imports commend.
   * @return Rule that best matches targetElem.
   * @exception XSLProcessorException thrown if the active ProblemListener and XMLParserLiaison decide
   * the error condition is severe enough to halt processing.
   */
  public ElemTemplate findTemplate(XSLTEngineImpl transformContext,
                                   Node sourceTree,
                                   Node targetNode,
                                   QName mode,
                                   boolean useImports)
    throws SAXException
  {
    ElemTemplate bestMatchedRule = null;
    MatchPattern2 bestMatchedPattern =null; // Syncs with bestMatchedRule
    if(m_isWrapperless)
    {
      return m_wrapperlessTemplate;
    }
    Vector conflicts = null;
    if(!useImports)
    {
      double highScore = XPath.MATCH_SCORE_NONE;

      MatchPattern2 matchPat = null;
      int targetNodeType = targetNode.getNodeType();

      switch(targetNodeType)
      {
      case Node.ELEMENT_NODE:
        // String targetName = m_parserLiaison.getExpandedElementName((Element)targetNode);
        String targetName = transformContext.m_parserLiaison.getLocalNameOfNode(targetNode);
        matchPat = locateMatchPatternList2(targetName, true);
        break;

      case Node.PROCESSING_INSTRUCTION_NODE:
      case Node.ATTRIBUTE_NODE:
        matchPat = locateMatchPatternList2(targetNode.getNodeName(), true);
        break;

      case Node.CDATA_SECTION_NODE:
      case Node.TEXT_NODE:
        matchPat = locateMatchPatternList2(XPath.PSEUDONAME_TEXT, false);
        break;

      case Node.COMMENT_NODE:
        matchPat = locateMatchPatternList2(XPath.PSEUDONAME_COMMENT, false);
        break;

      case Node.DOCUMENT_NODE:
        matchPat = locateMatchPatternList2(XPath.PSEUDONAME_ROOT, false);
        break;

      case Node.DOCUMENT_FRAGMENT_NODE:
        matchPat = locateMatchPatternList2(XPath.PSEUDONAME_ANY, false);
        break;

      default:
        {
          matchPat = locateMatchPatternList2(targetNode.getNodeName(), false);
        }
      }

      String prevPat = null;
      MatchPattern2 prevMatchPat = null;

      while(null != matchPat)
      {
        ElemTemplate rule = matchPat.getTemplate();
        // We'll be needing to match rules according to what
        // mode we're in.
        QName ruleMode = rule.m_mode;

        // The logic here should be that if we are not in a mode AND
        // the rule does not have a node, then go ahead.
        // OR if we are in a mode, AND the rule has a node,
        // AND the rules match, then go ahead.
        if(((null == mode) && (null == ruleMode)) ||
           ((null != ruleMode) && (null != mode) && ruleMode.equals(mode)))
        {
          String patterns = matchPat.getPattern();

          if((null != patterns) && !((prevPat != null) && prevPat.equals(patterns) &&
                                     (prevMatchPat.getTemplate().m_priority
                                      == matchPat.getTemplate().m_priority)) )
          {
            prevMatchPat = matchPat;
            prevPat = patterns;

            // Date date1 = new Date();
            XPath xpath = matchPat.getExpression();
            // System.out.println("Testing score for: "+targetNode.getNodeName()+
            //                   " against '"+xpath.m_currentPattern);
            double score = xpath.getMatchScore(transformContext.getExecContext(), targetNode);
            // System.out.println("Score for: "+targetNode.getNodeName()+
            //                   " against '"+xpath.m_currentPattern+
            //                   "' returned "+score);

            if(XPath.MATCH_SCORE_NONE != score)
            {
              double priorityOfRule
                = (XPath.MATCH_SCORE_NONE != rule.m_priority)
                  ? rule.m_priority : score;
              matchPat.m_priority = priorityOfRule;
              double priorityOfBestMatched = (null != bestMatchedPattern) ?
                                             bestMatchedPattern.m_priority :
                                             XPath.MATCH_SCORE_NONE;
              // System.out.println("priorityOfRule: "+priorityOfRule+", priorityOfBestMatched: "+priorityOfBestMatched);
              if(priorityOfRule > priorityOfBestMatched)
              {
                if(null != conflicts)
                  conflicts.removeAllElements();
                highScore = score;
                bestMatchedRule = rule;
                bestMatchedPattern = matchPat;
              }
              else if(priorityOfRule == priorityOfBestMatched)
              {
                if(null == conflicts)
                  conflicts = new Vector(10);
                addObjectIfNotFound(bestMatchedPattern, conflicts);
                conflicts.addElement(matchPat);
                highScore = score;
                bestMatchedRule = rule;
                bestMatchedPattern = matchPat;
              }
            }
            // Date date2 = new Date();
            // m_totalTimePatternMatching+=(date2.getTime() - date1.getTime());
          } // end if(null != patterns)
        } // end if if(targetModeString.equals(mode))

        MatchPattern2 nextMatchPat = matchPat.getNext();

        // We also have to consider wildcard matches.
        if((null == nextMatchPat) && !matchPat.m_targetString.equals("*") &&
           ((Node.ELEMENT_NODE == targetNodeType) ||
            (Node.ATTRIBUTE_NODE == targetNodeType) ||
            (Node.PROCESSING_INSTRUCTION_NODE == targetNodeType)))
        {
          nextMatchPat = (MatchPattern2)m_patternTable.get("*");
        }
        matchPat = nextMatchPat;
      }
    } // end if(!useImports)

    if(null == bestMatchedRule)
    {
      int nImports = m_stylesheet.m_imports.size();
      for(int i = 0; i < nImports; i++)
      {
        Stylesheet stylesheet = (Stylesheet)m_stylesheet.m_imports.elementAt(i);
        bestMatchedRule = stylesheet.findTemplate(transformContext, sourceTree, targetNode, mode,
                                                  false);
        if(null != bestMatchedRule)
        {
          break;
        }
      }
    }

    if(null != conflicts)
    {
      int nConflicts = conflicts.size();
      // System.out.println("nConflicts: "+nConflicts);
      String conflictsString = (!transformContext.m_quietConflictWarnings)
                               ? "" : null;
      for(int i = 0; i < nConflicts; i++)
      {
        MatchPattern2 conflictPat = (MatchPattern2)conflicts.elementAt(i);
        if(0 != i)
        {
          if(!transformContext.m_quietConflictWarnings)
            conflictsString += ", ";

          // Find the furthest one towards the bottom of the document.
          if(conflictPat.m_posInStylesheet > bestMatchedPattern.m_posInStylesheet)
          {
            bestMatchedPattern = conflictPat;
          }
        }
        else
        {
          bestMatchedPattern = conflictPat;
        }
        if(!transformContext.m_quietConflictWarnings)
          conflictsString += "\""+conflictPat.getPattern()+"\"";
      }
      bestMatchedRule = bestMatchedPattern.getTemplate();
      if(!transformContext.m_quietConflictWarnings)
      {
        //conflictsString += " ";
        //conflictsString += "Last found in stylesheet will be used.";
        transformContext.warn(XSLTErrorResources.WG_SPECIFICITY_CONFLICTS, new Object[] {conflictsString});
      }
    }

    return bestMatchedRule;
  } // end findTemplate

  /**
   * Add object to vector if not already there.
   */
  private void addObjectIfNotFound(Object obj, Vector v)
  {
    int n = v.size();
    boolean addIt = true;
    for(int i = 0; i < n; i++)
    {
      if(v.elementAt(i) == obj)
      {
        addIt = false;
        break;
      }
    }
    if(addIt)
    {
      v.addElement(obj);
    }
  }

  /**
   * Given an element type, locate the start of a linked list of
   * possible template matches.
   */
  private MatchPattern2 locateMatchPatternList2(String sourceElementType, boolean tryWildCard)
  {
    MatchPattern2 startMatchList = null;
    Object val = m_patternTable.get(sourceElementType);
    if(null != val)
    {
      startMatchList = (MatchPattern2)val;
    }
    else if(tryWildCard)
    {
      val = m_patternTable.get("*");
      if(null != val)
      {
        startMatchList = (MatchPattern2)val;
      }
    }
    return startMatchList;
  }

  /**
   * Add a template to the template list.
   */
  void addTemplate(ElemTemplate template)
  {
    int pos = 0;
    if(null == m_firstTemplate)
    {
      m_firstTemplate = template;
    }
    else
    {
      ElemTemplateElement next = m_firstTemplate;
      while(null != next)
      {
        if(null == next.m_nextSibling)
        {
          next.m_nextSibling = template;
          template.m_nextSibling = null; // just to play it safe.
          break;
        }
        pos++;
        next = next.m_nextSibling;
      }
    }
    if(null != template.m_name)
    {
      m_namedTemplates.put(template.m_name, template);
    }

    if(null != template.m_matchPattern)
    {
      Vector strings = template.m_matchPattern.getTargetElementStrings();
      if(null != strings)
      {
        int nTargets = strings.size();
        for(int stringIndex = 0; stringIndex < nTargets; stringIndex++)
        {
          String target = (String)strings.elementAt(stringIndex);

          Object newMatchPat = new MatchPattern2(template.m_matchPattern.getPatternString(),
                                                 template.m_matchPattern,
                                                 template, pos,
                                                 target, m_stylesheet);

          // See if there's already one there
          Object val = m_patternTable.get(target);
          if(null == val)
          {
            // System.out.println("putting: "+target);
            m_patternTable.put(target, newMatchPat);
          }
          else
          {
            // find the tail of the list
            MatchPattern2 matchPat = (MatchPattern2)val;
            ((MatchPattern2)newMatchPat).setNext(matchPat);
            m_patternTable.put(target, newMatchPat);
            /*
            MatchPattern2 next;
            while((next = matchPat.getNext()) != null)
            {
            matchPat = next;
            }
            // System.out.println("appending: "+target+" to "+matchPat.getPattern());
            matchPat.setNext((MatchPattern2)newMatchPat);
            */
          }
        }
      }
    }
  }

  /**
   * Locate a macro via the "name" attribute.
   * @exception XSLProcessorException thrown if the active ProblemListener and XMLParserLiaison decide
   * the error condition is severe enough to halt processing.
   */
  ElemTemplateElement findNamedTemplate(String name)
    throws XSLProcessorException
  {
    QName qname = new QName(name, m_stylesheet.m_namespaces);

    return findNamedTemplate(qname);
  }

  /**
   * Locate a macro via the "name" attribute.
   * @exception XSLProcessorException thrown if the active ProblemListener and XMLParserLiaison decide
   * the error condition is severe enough to halt processing.
   */
  ElemTemplateElement findNamedTemplate(QName qname)
    throws XSLProcessorException
  {
    ElemTemplateElement namedTemplate = null;
    Object obj = m_namedTemplates.get(qname);
    if(null == obj)
    {
      int nImports = m_stylesheet.m_imports.size();
      for(int i = 0; i < nImports; i++)
      {
        Stylesheet stylesheet = (Stylesheet)m_stylesheet.m_imports.elementAt(i);
        namedTemplate = stylesheet.findNamedTemplate(qname);
        if(null != namedTemplate)
        {
          break;
        }
      }
      if((null == namedTemplate) && (null != m_stylesheet.m_stylesheetParent))
      {
        Stylesheet stylesheet = m_stylesheet.m_stylesheetParent.getPreviousImport(m_stylesheet);
        if(null != stylesheet)
        {
          namedTemplate = stylesheet.findNamedTemplate(qname);
        }
      }
    }
    else
    {
      namedTemplate = (ElemTemplateElement)obj;
    }

    return namedTemplate;
  }

  /**
   * A class to contain a match pattern and it's corresponding template.
   * This class also defines a node in a match pattern linked list.
   */
  class MatchPattern2 implements Serializable
  {
    /**
     * Construct a match pattern from a pattern and template.
     * @param pat For now a Nodelist that contains old-style element patterns.
     * @param template The node that contains the template for this pattern.
     * @param isMatchPatternsOnly tells if pat param contains only match
     * patterns (for compatibility with old syntax).
     */
    MatchPattern2(String pat, XPath exp, ElemTemplate template, int posInStylesheet,
                  String targetString, Stylesheet stylesheet)
    {
      m_pattern = pat;
      m_template = template;
      m_posInStylesheet = posInStylesheet;
      m_targetString = targetString;
      m_stylesheet = stylesheet;
      m_expression = exp;
    }

    Stylesheet m_stylesheet;

    String m_targetString;

    XPath m_expression;
    public XPath getExpression() { return m_expression; }

    int m_posInStylesheet;

    /**
     * Transient... only used to track priority while
     * processing.
     */
    double m_priority = XPath.MATCH_SCORE_NONE;

    private String m_pattern;
    public String getPattern() { return m_pattern; }

    private ElemTemplate m_template; // ref to the corrisponding template
    public ElemTemplate getTemplate() { return m_template; }

    private MatchPattern2 m_next = null; // null when at end of list.
    public MatchPattern2 getNext() { return m_next; }
    public void setNext(MatchPattern2 mp) { m_next = mp; }
  }

}
TOP

Related Classes of org.apache.xalan.xslt.TemplateList$MatchPattern2

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.