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.