You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@xalan.apache.org by mu...@apache.org on 2025/03/22 04:46:43 UTC

(xalan-java) branch xalan-j_xslt3.0_mvn updated: improving implementation of xsl:apply-templates instruction to support xsl 3 use cases, along with related working test case

This is an automated email from the ASF dual-hosted git repository.

mukulg pushed a commit to branch xalan-j_xslt3.0_mvn
in repository https://gitbox.apache.org/repos/asf/xalan-java.git


The following commit(s) were added to refs/heads/xalan-j_xslt3.0_mvn by this push:
     new cce212d98 improving implementation of xsl:apply-templates instruction to support xsl 3 use cases, along with related working test case
cce212d98 is described below

commit cce212d986d219a0ed1cc9bb36bf09f5ea37bafd
Author: Mukul Gandhi <ga...@gmail.com>
AuthorDate: Sat Mar 22 10:16:28 2025 +0530

    improving implementation of xsl:apply-templates instruction to support xsl 3 use cases, along with related working test case
---
 README                                             |   4 +-
 .../apache/xalan/templates/ElemApplyTemplates.java | 148 +++++++++++++++------
 .../org/apache/xalan/templates/TemplateList.java   |  32 ++++-
 .../templates/TemplateSubPatternAssociation.java   |  17 ++-
 .../xslt/util/XslTransformSharedDatastore.java     |   6 +
 .../org/apache/xpath/compiler/XPathParser.java     |  25 +++-
 .../org/apache/xpath/functions/FuncReplace.java    |  12 +-
 .../org/apache/xpath/functions/FuncStartsWith.java |  28 +++-
 .../apache/xalan/tests/xslt3/XslTemplateTests.java |  10 ++
 src/test/resources/xsl_template/gold/test17.out    |  16 +++
 src/test/resources/xsl_template/input.txt          |   7 +
 src/test/resources/xsl_template/test17.xsl         |  60 +++++++++
 12 files changed, 303 insertions(+), 62 deletions(-)

diff --git a/README b/README
index 835d73081..d9e08bffc 100644
--- a/README
+++ b/README
@@ -59,11 +59,11 @@ This produces Maven build output with trailing information like following:
 [INFO]  T E S T S
 [INFO] -------------------------------------------------------
 [INFO] Running org.apache.xalan.tests.main.AllXsl3Tests
-[INFO] Tests run: 948, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 15.548 s - in org.apache.xalan.tests.main.AllXsl3Tests
+[INFO] Tests run: 949, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 44.034 s - in org.apache.xalan.tests.main.AllXsl3Tests
 [INFO]
 [INFO] Results:
 [INFO]
-[INFO] Tests run: 948, Failures: 0, Errors: 0, Skipped: 0
+[INFO] Tests run: 949, Failures: 0, Errors: 0, Skipped: 0
 [INFO]
 [INFO] ------------------------------------------------------------------------
 [INFO] BUILD SUCCESS
diff --git a/src/main/java/org/apache/xalan/templates/ElemApplyTemplates.java b/src/main/java/org/apache/xalan/templates/ElemApplyTemplates.java
index 72d2d043d..de8859b07 100644
--- a/src/main/java/org/apache/xalan/templates/ElemApplyTemplates.java
+++ b/src/main/java/org/apache/xalan/templates/ElemApplyTemplates.java
@@ -20,7 +20,11 @@
  */
 package org.apache.xalan.templates;
 
+import java.util.Hashtable;
+import java.util.Iterator;
 import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
 import java.util.Vector;
 
 import javax.xml.transform.SourceLocator;
@@ -53,6 +57,7 @@ import org.w3c.dom.NodeList;
 import org.xml.sax.SAXException;
 
 import xml.xpath31.processor.types.XSAnyAtomicType;
