001: package net.sf.saxon.instruct;
002:
003: import net.sf.saxon.expr.Atomizer;
004: import net.sf.saxon.expr.Expression;
005: import net.sf.saxon.expr.XPathContext;
006: import net.sf.saxon.expr.StaticProperty;
007: import net.sf.saxon.om.Item;
008: import net.sf.saxon.om.SequenceIterator;
009: import net.sf.saxon.om.FastStringBuffer;
010: import net.sf.saxon.trans.XPathException;
011: import net.sf.saxon.type.Type;
012: import net.sf.saxon.value.AtomicValue;
013: import net.sf.saxon.value.StringValue;
014:
015: /**
016: * This class implements the rules for an XQuery simple content constructor, which are used in constructing
017: * the string value of an attribute node, text node, comment node, etc, from the value of the select
018: * expression or the contained sequence constructor. These differ slightly from the XSLT rules implemented
019: * in the superclass - specifically, the sequence is simply atomized, whereas XSLT takes special steps to
020: * concatenate adjacent text nodes before inserting separators.
021: */
022:
023: public class QuerySimpleContentConstructor extends
024: SimpleContentConstructor {
025:
026: boolean noNodeIfEmpty;
027:
028: public QuerySimpleContentConstructor(Expression select,
029: Expression separator, boolean noNodeIfEmpty) {
030: super (select, separator);
031: this .noNodeIfEmpty = noNodeIfEmpty;
032: }
033:
034: /**
035: * Compute the cardinality of the result of the expression.
036: * @return the cardinality, @link {StaticProperty.EXACTLY_ONE}
037: */
038:
039: protected int computeCardinality() {
040: if (noNodeIfEmpty) {
041: return StaticProperty.ALLOWS_ZERO_OR_ONE;
042: } else {
043: return StaticProperty.EXACTLY_ONE;
044: }
045: }
046:
047: /**
048: * Expand the stylesheet elements subordinate to this one, returning the result
049: * as a string. The expansion must not generate any element or attribute nodes.
050: * @param context The dynamic context for the transformation
051: */
052:
053: public CharSequence expandChildren(XPathContext context)
054: throws XPathException {
055: Item item = select.evaluateItem(context);
056: if (item == null) {
057: return (noNodeIfEmpty ? null : "");
058: } else {
059: return item.getStringValueCS();
060: }
061: }
062:
063: /**
064: * Evaluate an expression as a single item. This always returns either a single Item or
065: * null (denoting the empty sequence). No conversion is done. This method should not be
066: * used unless the static type of the expression is a subtype of "item" or "item?": that is,
067: * it should not be called if the expression may return a sequence. There is no guarantee that
068: * this condition will be detected.
069: *
070: * @param context The context in which the expression is to be evaluated
071: * @return the node or atomic value that results from evaluating the
072: * expression; or null to indicate that the result is an empty
073: * sequence
074: * @throws net.sf.saxon.trans.XPathException
075: * if any dynamic error occurs evaluating the
076: * expression
077: */
078:
079: public Item evaluateItem(XPathContext context)
080: throws XPathException {
081:
082: if (isSingleton && isAtomic) {
083: // optimize for this case
084: Item item = select.evaluateItem(context);
085: if (item == null) {
086: if (noNodeIfEmpty) {
087: return null;
088: } else {
089: return StringValue.EMPTY_STRING;
090: }
091: }
092: if (item instanceof StringValue) {
093: return item;
094: } else {
095: return ((AtomicValue) item).convert(Type.STRING,
096: context);
097: }
098: }
099: SequenceIterator iter = select.iterate(context);
100: if (!isAtomic) {
101: iter = Atomizer.AtomizingFunction
102: .getAtomizingIterator(iter);
103: }
104: FastStringBuffer sb = new FastStringBuffer(1024);
105: boolean first = true;
106: String sep = " ";
107: while (true) {
108: Item item = iter.next();
109: if (item == null) {
110: break;
111: }
112: if (!first) {
113: sb.append(sep);
114: }
115: first = false;
116: sb.append(item.getStringValueCS());
117: }
118: if (first && noNodeIfEmpty) {
119: return null;
120: }
121: return StringValue.makeStringValue(sb.condense());
122: }
123:
124: }
125:
126: //
127: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
128: // you may not use this file except in compliance with the License. You may obtain a copy of the
129: // License at http://www.mozilla.org/MPL/
130: //
131: // Software distributed under the License is distributed on an "AS IS" basis,
132: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
133: // See the License for the specific language governing rights and limitations under the License.
134: //
135: // The Original Code is: all this file.
136: //
137: // The Initial Developer of the Original Code is Michael H. Kay.
138: //
139: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
140: //
141: // Contributor(s): none.
142: //
|