/*
 * 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.
 */
package org.apache.xalan.templates;

import java.util.List;
import java.util.Map;
import java.util.Vector;

import javax.xml.transform.SourceLocator;
import javax.xml.transform.TransformerException;

import org.apache.xalan.transformer.TransformerImpl;
import org.apache.xalan.xslt.util.StringUtil;
import org.apache.xalan.xslt.util.XslTransformData;
import org.apache.xalan.xslt.util.XslTransformEvaluationHelper;
import org.apache.xml.dtm.DTM;
import org.apache.xml.dtm.DTMCursorIterator;
import org.apache.xml.dtm.DTMManager;
import org.apache.xml.serializer.SerializationHandler;
import org.apache.xpath.Expression;
import org.apache.xpath.XPath;
import org.apache.xpath.XPathContext;
import org.apache.xpath.axes.LocPathIterator;
import org.apache.xpath.compiler.Keywords;
import org.apache.xpath.composite.XPathIfExpr;
import org.apache.xpath.composite.XPathLetExpr;
import org.apache.xpath.composite.XPathNamedFunctionReference;
import org.apache.xpath.functions.FuncRound;
import org.apache.xpath.functions.Function;
import org.apache.xpath.functions.WrongNumberArgsException;
import org.apache.xpath.functions.XPathDynamicFunctionCall;
import org.apache.xpath.functions.XSL3ConstructorOrExtensionFunction;
import org.apache.xpath.functions.XSL3FunctionService;
import org.apache.xpath.objects.ResultSequence;
import org.apache.xpath.objects.XMLNodeCursorImpl;
import org.apache.xpath.objects.XNumber;
import org.apache.xpath.objects.XObject;
import org.apache.xpath.objects.XPathArray;
import org.apache.xpath.objects.XPathMap;
import org.apache.xpath.objects.XString;
import org.apache.xpath.operations.Div;
import org.apache.xpath.operations.Operation;
import org.apache.xpath.operations.Variable;
import org.apache.xpath.types.DateTimeUtil;
import org.w3c.dom.DOMException;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import xml.xpath31.processor.types.XSAnyType;
import xml.xpath31.processor.types.XSDateTime;
import xml.xpath31.processor.types.XSDayTimeDuration;
import xml.xpath31.processor.types.XSDecimal;
import xml.xpath31.processor.types.XSDouble;
import xml.xpath31.processor.types.XSInteger;
import xml.xpath31.processor.types.XSNumericType;
import xml.xpath31.processor.types.XSQName;
import xml.xpath31.processor.types.XSString;

/**
 * Implementation of XSLT 3.0 xsl:value-of instruction.
 * 
 * @author Scott Boag <scott_boag@us.ibm.com>
 * @author Ilene Seelemann
 *         Morris Kwan <mkwan@apache.org>, Christine Li <jycli@apache.org>
 *         
 * @author Mukul Gandhi <mukulg@apache.org>
 *         (XSLT 3.0 specific changes, to this class)
 * 
 * @xsl.usage advanced
 */
public class ElemValueOf extends ElemTemplateElement {
    
  static final long serialVersionUID = 3490728458007586786L;

  /**
   * The select expression to be executed.
   */
  private XPath m_selectExpression = null;

  /**
   * True if the pattern is a simple ".".
   */
  private boolean m_isDot = false;
  
  /**
   * This class field is used during, XPath.fixupVariables(..) action 
   * as performed within object of this class.  
   */    
  private Vector m_vars;
  
  /**
   * This class field is used during, XPath.fixupVariables(..) action 
   * as performed within object of this class.  
   */
  private int m_globals_size;

  /**
   * Set the "select" attribute.
   * The required select attribute is an expression; this expression
   * is evaluated and the resulting object is converted to a
   * string as if by a call to the string function.
   *
   * @param v The value to set for the "select" attribute.
   */
  public void setSelect(XPath v)
  {

    if (null != v)
    {
      String s = v.getPatternString();

      m_isDot = (null != s) && s.equals(".");
    }

    m_selectExpression = v;
  }

  /**
   * Get the "select" attribute.
   * The required select attribute is an expression; this expression
   * is evaluated and the resulting object is converted to a
   * string as if by a call to the string function.
   *
   * @return The value of the "select" attribute.
   */
  public XPath getSelect()
  {
    return m_selectExpression;
  }
  
  /**
   * The separator attribute value.
   */
  private AVT m_separator = null;

  /**
   * Set the value of separator attribute. 
   */
  public void setSeparator(AVT separator) {
	  m_separator = separator; 
  }

  /**
   * Get the value of separator attribute. 
   */
  public AVT getSeparator() {
	  return m_separator; 
  }

  /**
   * Tells if this element should disable escaping.
   * 
   */
  private boolean m_disableOutputEscaping = false;

  /**
   * Set the "disable-output-escaping" attribute.
   * Normally, the xml output method escapes & and < (and
   * possibly other characters) when outputting text nodes.
   * This ensures that the output is well-formed XML. However,
   * it is sometimes convenient to be able to produce output
   * that is almost, but not quite well-formed XML; for
   * example, the output may include ill-formed sections
   * which are intended to be transformed into well-formed
   * XML by a subsequent non-XML aware process. For this reason,
   * XSLT provides a mechanism for disabling output escaping.
   * An xsl:value-of or xsl:text element may have a
   * disable-output-escaping attribute; the allowed values
   * are yes or no; the default is no; if the value is yes,
   * then a text node generated by instantiating the xsl:value-of
   * or xsl:text element should be output without any escaping.
   * @see <a href="http://www.w3.org/TR/xslt#disable-output-escaping">disable-output-escaping in XSLT Specification</a>
   *
   * @param v The value to set for the "disable-output-escaping" attribute.
   */
  public void setDisableOutputEscaping(boolean v)
  {
    m_disableOutputEscaping = v;
  }

  /**
   * Get the "disable-output-escaping" attribute.
   * Normally, the xml output method escapes & and < (and
   * possibly other characters) when outputting text nodes.
   * This ensures that the output is well-formed XML. However,
   * it is sometimes convenient to be able to produce output
   * that is almost, but not quite well-formed XML; for
   * example, the output may include ill-formed sections
   * which are intended to be transformed into well-formed
   * XML by a subsequent non-XML aware process. For this reason,
   * XSLT provides a mechanism for disabling output escaping.
   * An xsl:value-of or xsl:text element may have a
   * disable-output-escaping attribute; the allowed values
   * are yes or no; the default is no; if the value is yes,
   * then a text node generated by instantiating the xsl:value-of
   * or xsl:text element should be output without any escaping.
   * @see <a href="http://www.w3.org/TR/xslt#disable-output-escaping">disable-output-escaping in XSLT Specification</a>
   *
   * @return The value of the "disable-output-escaping" attribute.
   */
  public boolean getDisableOutputEscaping()
  {
    return m_disableOutputEscaping;
  }
  
