package client.net.sf.saxon.ce.expr.instruct; import client.net.sf.saxon.ce.Controller; import client.net.sf.saxon.ce.event.Builder; import client.net.sf.saxon.ce.event.PipelineConfiguration; import client.net.sf.saxon.ce.event.Receiver; import client.net.sf.saxon.ce.event.SequenceReceiver; import client.net.sf.saxon.ce.expr.*; import client.net.sf.saxon.ce.functions.StringJoin; import client.net.sf.saxon.ce.functions.SystemFunction; import client.net.sf.saxon.ce.om.DocumentInfo; import client.net.sf.saxon.ce.om.Item; import client.net.sf.saxon.ce.om.SequenceIterator; 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.FastStringBuffer; import client.net.sf.saxon.ce.type.BuiltInAtomicType; import client.net.sf.saxon.ce.type.ItemType; import client.net.sf.saxon.ce.type.TypeHierarchy; import client.net.sf.saxon.ce.value.StringValue; import client.net.sf.saxon.ce.value.TextFragmentValue; import client.net.sf.saxon.ce.value.UntypedAtomicValue; /** * An instruction to create a document node. This corresponds to the xsl:document-node * instruction in XSLT. It is also used to support the document node constructor * expression in XQuery, and is generated implicitly within an xsl:variable * that constructs a temporary tree. * * <p>Conceptually it represents an XSLT instruction xsl:document-node, * with no attributes, whose content is a complex content constructor for the * children of the document node.</p> */ public class DocumentInstr extends ParentNodeConstructor { //private static final int[] treeSizeParameters = {50, 10, 5, 200}; // estimated size of a temporary tree: {nodes, attributes, namespaces, characters} private boolean textOnly; private String constantText; /** * Create a document constructor instruction * @param textOnly true if the content contains text nodes only * @param constantText if the content contains text nodes only and the text is known at compile time, * supplies the textual content * @param baseURI the base URI of the instruction */ public DocumentInstr(boolean textOnly, String constantText, String baseURI) { this.textOnly = textOnly; this.constantText = constantText; setBaseURI(baseURI); } /** * An implementation of Expression must provide at least one of the methods evaluateItem(), iterate(), or process(). * This method indicates which of these methods is prefered. For instructions this is the process() method. */ public int getImplementationMethod() { return Expression.EVALUATE_METHOD; } /** * Determine whether this is a "text only" document: essentially, an XSLT xsl:variable that contains * a single text node or xsl:value-of instruction. * @return true if this is a text-only document */ public boolean isTextOnly() { return textOnly; } /** * Simplify an expression. This performs any static optimization (by rewriting the expression * as a different expression). The default implementation does nothing. * * @return the simplified expression * @throws client.net.sf.saxon.ce.trans.XPathException * if an error is discovered during expression rewriting * @param visitor an expression visitor */ public Expression simplify(ExpressionVisitor visitor) throws XPathException { return super.simplify(visitor); } /** * In the case of a text-only instruction (xsl:variable containing a text node or one or more xsl:value-of * instructions), return an expression that evaluates to the textual content as an instance of xs:untypedAtomic * @param env the static evaluation context * @return an expression that evaluates to the textual content */ public Expression getStringValueExpression(StaticContext env) { if (textOnly) { if (constantText != null) { return new StringLiteral(new UntypedAtomicValue(constantText)); } else if (content instanceof ValueOf) { return ((ValueOf)content).convertToCastAsString(); } else { StringJoin fn = (StringJoin)SystemFunction.makeSystemFunction( "string-join", new Expression[]{content, new StringLiteral(StringValue.EMPTY_STRING)}); CastExpression cast = new CastExpression(fn, BuiltInAtomicType.UNTYPED_ATOMIC, false); ExpressionTool.copyLocationInfo(this, cast); return cast; } } else { throw new AssertionError("getStringValueExpression() called on non-text-only document instruction"); } } /** * Get the item type * @param th The TypeHierarchy * @return the in */ public ItemType getItemType(TypeHierarchy th) { return NodeKindTest.DOCUMENT; } public TailCall processLeavingTail(XPathContext context) throws XPathException { SequenceReceiver out = context.getReceiver(); out.startDocument(); content.process(context); out.endDocument(); return null; } /** * Evaluate as an expression. */ public Item evaluateItem(XPathContext context) throws XPathException { Controller controller = context.getController(); DocumentInfo root; if (textOnly) { CharSequence textValue; if (constantText != null) { textValue = constantText; } else { FastStringBuffer sb = new FastStringBuffer(FastStringBuffer.SMALL); SequenceIterator iter = content.iterate(context); while (true) { Item item = iter.next(); if (item==null) break; sb.append(item.getStringValueCS()); } textValue = sb.condense(); } root = new TextFragmentValue(textValue, getBaseURI()); ((TextFragmentValue)root).setConfiguration(controller.getConfiguration()); } else { try { XPathContext c2 = context.newMinorContext(); Builder builder = controller.makeBuilder(); //receiver.setSystemId(getBaseURI()); builder.setBaseURI(getBaseURI()); PipelineConfiguration pipe = controller.makePipelineConfiguration(); builder.setPipelineConfiguration(pipe); c2.changeOutputDestination(builder, false); Receiver out = c2.getReceiver(); out.open(); out.startDocument(); content.process(c2); out.endDocument(); out.close(); root = (DocumentInfo)builder.getCurrentRoot(); } catch (XPathException e) { e.maybeSetLocation(getSourceLocator()); e.maybeSetContext(context); throw e; } } return root; } /** * Get the name of this instruction for diagnostic and tracing purposes * (the string "document-constructor") */ public int getInstructionNameCode() { return StandardNames.XSL_DOCUMENT; } } // 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.