package client.net.sf.saxon.ce.expr.instruct;
import client.net.sf.saxon.ce.event.SequenceReceiver;
import client.net.sf.saxon.ce.expr.*;
import client.net.sf.saxon.ce.om.Item;
import client.net.sf.saxon.ce.om.StandardNames;
import client.net.sf.saxon.ce.pattern.NodeKindTest;
import client.net.sf.saxon.ce.trans.XPathException;
import client.net.sf.saxon.ce.tree.util.Orphan;
import client.net.sf.saxon.ce.type.*;
import client.net.sf.saxon.ce.value.StringValue;
/**
* An xsl:value-of element in the stylesheet. <br>
* The xsl:value-of element takes attributes:<ul>
* <li>a mandatory attribute select="expression".
* This must be a valid String expression</li>
* <li>an optional disable-output-escaping attribute, value "yes" or "no"</li>
* <li>an optional separator attribute. This is handled at compile-time: if the separator attribute
* is present, the select expression passed in here will be a call to the string-join() function.</li>
* </ul>
*/
public final class ValueOf extends SimpleNodeConstructor {
private boolean isNumberingInstruction = false; // set to true if generated by xsl:number
private boolean noNodeIfEmpty;
/**
* Create a new ValueOf expression
* @param select the select expression
* @param noNodeIfEmpty true if the instruction is to return () if the select expression is (),
*/
public ValueOf(Expression select, boolean noNodeIfEmpty) {
this.select = select;
this.noNodeIfEmpty = noNodeIfEmpty;
adoptChildExpression(select);
}
/**
* Indicate that this is really an xsl:nunber instruction
*/
public void setIsNumberingInstruction() {
isNumberingInstruction = true;
}
/**
* Determine whether this is really an xsl:number instruction
* @return true if this derives from xsl:number
*/
public boolean isNumberingInstruction() {
return isNumberingInstruction;
}
/**
* Get the name of this instruction for diagnostic and tracing purposes
* @return the namecode of the instruction name
*/
public int getInstructionNameCode() {
if (isNumberingInstruction) {
return StandardNames.XSL_NUMBER;
} else if (select instanceof StringLiteral) {
return StandardNames.XSL_TEXT;
} else {
return StandardNames.XSL_VALUE_OF;
}
}
public ItemType getItemType(TypeHierarchy th) {
return NodeKindTest.TEXT;
}
public int computeCardinality() {
if (noNodeIfEmpty) {
return StaticProperty.ALLOWS_ZERO_OR_ONE;
} else {
return StaticProperty.EXACTLY_ONE;
}
}
public void localTypeCheck(ExpressionVisitor visitor, ItemType contextItemType) {
//
}
/**
* Convert this value-of instruction to an expression that delivers the string-value of the resulting
* text node as an untyped atomic value.
* @return the converted expression
*/
public Expression convertToCastAsString() {
return new CastExpression(select, BuiltInAtomicType.UNTYPED_ATOMIC, true);
}
/**
* Process this instruction
* @param context the dynamic context of the transformation
* @return a TailCall to be executed by the caller, always null for this instruction
*/
public TailCall processLeavingTail(XPathContext context) throws XPathException {
if (noNodeIfEmpty) {
StringValue value = (StringValue)select.evaluateItem(context);
if (value != null) {
processValue(value.getStringValueCS(), context);
}
return null;
} else {
return super.processLeavingTail(context);
}
}
/**
* Process the value of the node, to create the new node.
* @param value the string value of the new node
* @param context the dynamic evaluation context
* @throws client.net.sf.saxon.ce.trans.XPathException
*
*/
public void processValue(CharSequence value, XPathContext context) throws XPathException {
SequenceReceiver out = context.getReceiver();
out.characters(value);
}
/**
* Evaluate this expression, returning the resulting text node to the caller
* @param context the dynamic evaluation context
* @return the parentless text node that results from evaluating this instruction, or null to
* represent an empty sequence
* @throws XPathException
*/
public Item evaluateItem(XPathContext context) throws XPathException {
try {
CharSequence val;
Item item = select.evaluateItem(context);
if (item == null) {
if (noNodeIfEmpty) {
return null;
} else {
val = "";
}
} else {
val = item.getStringValueCS();
}
Orphan o = new Orphan(context.getController().getConfiguration());
o.setNodeKind(Type.TEXT);
o.setStringValue(val);
return o;
} catch (XPathException err) {
err.maybeSetLocation(getSourceLocator());
throw err;
}
}
}
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// This Source Code Form is “Incompatible With Secondary Licenses”, as defined by the Mozilla Public License, v. 2.0.