  /**
   * Class field, that represents the value of "xpath-default-namespace" 
   * attribute.
   */
  private String m_xpath_default_namespace = null;

  /**
   * Set the value of "xpath-default-namespace" attribute.
   *
   * @param v   Value of the "xpath-default-namespace" attribute
   */
  public void setXpathDefaultNamespace(String v)
  {
	  m_xpath_default_namespace = v; 
  }

  /**
   * Get the value of "xpath-default-namespace" attribute.
   *  
   * @return		  The value of "xpath-default-namespace" attribute 
   */
  public String getXpathDefaultNamespace() {
	  return m_xpath_default_namespace;
  }
  
  /**
   * Variable to indicate whether, an attribute 'expand-text'
   * is declared on xsl:value-of instruction.
   */
  private boolean m_expand_text_declared;
  
  /**
   * Class field, that represents the value of "expand-text" 
   * attribute.
   */
  private boolean m_expand_text;

  /**
   * Set the value of "expand-text" attribute.
   *
   * @param v   Value of the "expand-text" attribute
   */
  public void setExpandText(boolean v)
  {
	  m_expand_text = v;
	  m_expand_text_declared = true;
  }

  /**
   * Get the value of "expand-text" attribute.
   *  
   * @return		  The value of "expand-text" attribute 
   */
  public boolean getExpandText() {
	  return m_expand_text;
  }
  
  /**
   * Get a boolean value indicating whether, an "expand-text" 
   * attribute has been declared. 
   */
  public boolean getExpandTextDeclared() {
	  return m_expand_text_declared;
  }
  
  /**
   * An XPath expression for 'use-when' attribute. 
   */
  private XPath m_useWhen = null;

  /**
   * Method definition, to set the value of XSL attribute 
   * "use-when".
   * 
   * @param xpath            XPath expression for attribute "use-when"
   */
  public void setUseWhen(XPath xpath)
  {
	  m_useWhen = xpath;  
  }

  /**
   * Method definition, to get the value of XSL attribute 
   * "use-when".
   * 
   * @return			XPath expression for attribute "use-when"
   */
  public XPath getUseWhen()
  {
	  return m_useWhen;
  }

  /**
   * Get an integer representation of the element type.
   *
   * @return An integer representation of the element, defined in the
   *     Constants class.
   * @see org.apache.xalan.templates.Constants
   */
  public int getXSLToken()
  {
    return Constants.ELEMNAME_VALUEOF;
  }

  /**
   * This function is called after everything else has been
   * recomposed, and allows the template to set remaining
   * values that may be based on some other property that
   * depends on recomposition.
   *
   * NEEDSDOC @param sroot
   *
   * @throws TransformerException
   */
  public void compose(StylesheetRoot sroot) throws TransformerException
  {

    super.compose(sroot);

    java.util.Vector vnames = (sroot.getComposeState()).getVariableNames();
    
    m_vars = (Vector)(vnames.clone()); 
    m_globals_size = (sroot.getComposeState()).getGlobalsSize();

    if (m_selectExpression != null) {
        m_selectExpression.fixupVariables(vnames, m_globals_size);
    }
  }

  /**
   * Return the node name.
   *
   * @return The node name
   */
  public String getNodeName()
  {
    return Constants.ELEMNAME_VALUEOF_STRING;
  }