+import xml.xpath31.processor.types.XSBoolean;
 
 /**
  * Implementation of XSLT xsl:apply-templates element.
@@ -216,8 +221,7 @@ public class ElemApplyTemplates extends ElemCallTemplate
     if (m_selectExpression instanceof XPathSequenceConstructor) {
     	resultSeq = (ResultSequence)(((XPathSequenceConstructor)m_selectExpression).execute(xctxt));
     	
-    	if (isAllSeqItemsXdmAtomicValues(resultSeq)) {
-    		// Added for XSLT 3.0    		
+    	if (isAllSeqItemsXdmAtomicValues(resultSeq)) {    		
     		executeXslTransformAtomicValueSeq(transformer, xctxt, resultSeq);
     		
     		return;
@@ -253,20 +257,8 @@ public class ElemApplyTemplates extends ElemCallTemplate
     		   }
     	   }
        }
-       else if (varEvalResult instanceof XSAnyAtomicType) {
-    	   // Added for XSLT 3.0    	   
-    	   final StylesheetRoot sroot1 = transformer.getStylesheet();
-    	   final TemplateList tlOne = sroot1.getTemplateListComposed();
-    	   ElemTemplate template = tlOne.getTemplate(".");
-    	   
-    	   xctxt.setXPath3ContextItem(varEvalResult);
-    	   
-    	   for (ElemTemplateElement t = template.m_firstChild; t != null; t = t.m_nextSibling) {
-    		   xctxt.setSAXLocator(t);
-    		   transformer.pushElemTemplateElement(t);    		   
-    		   t.execute(transformer);
-    		   transformer.popElemTemplateElement();
-    	   }
+       else if (varEvalResult instanceof XSAnyAtomicType) {   	       	       	   
+    	   executeXslTransformAtomicValue(transformer, xctxt, varEvalResult);
 
     	   return; 
        }
@@ -302,20 +294,8 @@ public class ElemApplyTemplates extends ElemCallTemplate
        else if (varEvalResult instanceof XNodeSet) {
     	   sourceNodes = ((XNodeSet)varEvalResult).asIterator(xctxt, sourceNode);
        }
-       else if (isXdmItemAtomicValue(varEvalResult)) {
-    	   // Added for XSLT 3.0    	   
-    	   final StylesheetRoot sroot1 = transformer.getStylesheet();
-    	   final TemplateList tlOne = sroot1.getTemplateListComposed();
-    	   ElemTemplate template = tlOne.getTemplate(".");
-    	   
-    	   xctxt.setXPath3ContextItem(varEvalResult);
-    	   
-    	   for (ElemTemplateElement t = template.m_firstChild; t != null; t = t.m_nextSibling) {
-    		   xctxt.setSAXLocator(t);
-    		   transformer.pushElemTemplateElement(t);    		   
-    		   t.execute(transformer);
-    		   transformer.popElemTemplateElement();
-    	   }
+       else if (isXdmItemAtomicValue(varEvalResult)) {    	   
+    	   executeXslTransformAtomicValue(transformer, xctxt, varEvalResult);
 
     	   return;
        }
@@ -657,27 +637,115 @@ public class ElemApplyTemplates extends ElemCallTemplate
   }
 
   /**
-   * This method definition does, an XSL transformation of a 
-   * sequence of XDM atomic values.
+   * This method definition does, an XSL transformation for a sequence of 
+   * XDM atomic values.
    */
   private void executeXslTransformAtomicValueSeq(TransformerImpl transformer, final XPathContext xctxt,
 		  														ResultSequence resultSeq) throws TransformerException {
 	  
 	  final StylesheetRoot sroot = transformer.getStylesheet();
 	  final TemplateList tl = sroot.getTemplateListComposed();
-	  ElemTemplate template = tl.getTemplate(".");    		    		
-
+	  
+	  Hashtable templateListHashTable = tl.getPatternTable();
+	  Set hashTableEntrySet = templateListHashTable.entrySet();
+	  Iterator iter = hashTableEntrySet.iterator();
+	  
 	  for (int idx = 0; idx < resultSeq.size(); idx++) {
 		  XObject xObj = resultSeq.item(idx);
+		  executeXslTransformAtomicValue(transformer, xctxt, xObj, iter);
+		  
+		  // Reset an iterator object instance
+		  iter = hashTableEntrySet.iterator();		  
+	  }
+  }
+  
+  /**
+   * This method initializes few XSL transform context variables, and does 
+   * transformation for one XDM atomic value.
+   */
+  private void executeXslTransformAtomicValue(TransformerImpl transformer, final XPathContext xctxt,
+		  														XObject xObj) throws TransformerException {
+	  
+	  final StylesheetRoot sroot = transformer.getStylesheet();
+	  final TemplateList tl = sroot.getTemplateListComposed();
+
+	  Hashtable templateListHashTable = tl.getPatternTable();
+	  Set hashTableEntrySet = templateListHashTable.entrySet();
+	  Iterator iter = hashTableEntrySet.iterator();
+
+	  executeXslTransformAtomicValue(transformer, xctxt, xObj, iter);
+	  
+	  // Reset an iterator object instance
+	  iter = hashTableEntrySet.iterator();
+  }
+
+  /**
+   * This method definition does, an XSL transform for one XDM atomic value.
+   */
+  private void executeXslTransformAtomicValue(TransformerImpl transformer, final XPathContext xctxt, XObject xObj,
+		  									 		   Iterator iter) throws TransformerException {
+	  
+	  ElemTemplate template = null;
+	  
+	  SourceLocator srcLocator = xctxt.getSAXLocator();
+	  
+	  XObject prevCtxItem = xctxt.getXPath3ContextItem();
+	  
+	  while (iter.hasNext()) {
+		  Entry<Object, Object> hashTableEntry = (Entry<Object, Object>)iter.next();
+		  Object hTableKeyObj = hashTableEntry.getKey();
+		  TemplateSubPatternAssociation htValueObj = (TemplateSubPatternAssociation)(hashTableEntry.getValue());		
+		  template = htValueObj.getTemplate();
+		  
 		  xctxt.setXPath3ContextItem(xObj);
-		  for (ElemTemplateElement t = template.m_firstChild; 
-				                                         t != null; t = t.m_nextSibling) {
-			  xctxt.setSAXLocator(t);
-			  transformer.pushElemTemplateElement(t);    		   
-			  t.execute(transformer);
-			  transformer.popElemTemplateElement();
+		  
+		  String keyValueStr = (String)hTableKeyObj;
+		  if (keyValueStr.startsWith(".[")) {				  				  
+			  String xpathStr = keyValueStr.substring(2);
+			  xpathStr = xpathStr.substring(0, xpathStr.length() - 1);
+			  XPath xpath = new XPath(xpathStr, srcLocator, xctxt.getNamespaceContext(), 
+					  																XPath.SELECT, null);						
+			  XObject xpathEvalResult = xpath.execute(xctxt, DTM.NULL, xctxt.getNamespaceContext());						
+			  boolean isSuccess = false;
+			  if (xpathEvalResult instanceof XBooleanStatic) {
+				  XBooleanStatic xBoolStatic = (XBooleanStatic)xpathEvalResult;
+				  isSuccess = xBoolStatic.bool(); 
+			  }
+			  else if (xpathEvalResult instanceof XBoolean) {
+				  XBoolean xBoolean = (XBoolean)xpathEvalResult;
+				  isSuccess = xBoolean.bool(); 
+			  }
+			  else if (xpathEvalResult instanceof XSBoolean) {
+				  XSBoolean xsBoolean = (XSBoolean)xpathEvalResult;
+				  isSuccess = xsBoolean.bool();
+			  }
+
+			  if (isSuccess) {							  	 
+				  for (ElemTemplateElement t = template.m_firstChild; 
+						  									    t != null; t = t.m_nextSibling) {
+					  xctxt.setSAXLocator(t);
+					  transformer.pushElemTemplateElement(t);    		   
+					  t.execute(transformer);
+					  transformer.popElemTemplateElement();
+				  }
+				  
+				  break;
+			  }				  				  
 		  }
+		  else if (".".equals(keyValueStr)) {						 						  		 
+			  for (ElemTemplateElement t = template.m_firstChild; 
+					  										  t != null; t = t.m_nextSibling) {
+				  xctxt.setSAXLocator(t);
+				  transformer.pushElemTemplateElement(t);    		   
+				  t.execute(transformer);
+				  transformer.popElemTemplateElement();
+			  }
+			  
+			  break;
+		  }		  
 	  }
+	  
+	  xctxt.setXPath3ContextItem(prevCtxItem);
   }
 
   /**
diff --git a/src/main/java/org/apache/xalan/templates/TemplateList.java b/src/main/java/org/apache/xalan/templates/TemplateList.java
index 121564a42..186b7003a 100644
--- a/src/main/java/org/apache/xalan/templates/TemplateList.java
+++ b/src/main/java/org/apache/xalan/templates/TemplateList.java
@@ -27,6 +27,7 @@ import java.util.Vector;
 import javax.xml.transform.TransformerException;
 
 import org.apache.xalan.res.XSLTErrorResources;
+import org.apache.xalan.xslt.util.XslTransformSharedDatastore;
 import org.apache.xml.dtm.DTM;
 import org.apache.xml.utils.QName;
 import org.apache.xpath.Expression;
@@ -109,9 +110,10 @@ public class TemplateList implements java.io.Serializable
       
       XPath templateMatchXPath = template.getMatch();
       String xpathPatternStr = templateMatchXPath.getPatternString();
-	  if (".".equalsIgnoreCase(xpathPatternStr)) {
-		 // added for XSLT 3.0		  
-		 m_patternTable.put(String.valueOf(xpathPatternStr), template);
+	  if (".".equals(xpathPatternStr) || xpathPatternStr.startsWith(".[")) {		 		 
+		 insertPatternInTable(String.valueOf(xpathPatternStr), template);
+		 
+		 XslTransformSharedDatastore.templateMatchDotPatternPredicateStr = null;
 	  }
 	  else if (matchExpr instanceof StepPattern)
       {
@@ -135,7 +137,7 @@ public class TemplateList implements java.io.Serializable
     }
   }
 
-  /** Flag to indicate whether in DEBUG mode          */
+/** Flag to indicate whether in DEBUG mode          */
   final static boolean DEBUG = false;
 
   /**
@@ -196,7 +198,7 @@ public class TemplateList implements java.io.Serializable
       Enumeration associations = m_patternTable.elements();
 
       while (associations.hasMoreElements())
-      {
+      {    	
         TemplateSubPatternAssociation head =
           (TemplateSubPatternAssociation) associations.nextElement();
         TemplateSubPatternAssociation wild = m_wildCardPatterns;
@@ -382,6 +384,22 @@ public class TemplateList implements java.io.Serializable
       }
     }
   }
+  
+  /**
+   * Add a template to the template list.
+   * 
+   * This method definition supports, XSLT 3.0 xsl:template match pattern 
+   * strings ".", .[...].
+   *
+   * @param pattern
+   * @param template
+   */
+  private void insertPatternInTable(String xpathMatchPatternStr, ElemTemplate template) {		
+	  TemplateSubPatternAssociation association =
+			  								new TemplateSubPatternAssociation(template, null, xpathMatchPatternStr);
+
+	  m_patternTable.put(xpathMatchPatternStr, association);
+  }
 
   /**
    * Given a match pattern and template association, return the 
@@ -937,4 +955,8 @@ public class TemplateList implements java.io.Serializable
     }
   }
 
+  public Hashtable getPatternTable() {
+	  return m_patternTable;
+  }
+
 }
diff --git a/src/main/java/org/apache/xalan/templates/TemplateSubPatternAssociation.java b/src/main/java/org/apache/xalan/templates/TemplateSubPatternAssociation.java
index 0ff01ebe2..d23ac78d7 100644
--- a/src/main/java/org/apache/xalan/templates/TemplateSubPatternAssociation.java
+++ b/src/main/java/org/apache/xalan/templates/TemplateSubPatternAssociation.java
@@ -63,12 +63,17 @@ class TemplateSubPatternAssociation implements Serializable, Cloneable
    */
   TemplateSubPatternAssociation(ElemTemplate template, StepPattern pattern, String pat)
   {
-
-    m_pattern = pat;
-    m_template = template;
-    m_stepPattern = pattern;
-    m_targetString = m_stepPattern.getTargetString();
-    m_wild = m_targetString.equals("*");
+	  m_pattern = pat;
+	  m_template = template;
+	  m_stepPattern = pattern;	  
+	  if (m_stepPattern != null) {
+		  m_targetString = m_stepPattern.getTargetString();
+		  m_wild = m_targetString.equals("*");
+	  }
+	  else {
+		  m_targetString = m_pattern;
+		  m_wild = m_targetString.equals("*");
+	  }
   }
 
   /**
diff --git a/src/main/java/org/apache/xalan/xslt/util/XslTransformSharedDatastore.java b/src/main/java/org/apache/xalan/xslt/util/XslTransformSharedDatastore.java
index a01d65e8a..e24689521 100644
--- a/src/main/java/org/apache/xalan/xslt/util/XslTransformSharedDatastore.java
+++ b/src/main/java/org/apache/xalan/xslt/util/XslTransformSharedDatastore.java
@@ -71,5 +71,11 @@ public class XslTransformSharedDatastore {
      * intersect or except.
      */
     public static StringBuffer xpathNodeCombiningExprRhsStrBuff;
+    
+    /**
+     * This class field represents, XPath predicate suffix of XSL 
+     * template definition like xsl:template match=".[..]".
+     */
+    public static String templateMatchDotPatternPredicateStr;
 
 }