  /**
   * Execute the string expression and copy the text to the
   * result tree.
   * The required select attribute is an expression; this expression
   * is evaluated and the resulting object is converted to a string
   * as if by a call to the string function. The string specifies
   * the string-value of the created text node. If the string is
   * empty, no text node will be created. The created text node will
   * be merged with any adjacent text nodes.
   * @see <a href="http://www.w3.org/TR/xslt#value-of">value-of in XSLT Specification</a>
   *
   * @param transformer non-null reference to the the current transform-time state.
   *
   * @throws TransformerException
   */
  public void execute(TransformerImpl transformer) throws TransformerException
  {

    XPathContext xctxt = transformer.getXPathContext();
    
    SourceLocator srcLocator = xctxt.getSAXLocator();
    
    final int sourceNode = xctxt.getCurrentNode();
    
    if (m_useWhen != null) {
    	boolean result1 = isXPathExpressionStatic(m_useWhen.getExpression());
    	if (result1) {
    		XObject useWhenResult = m_useWhen.execute(xctxt, sourceNode, xctxt.getNamespaceContext());
    		if (!useWhenResult.bool()) {
    			return;
    		}
    	}
    	else {
    		throw new TransformerException("XPST0008 : XSL variables other than XSLT static variables/parameters, cannot be "
                    																									+ "used within XPath static expression.", srcLocator);
    	}
    }
    
    SerializationHandler rth = transformer.getResultTreeHandler();

    if (transformer.getDebug())
      transformer.getTraceManager().emitTraceEvent(this);

    try
    {     
    	if ((m_selectExpression != null) && (m_xpath_default_namespace != null)) {    		
    	   m_selectExpression = new XPath(m_selectExpression.getPatternString(), srcLocator, xctxt.getNamespaceContext(), XPath.SELECT, null);
    	}
    	
        xctxt.pushNamespaceContext(this);

        int current = xctxt.getCurrentNode();

        xctxt.pushCurrentNodeAndExpression(current, current);
        
        String separatorStrValue = null;
        if (m_separator != null) {
           separatorStrValue = m_separator.evaluate(xctxt, current, this);
        }
        
        if (m_disableOutputEscaping)
            rth.processingInstruction(
              javax.xml.transform.Result.PI_DISABLE_OUTPUT_ESCAPING, "");

        try
        {
          Expression expr = null;
          
          if (m_selectExpression != null) {        	  
        	 Node childNode = getFirstChild();
        	 if (childNode != null) {
                throw new TransformerException("XTSE0870 : An XSL 'value-of' instruction cannot have both a "
                		                                    + "'select' attribute and non-empty content.", srcLocator);
        	 }
        	 else {
        		expr = m_selectExpression.getExpression();        		
        	 }
          }          
          else {
        	  evaluateXslValueOfSeqConstructorAndEmitResult(transformer, xctxt, rth, separatorStrValue);
        	  
        	  return;
          }
          
          if ((XslTransformData.m_is_xsl_test_invocation) && (expr instanceof LocPathIterator)) {
        	  // Support for, Xalan-J's test driver for W3C XSLT 3.0 test suite
        	  
        	  LocPathIterator locPathIterator = (LocPathIterator)expr;
        	  
        	  try {
        		  DTMCursorIterator dtmIter = locPathIterator.asIterator(xctxt, current);
        		  
        		  // If a non-empty node exists, return true else return false
        		  if (dtmIter.nextNode() != DTM.NULL) {
        			  (new XString("true")).dispatchCharactersEvents(rth);
        		  }
        		  else {
        			  (new XString("false")).dispatchCharactersEvents(rth);
        		  }
        		  
        		  return;
        	  }
        	  catch (Exception ex) {
        		  // no op 
        	  }
          }

          if (transformer.getDebug())
          {
            XObject obj = expr.execute(xctxt);

            transformer.getTraceManager().emitSelectedEvent(current, this, "select", 
            		                                                             m_selectExpression, obj);
            obj.dispatchCharactersEvents(rth);
          }
          else
          {
              XObject xpath3ContextItem = xctxt.getXPath3ContextItem();
              
              if (m_isDot && xpath3ContextItem != null) {                  
                  String strValue = XslTransformEvaluationHelper.getStrVal(xpath3ContextItem);
                  if (separatorStrValue != null) {
                	 strValue = strValue.replace(" ", separatorStrValue);
                  }
                  
                  (new XString(strValue)).dispatchCharactersEvents(rth);
              }
              else {
                  if (expr instanceof XSL3ConstructorOrExtensionFunction) {
                	  XSL3ConstructorOrExtensionFunction xpathFunc = (XSL3ConstructorOrExtensionFunction)expr;
                	  XSL3FunctionService xslFunctionService = xctxt.getXSLFunctionService();
                      
                	  XObject evalResult = xslFunctionService.callFunction(xpathFunc, transformer, xctxt);
                      
                      if (evalResult != null) {
                    	  if (evalResult instanceof XSDayTimeDuration) {
                    		  serializeXsDaytimeDurationValue((XSDayTimeDuration)evalResult, 3, xctxt, rth);
                    	  }
                    	  else if (evalResult instanceof XSQName) {
                    		  XSQName xsQName = (XSQName)evalResult;
                    		  String nsPrefix = xsQName.getPrefix();
                    		  String strValue = null;
                    		  if ((nsPrefix != null) && !"".equals(nsPrefix)) {
                    			 strValue = nsPrefix + ":" + xsQName.getLocalPart(); 
                    		  }
                    		  else {
                    			 strValue = ((XSQName) evalResult).stringValue();  
                    		  }                    		                      		  
                    		  
                    		  (new XString(strValue)).dispatchCharactersEvents(rth);
                    	  }
                    	  else if (evalResult instanceof ResultSequence) {
                    		  ResultSequence rSeq = (ResultSequence)evalResult;
                    		  int rSeqLength = rSeq.size();
                    		  StringBuffer strBuff = new StringBuffer(); 
                    		  for (int idx = 0; idx < rSeqLength; idx++) {
                    			 XObject xObj1 = rSeq.item(idx);
                    			 String strValue = XslTransformEvaluationHelper.getStrVal(xObj1);                    			                     			 
                    			 if (idx < (rSeqLength - 1)) {
                    				if (separatorStrValue == null) {
                    				   strBuff.append(strValue + " ");
                    				}
                    				else {
                    				   strBuff.append(strValue + separatorStrValue);
                    				}
                    			 }
                    			 else {
                    				 strBuff.append(strValue); 
                    			 }
                    		  }
                    		  
                    		  String strValue = strBuff.toString(); 
                    		  
                    		  (new XString(strValue)).dispatchCharactersEvents(rth);
                    	  }
                    	  else {
                    		  String strValue = XslTransformEvaluationHelper.getStrVal(evalResult);                                                       
                    		  strValue = preProcessStrBeforeXslSerialization(strValue);                    		  
                    		  if (separatorStrValue != null) {
                    			 strValue = strValue.replace(" ", separatorStrValue); 
                    		  }
                    		  
                    		  (new XString(strValue)).dispatchCharactersEvents(rth);
                    	  }
                      }
                      else {
                          expr.executeCharsToContentHandler(xctxt, rth);   
                      }
                  }
                  else if (expr instanceof Function) {
                      XObject evalResult = ((Function)expr).execute(xctxt);
                      
                      if (evalResult instanceof XSQName) {
                    	 XSQName xsQName = (XSQName)evalResult;
                    	 String localPart = xsQName.getLocalPart();
                    	 if ((Constants.ANONYMOUS_FUNCTION).equals(localPart)) {
                    		 evalResult = new ResultSequence(); 
                    	 }
                      }
                      
                      String strValue = null;                      
                      if (evalResult instanceof XSAnyType) {
                    	  if (evalResult instanceof XSQName) {
                    		 XSQName xsQname = (XSQName)evalResult;
                    		 String localName = xsQname.getLocalPart();
                    		 String prefix = xsQname.getPrefix();
                    		 if ((prefix != null) && !"".equals(prefix)) {
                    			strValue = prefix + ":" + localName; 
                    		 }
                    		 else {
                    			strValue = ((XSQName)evalResult).stringValue(); 
                    		 }
                    	  }
                    	  else {
                    		 strValue = XslTransformEvaluationHelper.getStrVal(evalResult);
                    	  }
                      }                                            
                      else if (evalResult instanceof XMLNodeCursorImpl) {
                    	  XMLNodeCursorImpl xmlNodeCursorImpl = (XMLNodeCursorImpl)evalResult;
                    	  DTMCursorIterator dtmCursorIter = xmlNodeCursorImpl.iterRaw();
                    	  int nextNode;
                    	  StringBuffer strBuffer = new StringBuffer();
                    	  while ((nextNode = dtmCursorIter.nextNode()) != DTM.NULL) {
                    		  XMLNodeCursorImpl node = new XMLNodeCursorImpl(nextNode, xctxt);
                    		  strBuffer.append(node.str() + " ");
                    	  }
                    	  
                    	  strValue = (strBuffer.toString()).trim(); 
                      }
                      else if (evalResult instanceof ResultSequence) {
                    	  strValue = getEffectiveSequenceStrValue((ResultSequence)evalResult, separatorStrValue);
                      }
                      else if (evalResult instanceof XPathArray) {
                    	  XPathArray xpathArr = (XPathArray)evalResult;
                    	  List<XObject> nativeArr = xpathArr.getNativeArray();

                    	  ResultSequence rSeq = new ResultSequence();
                    	  for (int idx = 0; idx < nativeArr.size(); idx++) {                           
                    		  rSeq.add(nativeArr.get(idx));
                    	  }

                    	  strValue = getEffectiveSequenceStrValue(rSeq, separatorStrValue);
                      }
                      else if (evalResult instanceof XPathMap) {                    	                      	  
                    	  String xpathPatternStr = m_selectExpression.getPatternString();
                    	  if (xpathPatternStr.startsWith(Keywords.FUNC_RANDOM_NUMBER_GENERATOR + "(") 
                    			                                                && xpathPatternStr.endsWith("?" + 
                    	                                                                                   Constants.ATTRVAL_DATATYPE_NUMBER)) {
                    		  XPathMap xpathMap = (XPathMap)evalResult;
                    		  Map<XObject,XObject> nativeMap = xpathMap.getNativeMap();
                    		  XObject xObj = nativeMap.get(new XSString(Constants.ATTRVAL_DATATYPE_NUMBER));
                    		  XSDouble xsDouble = (XSDouble)xObj;
                    		  XString xString = new XString(xsDouble.stringValue());
                    		  xString.dispatchCharactersEvents(rth);
                    	  }
                    	  else {
                    		  throw new TransformerException("FOTY0013 : Cannot do an XPath atomization of a map "
                                                                                                       + "(ref, https://www.w3.org/TR/xpath-31/#id-atomization).", srcLocator);
                    	  }
                      }
                      else {                    	  
                    	  strValue = XslTransformEvaluationHelper.getStrVal(evalResult);
                    	  
                    	  if (separatorStrValue != null) {
                           	 strValue = strValue.replace(" ", separatorStrValue);
                          }
                      }
                      
                      (new XString(strValue)).dispatchCharactersEvents(rth);
                  }
                  else if (expr instanceof Variable) {          	  
                      XObject evalResult = ((Variable)expr).execute(xctxt);
                      
                      String strValue = null;                      
                      if (evalResult instanceof XSQName) {
                    	  XSQName xsQName = (XSQName)evalResult;
                    	  String prfxStr = xsQName.getPrefix();
                    	  String localStr = xsQName.getLocalPart();
                    	  if ((prfxStr != null) && !"".equals(prfxStr)) {
                    		 strValue = prfxStr + ":" + localStr;   
                    	  }
                    	  else {
                    		 strValue = localStr;  
                    	  }
                      }
                      else if (evalResult instanceof XSAnyType) {
                          strValue = ((XSAnyType)evalResult).stringValue();
                          
                          if (separatorStrValue != null) {
                           	 strValue = strValue.replace(" ", separatorStrValue);
                          }
                      }
                      else if (evalResult instanceof XPathArray) {
                    	 XPathArray xpathArr = (XPathArray)evalResult;
                    	 List<XObject> nativeArr = xpathArr.getNativeArray();                    	                          
                         
                         ResultSequence rSeq = new ResultSequence();
                         for (int idx = 0; idx < nativeArr.size(); idx++) {                           
                        	rSeq.add(nativeArr.get(idx));
                         }
                         
                         strValue = getEffectiveSequenceStrValue(rSeq, separatorStrValue);
                      }
                      else if (evalResult instanceof XPathMap) {                    	 
                    	  String xpathPatternStr = m_selectExpression.getPatternString();
                    	  if (xpathPatternStr.startsWith(Keywords.FUNC_RANDOM_NUMBER_GENERATOR + "(") 
                    			                                                   && xpathPatternStr.endsWith("?" + Constants.ATTRVAL_DATATYPE_NUMBER)) {
                    		  XPathMap xpathMap = (XPathMap)evalResult;
                    		  Map<XObject,XObject> nativeMap = xpathMap.getNativeMap();
                    		  XObject xObj = nativeMap.get(new XSString(Constants.ATTRVAL_DATATYPE_NUMBER));
                    		  XSDouble xsDouble = (XSDouble)xObj;
                    		  XString xString = new XString(xsDouble.stringValue());
                    		  xString.dispatchCharactersEvents(rth);
                    	  }
                    	  else {
                    		  throw new TransformerException("FOTY0013 : Cannot do an XPath atomization of a map "
                    				                                                                        + "(ref, https://www.w3.org/TR/xpath-31/#id-atomization).", srcLocator);
                    	  }
                      }
                      else if (evalResult instanceof XNumber) {
                    	 XNumber xNumber = (XNumber)evalResult;
                    	 if (xNumber.isXsInteger()) {
                    		XSInteger xsInteger = xNumber.getXsInteger();
                    		strValue = xsInteger.stringValue(); 
                    	 }
                    	 else if (xNumber.isXsDecimal()) {
                    		XSDecimal xsDecimal = xNumber.getXsDecimal();
                     		strValue = xsDecimal.stringValue(); 
                    	 }
                    	 else if (xNumber.isXsDouble()) {
                    		XSDouble xsDouble = xNumber.getXsDouble();
                      		strValue = xsDouble.stringValue(); 
                    	 }
                    	 else {
                    		strValue = XslTransformEvaluationHelper.getStrVal(evalResult);
                    	 }
                      }
                      else if (evalResult instanceof ResultSequence) {
                    	 strValue = getEffectiveSequenceStrValue((ResultSequence)evalResult, separatorStrValue); 
                      }                      
                      else if (evalResult instanceof XMLNodeCursorImpl) {                    	  
                    	  XMLNodeCursorImpl xmlNodeCursorImpl = (XMLNodeCursorImpl)evalResult;
                    	  DTMCursorIterator iter = xmlNodeCursorImpl.iterRaw();                    	  
                    	  StringBuffer strBuff = new StringBuffer();
                    	  int nextNode;
                    	  while ((nextNode = iter.nextNode()) != DTM.NULL) {
                    		  XMLNodeCursorImpl nodeImpl = new XMLNodeCursorImpl(nextNode, xctxt);
                    		  String nodeStrValue = nodeImpl.str();
                    		  strBuff.append(nodeStrValue + " ");
                    	  }

                    	  strValue = strBuff.toString();
                    	  if (strValue.length() > 1) {
                    		 strValue = strValue.substring(0, strValue.length() - 1); 
                    	  }
                    	  
                    	  if (separatorStrValue != null) {
                           	 strValue = strValue.replace(" ", separatorStrValue);
                          }
                      }
                      else {
                    	 strValue = XslTransformEvaluationHelper.getStrVal(evalResult);
                    	 
                    	 if (separatorStrValue != null) {
                          	strValue = strValue.replace(" ", separatorStrValue);
                         }
                      }
                      
                      (new XString(strValue)).dispatchCharactersEvents(rth);
                  }
                  else if (expr instanceof Operation) {
                	 XObject evalResult = expr.execute(xctxt);
                	 if (evalResult instanceof XString) {
                		XString xString = (XString)evalResult;
                		String str1 = xString.str();
                		if (str1.contains("{" + Constants.XSL_ERROR_NAMESACE + "}")) {
                			String prefix = XslTransformEvaluationHelper.getPrefixFromNsUri(Constants.XSL_ERROR_NAMESACE, 
                					                                                                            (List<XMLNSDecl>)(this.getPrefixTable()));
                			str1 = str1.replace("{" + Constants.XSL_ERROR_NAMESACE + "}", prefix + ":");
                			evalResult = new XString(str1);
                		}
                	 }
                	 
                	 String strValue = null;
                	 
                	 if (expr instanceof Div) {
                		 if (evalResult == null) {
                			 strValue = "NaN";
                		 }
                		 else {
                			 strValue = XslTransformEvaluationHelper.getStrVal(evalResult);
                		 }
                	 }
                	 else if (evalResult instanceof XSDayTimeDuration) {
                		 strValue = DateTimeUtil.getFormattedStrXsDaytimeDuration((XSDayTimeDuration)evalResult);
                	 }
                	 else if (evalResult instanceof XSDateTime) {                		 
                		 XSDateTime xsDateTime = (XSDateTime)evalResult;                		 
                		 strValue = xsDateTime.stringValue();
                	 } 
                	 else if (evalResult instanceof ResultSequence) {                         
                         strValue = getEffectiveSequenceStrValue((ResultSequence)evalResult, separatorStrValue);
                     }                     
                     else {
                         strValue = XslTransformEvaluationHelper.getStrVal(evalResult);
                         
                         if (separatorStrValue != null) {
                          	strValue = strValue.replace(" ", separatorStrValue);
                         }
                     }
                     
                     (new XString(strValue)).dispatchCharactersEvents(rth);
                  }
                  else if (expr instanceof XPathDynamicFunctionCall) {
                     XPathDynamicFunctionCall dfc = (XPathDynamicFunctionCall)expr;
                     
                     XObject evalResult = dfc.execute(xctxt);
                     
                     String strValue = XslTransformEvaluationHelper.getStrVal(evalResult);
                     
                     if (separatorStrValue != null) {
                      	strValue = strValue.replace(" ", separatorStrValue);
                     }
                     
                     (new XString(strValue)).dispatchCharactersEvents(rth);
                  }
                  else if (expr instanceof LocPathIterator) {
                     LocPathIterator locPathIterator = (LocPathIterator)expr;
                     
                     Function func = locPathIterator.getFuncExpr();
                     XPathDynamicFunctionCall dfc = locPathIterator.getDynamicFuncCallExpr();
                     
                     DTMCursorIterator dtmIter = null;
                     boolean isLocPathIterOk = true;
                     try {
                        dtmIter = locPathIterator.asIterator(xctxt, current);
                     }
                     catch (Exception ex) {
                    	isLocPathIterOk = false;
                     }
                     
                     if ((dtmIter != null) && isLocPathIterOk) {                        
                        StringBuffer strBuff = new StringBuffer();
                        int nextNode;
                        while ((nextNode = dtmIter.nextNode()) != DTM.NULL)
                        {
                           XMLNodeCursorImpl xdmNodeObj = new XMLNodeCursorImpl(nextNode, xctxt);
                           String resultStr = "";
                           if (func != null) {
                        	  // Evaluate an XPath expression like /a/b/funcCall(..).
                        	  // Find one result item for a sequence of items.
                              XObject evalResult = evaluateXPathSuffixFunction(xctxt, srcLocator, func, xdmNodeObj);
                              resultStr = XslTransformEvaluationHelper.getStrVal(evalResult);                               
                           }
                           else if (dfc != null) {
                        	   // Evaluate an XPath expression like /a/b/$funcCall(..).
                        	   // Find one result item for a sequence of items.
                               XObject evalResult = evaluateXPathSuffixDfc(xctxt, dfc, xdmNodeObj);
                               resultStr = XslTransformEvaluationHelper.getStrVal(evalResult);                               
                           }
                           else {
                              resultStr = xdmNodeObj.str();
                           }
                           
                           strBuff.append(resultStr + " ");
                        }
                        
                        String nodeSetStrValue = strBuff.toString();                                                
                        if (nodeSetStrValue.length() > 1) {
                        	nodeSetStrValue = nodeSetStrValue.substring(0, nodeSetStrValue.length() - 1);
                        	if (separatorStrValue != null) {
                        	   nodeSetStrValue = nodeSetStrValue.replace(" ", separatorStrValue);
                        	}
                        	
                        	(new XString(nodeSetStrValue)).dispatchCharactersEvents(rth);
                        }                        
                     }
                     else {
                        String xpathPatternStr = m_selectExpression.getPatternString();
                        
                        if (xpathPatternStr.startsWith("$") && xpathPatternStr.contains("[") && 
                                                                                    xpathPatternStr.endsWith("]") && 
                                                                                    !(xpathPatternStr.contains("(") || xpathPatternStr.contains(")"))) {
                           /**
                            * Here, we handle the case where the XPath expression is of type $varName[expr],
                            * for example $varName[1], $varName[$idx], $varName[funcCall(arg)] etc, and
                            * $varName resolves to a 'ResultSequence' object.
                            */
                            
                           String varRefXPathExprStr = "$" + xpathPatternStr.substring(1, xpathPatternStr.indexOf('['));
                           String xpathIndexExprStr = xpathPatternStr.substring(xpathPatternStr.indexOf('[') + 1, 
                                                                                                   xpathPatternStr.indexOf(']'));
                           
                           ElemTemplateElement elemTemplateElement = (ElemTemplateElement)xctxt.getNamespaceContext();
                           List<XMLNSDecl> prefixTable = null;
                           if (elemTemplateElement != null) {
                              prefixTable = (List<XMLNSDecl>)elemTemplateElement.getPrefixTable();
                           }
                           
                           // Evaluate the, variable reference XPath expression
                           if (prefixTable != null) {
                              varRefXPathExprStr = XslTransformEvaluationHelper.replaceNsUrisWithPrefixesOnXPathStr(
                                                                                                             varRefXPathExprStr, 
                                                                                                             prefixTable);
                           }
                           
                           XPath xpathObj = new XPath(varRefXPathExprStr, srcLocator, 
                                                                                 xctxt.getNamespaceContext(), XPath.SELECT, null);
                           if (m_vars != null) {
                              xpathObj.fixupVariables(m_vars, m_globals_size);                            
                           }
                           
                           XObject varEvalResult = xpathObj.execute(xctxt, xctxt.getCurrentNode(), xctxt.getNamespaceContext());
                           
                           // Evaluate the, xdm sequence index XPath expression
                           if (prefixTable != null) {
                              xpathIndexExprStr = XslTransformEvaluationHelper.replaceNsUrisWithPrefixesOnXPathStr(
                                                                                                              xpathIndexExprStr, 
                                                                                                              prefixTable);
                           }
                            
                           xpathObj = new XPath(xpathIndexExprStr, srcLocator, xctxt.getNamespaceContext(), XPath.SELECT, null);
                           
                           if (m_vars != null) {
                              xpathObj.fixupVariables(m_vars, m_globals_size);                            
                           }
                           
                           XObject seqIndexEvalResult = xpathObj.execute(xctxt, xctxt.getCurrentNode(), 
                                                                                                  xctxt.getNamespaceContext());
                           if (varEvalResult instanceof ResultSequence) {
                              ResultSequence resultSeq = (ResultSequence)varEvalResult; 
                              
                              if (seqIndexEvalResult instanceof XNumber) {
                                 double indexValDbl = ((XNumber)seqIndexEvalResult).num();
                                 int indexValInt = (int)indexValDbl;
                                 if ((indexValDbl == indexValInt) && (indexValInt > 0)) {
                                    XObject evalResult = resultSeq.item(indexValInt - 1);
                                    String strValue = XslTransformEvaluationHelper.getStrVal(evalResult);
                                    
                                    if ((evalResult instanceof ResultSequence) && (separatorStrValue != null)) {
                                       strValue = strValue.replace(" ", separatorStrValue);
                                    }
                                    
                                    (new XString(strValue)).dispatchCharactersEvents(rth);
                                 }
                                 else {
                                    throw new javax.xml.transform.TransformerException("XPTY0004 : An xdm sequence index reference "
                                    		                                                                                   + "value, is not a positive integer.", srcLocator); 
                                 }
                              }
                              else if (seqIndexEvalResult instanceof XSNumericType) {
                                 String indexStrVal = ((XSNumericType)seqIndexEvalResult).stringValue();
                                 double indexValDbl = (Double.valueOf(indexStrVal)).doubleValue();
                                 int indexValInt = (int)indexValDbl;
                                 if ((indexValDbl == indexValInt) && (indexValInt > 0)) {
                                	 XObject evalResult = resultSeq.item(indexValInt - 1);
                                	 String strValue = XslTransformEvaluationHelper.getStrVal(evalResult);

                                	 if ((evalResult instanceof ResultSequence) && (separatorStrValue != null)) {
                                		 strValue = strValue.replace(" ", separatorStrValue);
                                	 }

                                	 (new XString(strValue)).dispatchCharactersEvents(rth);                                    
                                 }
                                 else {
                                	throw new javax.xml.transform.TransformerException("XPTY0004 : An xdm sequence index reference "
                                                                                                                              + "value, is not a positive integer.", srcLocator); 
                                 }
                              }
                              else {
                            	 throw new javax.xml.transform.TransformerException("XPTY0004 : An xdm sequence index reference value, "
                                                                                                                             + "is not numeric.", srcLocator);  
                              }
                           }                           
                        }
                        else if (xpathPatternStr.startsWith("$")) {
                           /**
                            * Evaluating an XPath expression like $varRef[a](b,..)[c]. A typical 
                            * example is, an XPath expression $varRef[a] is a 'function item' 
                            * reference that is provided arguments (b,..). The function call 
                            * result of, expression $varRef[a](b,..) is filtered with index 
                            * accessor [c].
                            */
                        	
                           int idx = xpathPatternStr.indexOf('[');
                           if (idx > -1) {
                        	   String prefix1 = xpathPatternStr.substring(0, idx);
                        	   String suffix1 = null;
                        	   if (idx > 0) {
                        	      suffix1 = xpathPatternStr.substring(idx);
                        	   }

                        	   ElemTemplateElement elemTemplateElement = (ElemTemplateElement)xctxt.getNamespaceContext();
                        	   List<XMLNSDecl> prefixTable = null;
                        	   if (elemTemplateElement != null) {
                        		   prefixTable = (List<XMLNSDecl>)elemTemplateElement.getPrefixTable();
                        	   }

                        	   if (prefixTable != null) {
                        		   prefix1 = XslTransformEvaluationHelper.replaceNsUrisWithPrefixesOnXPathStr(prefix1, prefixTable);
                        	   }

                        	   XPath xpathObj = new XPath(prefix1, srcLocator, xctxt.getNamespaceContext(), XPath.SELECT, null);
                        	   if (m_vars != null) {
                        		  xpathObj.fixupVariables(m_vars, m_globals_size);                            
                        	   }

                        	   XObject prefixEvalResult = xpathObj.execute(xctxt, xctxt.getCurrentNode(), xctxt.getNamespaceContext());
                        	   if (prefixEvalResult instanceof XPathNamedFunctionReference) {
                        		   XPathNamedFunctionReference xpathNamedFunctionReference = (XPathNamedFunctionReference)prefixEvalResult;                        		   
                        		   ResultSequence rSeq = new ResultSequence();
                        		   rSeq.add(xpathNamedFunctionReference);                        		   
                        		   prefixEvalResult = rSeq; 
                        	   }
                        	   
                        	   try {
                        		   if (prefixEvalResult instanceof ResultSequence) {
                        			   ResultSequence rSeq = (ResultSequence)prefixEvalResult;
                        			   int i = suffix1.indexOf('(');
                        			   int j = suffix1.indexOf(')');
                        			   String a1 = null;
                        			   String[] b1 = null;
                        			   String c1 = null;
                        			   if ((i > -1) && (j > -1) && (i < j)) {
                        				   String str1 = suffix1.substring(0, i);
                        				   if (str1.startsWith("[") && str1.endsWith("]")) {
                        					   int strLen1 = str1.length();
                        					   a1 = str1.substring(1, strLen1 - 1);
                        				   }
                        				   
                        				   String str2 = suffix1.substring(i + 1, j);
                        				   b1 = str2.split(",");                        				   
                        				   String str3 = suffix1.substring(j + 1);
                        				   if (str3.startsWith("[") && str3.endsWith("]")) {
                        					   int strLen3 = str3.length();
                        					   c1 = str3.substring(1, strLen3 - 1);
                        				   }
                        			   }
                        			   
                        			   XPath xpath = new XPath(a1, srcLocator, xctxt.getNamespaceContext(), XPath.SELECT, null);
        							   if (m_vars != null) {
        								   xpath.fixupVariables(m_vars, m_globals_size);                            
        							   }

        							   XObject aXObj = xpath.execute(xctxt, xctxt.getCurrentNode(), xctxt.getNamespaceContext());
        							   Integer aInt = Integer.valueOf(XslTransformEvaluationHelper.getStrVal(aXObj));
                        			   XObject xObj = rSeq.item(aInt - 1);
                        			   
                        			   if ((xObj != null) && (xObj instanceof XPathNamedFunctionReference)) {
                        				   XPathNamedFunctionReference xpathNamedFunctionReference = (XPathNamedFunctionReference)xObj;
                        				   ElemFunction elemFunction = xpathNamedFunctionReference.getXslStylesheetFunction();
                        				   if (elemFunction != null) {
                        					   int argCount = b1.length; 
                        					   if (elemFunction.getArity() == argCount) {
                        						   ResultSequence argResultSeq = new ResultSequence();
                        						   for (int idx2 = 0; idx2 < argCount; idx2++) {
                        							   XPath argXpathObj = new XPath(b1[idx2], srcLocator, xctxt.getNamespaceContext(), XPath.SELECT, null);
                        							   if (m_vars != null) {
                        								   argXpathObj.fixupVariables(m_vars, m_globals_size);                            
                        							   }

                        							   XObject argXObj = argXpathObj.execute(xctxt, xctxt.getCurrentNode(), xctxt.getNamespaceContext());
                        							   argResultSeq.add(argXObj);
                        						   }

                        						   XObject xslFuncEvalResult = elemFunction.evaluateXslFunction(transformer, argResultSeq);
                        						   if (xslFuncEvalResult instanceof ResultSequence) {
                        							   ResultSequence rSeq2 = (ResultSequence)xslFuncEvalResult;
                        							   xpath = new XPath(c1, srcLocator, xctxt.getNamespaceContext(), XPath.SELECT, null);
                        							   if (m_vars != null) {
                        								   xpath.fixupVariables(m_vars, m_globals_size);                            
                        							   }

                        							   XObject cXObj = xpath.execute(xctxt, xctxt.getCurrentNode(), xctxt.getNamespaceContext());
                        							   Integer cInt = Integer.valueOf(XslTransformEvaluationHelper.getStrVal(cXObj));
                        							   if (cInt > 0) {
                        								   xslFuncEvalResult = rSeq2.item(cInt - 1); 
                        							   }
                        						   }

                        						   String strValue = XslTransformEvaluationHelper.getStrVal(xslFuncEvalResult);

                        						   (new XString(strValue)).dispatchCharactersEvents(rth);
                        					   }
                        				   }
                        			   }
                        		   }
                        	   }
                        	   catch (Exception ex) {
                        		   // no op
                        	   }
                           }
                        }
                     }
                  }
                  else if (expr instanceof XPathLetExpr) {
                     XPathLetExpr letExpr = (XPathLetExpr)expr;
                      
                     XObject evalResult = letExpr.execute(xctxt);                     
                     String strValue = XslTransformEvaluationHelper.getStrVal(evalResult);
                     
                     if (separatorStrValue != null) {
                      	strValue = strValue.replace(" ", separatorStrValue);
                     }
                     
                     (new XString(strValue)).dispatchCharactersEvents(rth);
                  }
                  else if (expr instanceof XPathIfExpr) {
                      XPathIfExpr ifExpr = (XPathIfExpr)expr;
                       
                      XObject evalResult = ifExpr.execute(xctxt);                     
                      String strValue = XslTransformEvaluationHelper.getStrVal(evalResult);
                      
                      if (separatorStrValue != null) {
                       	 strValue = strValue.replace(" ", separatorStrValue);
                      }
                      
                      (new XString(strValue)).dispatchCharactersEvents(rth);
                  }
                  else if (expr instanceof XString) {
                	  XString xStr = (XString)expr;
                	  String strValue = xStr.str();
                	  String xpathPatternStr = m_selectExpression.getPatternString();
                	  if ("''''".equals(xpathPatternStr) && "".equals(strValue)) {
                		  // An XSL stylesheet has an effective character value ' (which in 
                		  // escaped form is '' and lexically specified with XPath expression 
                		  // string as '''') that needs to be emitted to stylesheet's result.
                		  XString xStr2 = new XString("'");
                		  xStr2.executeCharsToContentHandler(xctxt, rth);
                	  }
                	  else {
                		  xStr.executeCharsToContentHandler(xctxt, rth); 
                	  }
                  }
                  else {
                	  XObject evalResult = expr.execute(xctxt);
                	  
                	  if (evalResult instanceof ResultSequence) {
                		  if (separatorStrValue == null) {
                			  separatorStrValue = " "; 
                		  }

                		  ResultSequence rSeq = (ResultSequence)evalResult;
                		  int rSeqLngth = rSeq.size();
                		  StringBuffer strBuff = new StringBuffer();
                		  for (int idx = 0; idx < rSeqLngth; idx++) {
                			  XObject xObj = rSeq.item(idx);
                			  String str1 = null;
                			  if (xObj instanceof ResultSequence) {
                				  ResultSequence seq1 = (ResultSequence)xObj;
                				  if (seq1.size() > 0) {
                					  str1 = seq1.str(); 
                				  }
                			  }
                			  else if (xObj instanceof XMLNodeCursorImpl) {
                				  XMLNodeCursorImpl xmlNodeCursorImpl = (XMLNodeCursorImpl)xObj;
                				  if (xmlNodeCursorImpl.getLength() > 0) {
                					  str1 = xmlNodeCursorImpl.str();  
                				  }
                			  }
                			  else if (xObj instanceof XSDayTimeDuration) {
                				  str1 = DateTimeUtil.getFormattedStrXsDaytimeDuration((XSDayTimeDuration)xObj); 
                			  }
                			  else {
                				  str1 = XslTransformEvaluationHelper.getStrVal(xObj);
                			  }

                			  if ((str1 != null) && !((idx == 0) && "".equals(str1))) {                			  
                				  if (idx < (rSeqLngth - 1)) {
                					  strBuff = strBuff.append(str1 + separatorStrValue); 
                				  }
                				  else {
                					  strBuff = strBuff.append(str1);
                				  }
                			  }
                		  }

                		  XString xStr = new XString(strBuff.toString());               		                  		  

                		  xStr.executeCharsToContentHandler(xctxt, rth);
                	  }
                	  else {
                		  String strValue = XslTransformEvaluationHelper.getStrVal(evalResult);
                		  XString xStr = new XString(strValue);

                		  xStr.executeCharsToContentHandler(xctxt, rth);
                	  }
                  }
              }
          }
        }
        finally
        {
          xctxt.popNamespaceContext();
          xctxt.popCurrentNodeAndExpression();
        }
        
        if (m_disableOutputEscaping)
            rth.processingInstruction(
              javax.xml.transform.Result.PI_DISABLE_OUTPUT_ESCAPING, "");
    }
    catch (SAXException se)
    {
        throw new TransformerException(se);
    }
    catch (Exception ex) {
    	TransformerException te = new TransformerException(ex);
    	te.setLocator(this);
    	throw te;
    }
    finally
    {       	
      if (transformer.getDebug())
	    transformer.getTraceManager().emitTraceEndEvent(this); 
    }
  }

  /**
   * Add a child to the child list.
   *
   * @param newChild Child to add to children list
   *
   * @return Child just added to children list
   *
   * @throws DOMException
   */
  public ElemTemplateElement appendChild(ElemTemplateElement newChild)
  {
	  return super.appendChild(newChild);
  }
  
  /**
   * Call the children visitors.
   * @param visitor The visitor whose appropriate method will be called.
   */
  protected void callChildVisitors(XSLTVisitor visitor, boolean callAttrs)
  {
  	  if (callAttrs)
  		 m_selectExpression.getExpression().callVisitors(m_selectExpression, visitor);
      super.callChildVisitors(visitor, callAttrs);
  }
  
  /**
   * We might have earlier added a suffix STRING_VAL_SERIALIZATION_SUFFIX to 
   * certain string values for the purpose of correct XSLT transformation
   * serialization to the result. If those suffixes are still present on 
   * those strings, they need to be trimmed to restore original string 
   * values.
   */
  private String preProcessStrBeforeXslSerialization(String str) {
	 String resultStr = str;
	 
	 if (resultStr.contains(ElemSequence.STRING_VAL_SER_SUFFIX)) {
	     resultStr = resultStr.replace(ElemSequence.STRING_VAL_SER_SUFFIX, "");
	 }
	 
	 return resultStr;
  }
  