diff --git a/src/main/java/org/apache/xpath/compiler/XPathParser.java b/src/main/java/org/apache/xpath/compiler/XPathParser.java
index 8e9737f6b..f7d90e4fd 100644
--- a/src/main/java/org/apache/xpath/compiler/XPathParser.java
+++ b/src/main/java/org/apache/xpath/compiler/XPathParser.java
@@ -157,8 +157,8 @@ public class XPathParser
    * we translate that within this XPath parser implementation, to an XPath
    * range "to" expression using this class field (this equivalently produces
    * an xdm empty sequence). There may be other direct ways of implementing this.
-   * Pls review.
    */
+  // REVISIT
   public static final String XPATH_EXPR_STR_EMPTY_SEQUENCE = "1 to 0";
   
   private static final List<String> XPATH_OP_ARR_TOKENS_LIST = Arrays.asList(XPATH_OP_ARR);
@@ -1642,12 +1642,15 @@ public class XPathParser
    * For named function references specified with syntax functionNameString#integerLiteral,
    * check whether integerLiteral (i.e, function arity, of the function to be called) is 
    * an integer >= 0.
+   * 
+   * Function arity is defined as, "The number of arguments the function accepts".
    */
   private boolean isFuncArityWellFormedForNamedFuncRef(String funcRefStr) {	  
+	 
 	 boolean isFuncArityWellFormed = true;
 	 
 	 int idx = funcRefStr.indexOf('#');
-	 String intStr = funcRefStr.substring(idx+1);
+	 String intStr = funcRefStr.substring(idx + 1);
 	 Integer intVal = null;
 	 try {
 	    intVal = Integer.valueOf(intStr);
@@ -4587,12 +4590,28 @@ public class XPathParser
     	// strings, that represent XDM atomic values.
     	Object nodeTestOp = Keywords.getNodeType(m_token);
     	
-    	int nt = ((Integer) nodeTestOp).intValue();
+    	int nt = ((Integer)nodeTestOp).intValue();
 
         m_ops.setOp(m_ops.getOp(OpMap.MAPINDEX_LENGTH), nt);
         m_ops.setOp(OpMap.MAPINDEX_LENGTH, m_ops.getOp(OpMap.MAPINDEX_LENGTH) + 1);
         
         consumeExpected('.');
+        
+        if (tokenIs('[')) {
+           StringBuffer strBuff = new StringBuffer();
+           consumeExpected('[');
+           while (m_token != null) {
+        	  if (tokenIs(']')) {
+        		 consumeExpected(']');  
+        	  }
+        	  else {
+        		 strBuff.append(m_token);
+        		 nextToken();
+        	  }
+           }
+           
+           XslTransformSharedDatastore.templateMatchDotPatternPredicateStr = strBuff.toString();
+        }
     }
     else
     {
diff --git a/src/main/java/org/apache/xpath/functions/FuncReplace.java b/src/main/java/org/apache/xpath/functions/FuncReplace.java
index 8552dfe1e..836a4a17d 100644
--- a/src/main/java/org/apache/xpath/functions/FuncReplace.java
+++ b/src/main/java/org/apache/xpath/functions/FuncReplace.java
@@ -25,6 +25,7 @@ import javax.xml.transform.SourceLocator;
 import org.apache.xalan.res.XSLMessages;
 import org.apache.xalan.xslt.util.XslTransformEvaluationHelper;
 import org.apache.xpath.XPathContext;
+import org.apache.xpath.axes.SelfIteratorNoPredicate;
 import org.apache.xpath.objects.XObject;
 import org.apache.xpath.regex.Matcher;
 import org.apache.xpath.regex.PatternSyntaxException;
@@ -58,8 +59,15 @@ public class FuncReplace extends Function4Args {
         XObject result = null;
         
 	    SourceLocator srcLocator = xctxt.getSAXLocator();
-        
-        String inputStr = XslTransformEvaluationHelper.getStrVal(m_arg0.execute(xctxt));
+	    
+	    XObject xpath3ContextItem = xctxt.getXPath3ContextItem();
+	    String inputStr = null;
+	    if ((m_arg0 instanceof SelfIteratorNoPredicate) && (xpath3ContextItem != null)) {
+	       inputStr = XslTransformEvaluationHelper.getStrVal(xpath3ContextItem); 
+	    }
+	    else {
+           inputStr = XslTransformEvaluationHelper.getStrVal(m_arg0.execute(xctxt));
+	    }
         String patternStr = XslTransformEvaluationHelper.getStrVal(m_arg1.execute(xctxt));
         String replacementStr = XslTransformEvaluationHelper.getStrVal(m_arg2.execute(xctxt));
         
diff --git a/src/main/java/org/apache/xpath/functions/FuncStartsWith.java b/src/main/java/org/apache/xpath/functions/FuncStartsWith.java
index e99773318..8f57394c2 100644
--- a/src/main/java/org/apache/xpath/functions/FuncStartsWith.java
+++ b/src/main/java/org/apache/xpath/functions/FuncStartsWith.java
@@ -20,12 +20,15 @@
  */
 package org.apache.xpath.functions;
 
+import org.apache.xalan.xslt.util.XslTransformEvaluationHelper;
 import org.apache.xpath.XPathContext;
+import org.apache.xpath.axes.SelfIteratorNoPredicate;
 import org.apache.xpath.objects.XBoolean;
 import org.apache.xpath.objects.XObject;
 
 /**
- * Execute the StartsWith() function.
+ * Implementation of XPath fn:starts-with function.
+ * 
  * @xsl.usage advanced
  */
 public class FuncStartsWith extends Function2Args
@@ -33,8 +36,9 @@ public class FuncStartsWith extends Function2Args
     static final long serialVersionUID = 2194585774699567928L;
 
   /**
-   * Execute the function.  The function must return
+   * Execute the function. The function must return
    * a valid object.
+   * 
    * @param xctxt The current execution context.
    * @return A valid XObject.
    *
@@ -42,7 +46,23 @@ public class FuncStartsWith extends Function2Args
    */
   public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException
   {
-    return m_arg0.execute(xctxt).xstr().startsWith(m_arg1.execute(xctxt).xstr())
-           ? XBoolean.S_TRUE : XBoolean.S_FALSE;
+	  XObject result = null;
+    
+	  XObject xpath3ContextItem = xctxt.getXPath3ContextItem();
+	  
+	  XObject arg1XObj = m_arg1.execute(xctxt);
+	  String arg1StrValue = XslTransformEvaluationHelper.getStrVal(arg1XObj);
+
+	  if ((m_arg0 instanceof SelfIteratorNoPredicate) && (xpath3ContextItem != null)) {
+		  String arg0StrValue = XslTransformEvaluationHelper.getStrVal(xpath3ContextItem);		  
+		  result = arg0StrValue.startsWith(arg1StrValue) ? XBoolean.S_TRUE : XBoolean.S_FALSE;   
+	  }
+	  else {
+		  XObject xpathEvalResult = m_arg0.execute(xctxt);
+		  String arg0StrValue = XslTransformEvaluationHelper.getStrVal(xpathEvalResult);
+		  result = arg0StrValue.startsWith(arg1StrValue) ? XBoolean.S_TRUE : XBoolean.S_FALSE;
+	  }
+    
+      return result;
   }
 }
diff --git a/src/test/java/org/apache/xalan/tests/xslt3/XslTemplateTests.java b/src/test/java/org/apache/xalan/tests/xslt3/XslTemplateTests.java
index 963a1bb5d..5714f52ec 100644
--- a/src/test/java/org/apache/xalan/tests/xslt3/XslTemplateTests.java
+++ b/src/test/java/org/apache/xalan/tests/xslt3/XslTemplateTests.java
@@ -207,5 +207,15 @@ public class XslTemplateTests extends XSLTransformTestsUtil {
         
         runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
     }
+    
+    @Test
+    public void xslTemplateTest17() {
+        String xmlFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test17.xsl"; 
+        String xslFilePath = XSL_TRANSFORM_INPUT_DIRPATH + "test17.xsl";
+        
+        String goldFilePath = XSL_TRANSFORM_GOLD_DIRPATH + "test17.out";                
+        
+        runXslTransformAndAssertOutput(xmlFilePath, xslFilePath, goldFilePath, null);
+    }
 
 }
diff --git a/src/test/resources/xsl_template/gold/test17.out b/src/test/resources/xsl_template/gold/test17.out
new file mode 100644
index 000000000..650f441e5
--- /dev/null
+++ b/src/test/resources/xsl_template/gold/test17.out
@@ -0,0 +1,16 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>XSL transformation result</title>
+</head>
+<body>
+<br>
+<h3>Hello world, this text file is used for testing purpose</h3>
+<h1> Thanks for reading this</h1>
+<h3>Many thanks</h3>
+<h2> Thank you</h2>
+<h1> Your's sincerely</h1>
+<h3>--</h3>
+<h3>Apache Xalan</h3>
+</body>
+</html>
diff --git a/src/test/resources/xsl_template/input.txt b/src/test/resources/xsl_template/input.txt
new file mode 100644
index 000000000..538546414
--- /dev/null
+++ b/src/test/resources/xsl_template/input.txt
@@ -0,0 +1,7 @@
+Hello world, this text file is used for testing purpose
+== Thanks for reading this
+Many thanks
+:: Thank you
+== Your's sincerely
+--
+Apache Xalan
diff --git a/src/test/resources/xsl_template/test17.xsl b/src/test/resources/xsl_template/test17.xsl
new file mode 100644
index 000000000..2a7f15a2c
--- /dev/null
+++ b/src/test/resources/xsl_template/test17.xsl
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:xs="http://www.w3.org/2001/XMLSchema"
+				exclude-result-prefixes="xs"
+			    version="3.0">
+			    
+  <!-- Author: mukulg@apache.org -->
+
+  <!--  An XSL 3 stylesheet test case, to test xsl:template match 
+        with pattern ".", and ".[...]" (i.e, XPath string "." 
+        followed by an XPath predicate.
+        
+        This XSL stylesheet example's algorithm has been borrowed
+        from XSLT 3.0 spec.         
+  -->			     
+
+  <xsl:output method="html"/>
+
+  <xsl:template match="/">
+      <html>
+	     <head>
+		   <title>XSL transformation result</title>
+		 </head>
+		 <body>		   
+		   <br/><xsl:apply-templates select="unparsed-text-lines('input.txt')"/>
+		 </body>
+	  </html>
+  </xsl:template>
+  
+  <xsl:template match=".[starts-with(., '==')]">
+    <h1><xsl:value-of select="replace(., '==', '')"/></h1>
+  </xsl:template>
+  
+  <xsl:template match=".[starts-with(., '::')]">
+    <h2><xsl:value-of select="replace(., '::', '')"/></h2>
+  </xsl:template>
+
+  <xsl:template match=".">
+    <h3><xsl:value-of select="."/></h3>
+  </xsl:template>
+  
+  <!--
+      * Licensed to the Apache Software Foundation (ASF) under one
+      * or more contributor license agreements. See the NOTICE file
+      * distributed with this work for additional information
+      * regarding copyright ownership. The ASF licenses this file
+      * to you under the Apache License, Version 2.0 (the "License");
+      * you may not use this file except in compliance with the License.
+      * You may obtain a copy of the License at
+      *
+      *     http://www.apache.org/licenses/LICENSE-2.0
+      *
+      * Unless required by applicable law or agreed to in writing, software
+      * distributed under the License is distributed on an "AS IS" BASIS,
+      * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+      * See the License for the specific language governing permissions and
+      * limitations under the License.
+  -->
+
+</xsl:stylesheet>


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@xalan.apache.org
For additional commands, e-mail: commits-help@xalan.apache.org