  /**
   * Get an effective string value of sequence to be emitted,
   * considering xsl:value-of element's separator attribute if 
   * available.
   */
  private String getEffectiveSequenceStrValue(ResultSequence seq, String separatorStrValue) {	
		  
    String result = null;	  
	  
	StringBuffer strBuff = new StringBuffer();
	int size1 = seq.size();
	for (int idx = 0; idx < size1; idx++) {
	   XObject xObj = seq.item(idx);
	   String str1 = XslTransformEvaluationHelper.getStrVal(xObj);
	   if (idx < (size1 - 1)) {
		   if (separatorStrValue != null) {
			  strBuff.append(str1 + separatorStrValue);
		   }
		   else {
			  strBuff.append(str1 + " ");
		   }
	   }
	   else {
		   strBuff.append(str1);
	   }
	}
	
	result = strBuff.toString(); 
	
	return result;
	
  }
  
  /**
   * This method evaluates xsl:value-of instruction's contained sequence constructor,
   * and emits the result of evaluation to XSL transform's output.
   */
  private void evaluateXslValueOfSeqConstructorAndEmitResult(TransformerImpl transformer, XPathContext xctxt, 
		                                                     SerializationHandler rth, String separatorStrValue) throws TransformerException, SAXException {
	  
	  int rtfNodeHandle = transformer.transformToRTF(this);
	  DTMManager dtmMgr = xctxt.getDTMManager();        	  
	  DTM dtm = dtmMgr.getDTM(rtfNodeHandle);        	  
	  int nodeType = dtm.getNodeType(rtfNodeHandle);

	  StringBuffer nodeStrValBuff = new StringBuffer();

	  if (nodeType == DTM.DOCUMENT_NODE) {
		  Node docNode = dtm.getNode(rtfNodeHandle);
		  NodeList nodeList = docNode.getChildNodes();
		  if ((nodeList != null) && (nodeList.getLength() > 0)) {
			  for (int idx = 0; idx < nodeList.getLength(); idx++) {
				  Node node = nodeList.item(idx);
				  String nodeStrVal = node.getTextContent();
				  if (idx < (nodeList.getLength() - 1)) {
					  if (separatorStrValue != null) {
						  nodeStrValBuff.append(nodeStrVal + separatorStrValue);
					  }
					  else {
						  nodeStrValBuff.append(nodeStrVal); 
					  }
				  }
				  else {
					  nodeStrValBuff.append(nodeStrVal);
				  }
			  }
		  }

		  String nodeStrVal = (nodeStrValBuff.toString()).trim();
		  boolean status1 = false;		  
		  if (nodeStrVal.contains(ElemSequence.SER_INTEGER_SUFFIX_ID)) {
			  nodeStrVal = nodeStrVal.replace(ElemSequence.SER_INTEGER_SUFFIX_ID, "");
			  status1 = true;
		  }
		  else if (nodeStrVal.contains(ElemSequence.SER_DOUBLE_SUFFIX_ID)) {
			  nodeStrVal = nodeStrVal.replace(ElemSequence.SER_DOUBLE_SUFFIX_ID, "");
			  status1 = true;
		  }
		  else if (nodeStrVal.contains(ElemSequence.SER_DECIMAL_SUFFIX_ID)) {
			  nodeStrVal = nodeStrVal.replace(ElemSequence.SER_DECIMAL_SUFFIX_ID, "");
			  status1 = true;
		  }
		  else if (nodeStrVal.contains(ElemSequence.SER_FLOAT_SUFFIX_ID)) {
			  nodeStrVal = nodeStrVal.replace(ElemSequence.SER_FLOAT_SUFFIX_ID, "");
			  status1 = true;
		  }
		  else if (nodeStrVal.contains(ElemSequence.SER_SUFFIX_ID)) {
			  nodeStrVal = nodeStrVal.replace(ElemSequence.SER_SUFFIX_ID, "");
			  status1 = true;
		  }

		  if (status1 && (separatorStrValue != null)) {        				
			  nodeStrVal = nodeStrVal.replace(" ", separatorStrValue);
			  nodeStrVal = nodeStrVal.substring(0, (nodeStrVal.length() - 1));
			  String rTrimmedSeparator = StringUtil.strRtrim(separatorStrValue);
			  if (!separatorStrValue.equals(rTrimmedSeparator)) {
				  int lIdx = nodeStrVal.lastIndexOf(rTrimmedSeparator);
				  if (lIdx > 0) {
					  nodeStrVal = nodeStrVal.substring(0, lIdx);
				  } 
			  }
		  }
		  else {
			  nodeStrVal = nodeStrVal.trim();
		  }

		  (new XString(nodeStrVal)).dispatchCharactersEvents(rth);
	  }
	  else {
		  // xsl:value-of's 'separator' attribute is ignored 
		  // in this case. 
		  Node node = dtm.getNode(rtfNodeHandle);
		  String nodeStrVal = node.getTextContent();
		  (new XString(nodeStrVal)).dispatchCharactersEvents(rth);
	  }
   }
   
   /**
    * Method definition to serialize xs:dayTimeDuration value, by serializing
    * xs:dayTimeDuration value's seconds component upto a specified number
    * of decimal places.  
    * 
    * @param xsDayTimeDurationValue					The supplied xs:dayTimeDuration value 
    * @param precision								Precision value for mathematical rounding
    * @param xctxt									XPath context object
    * @param rth									An XSL SerializationHandler run-time object
    * @throws WrongNumberArgsException
    * @throws TransformerException
    * @throws SAXException
    */
   private void serializeXsDaytimeDurationValue(XSDayTimeDuration xsDayTimeDurationValue, int precision, 
		   										XPathContext xctxt, SerializationHandler rth)
		   																				throws WrongNumberArgsException, TransformerException, SAXException {
	   double dbl = xsDayTimeDurationValue.seconds();
	   
	   if (dbl != 0) {
		   FuncRound funcRound = new FuncRound();
		   funcRound.setArg0(new XSDouble(dbl));
		   funcRound.setArg(new XSInteger(String.valueOf(precision)), 1);
		   String roundedDblResult = (funcRound.execute(xctxt)).str();
		   String xsDayTimeDurationStrValue = xsDayTimeDurationValue.stringValue();
		   String secsStrValue = (Double.valueOf(dbl)).toString();
		   int idx = xsDayTimeDurationStrValue.indexOf(secsStrValue);
		   String prefixStr = xsDayTimeDurationStrValue.substring(0, idx);
		   xsDayTimeDurationStrValue = prefixStr + roundedDblResult + "S";
		   xsDayTimeDurationStrValue = preProcessStrBeforeXslSerialization(xsDayTimeDurationStrValue);
		   
		   (new XString(xsDayTimeDurationStrValue)).dispatchCharactersEvents(rth);
	   }
	   else {
		   (new XString(xsDayTimeDurationValue.stringValue())).dispatchCharactersEvents(rth);
	   }
   }

}
