001: package net.sf.saxon.style;
002:
003: import net.sf.saxon.expr.*;
004: import net.sf.saxon.functions.Concat;
005: import net.sf.saxon.functions.SystemFunction;
006: import net.sf.saxon.instruct.SimpleContentConstructor;
007: import net.sf.saxon.trans.StaticError;
008: import net.sf.saxon.trans.XPathException;
009: import net.sf.saxon.type.Type;
010: import net.sf.saxon.type.TypeHierarchy;
011: import net.sf.saxon.value.Cardinality;
012: import net.sf.saxon.value.StringValue;
013:
014: import java.util.ArrayList;
015: import java.util.List;
016:
017: /**
018: * This class represents an attribute value template. The class allows an AVT to be parsed, and
019: * can construct an Expression that returns the effective value of the AVT.
020: *
021: * This is an abstract class that is never instantiated, it contains static methods only.
022: */
023:
024: public abstract class AttributeValueTemplate {
025:
026: private AttributeValueTemplate() {
027: }
028:
029: /**
030: * Static factory method to create an AVT from an XSLT string representation.
031: */
032:
033: public static Expression make(String avt, int lineNumber,
034: StaticContext env) throws XPathException {
035:
036: List components = new ArrayList(5);
037:
038: int i0, i1, i8, i9;
039: int len = avt.length();
040: int last = 0;
041: while (last < len) {
042:
043: i0 = avt.indexOf("{", last);
044: i1 = avt.indexOf("{{", last);
045: i8 = avt.indexOf("}", last);
046: i9 = avt.indexOf("}}", last);
047:
048: if ((i0 < 0 || len < i0) && (i8 < 0 || len < i8)) { // found end of string
049: addStringComponent(components, avt, last, len);
050: break;
051: } else if (i8 >= 0 && (i0 < 0 || i8 < i0)) { // found a "}"
052: if (i8 != i9) { // a "}" that isn't a "}}"
053: StaticError err = new StaticError(
054: "Closing curly brace in attribute value template \""
055: + avt.substring(0, len)
056: + "\" must be doubled");
057: err.setErrorCode("XTSE0360");
058: throw err;
059: }
060: addStringComponent(components, avt, last, i8 + 1);
061: last = i8 + 2;
062: } else if (i1 >= 0 && i1 == i0) { // found a doubled "{{"
063: addStringComponent(components, avt, last, i1 + 1);
064: last = i1 + 2;
065: } else if (i0 >= 0) { // found a single "{"
066: if (i0 > last) {
067: addStringComponent(components, avt, last, i0);
068: }
069: Expression exp;
070: ExpressionParser parser = new ExpressionParser();
071: exp = parser.parse(avt, i0 + 1, Token.RCURLY,
072: lineNumber, env);
073: exp = exp.simplify(env);
074: last = parser.getTokenizer().currentTokenStartOffset + 1;
075:
076: if (env.isInBackwardsCompatibleMode()) {
077: components.add(makeFirstItem(exp, env));
078: } else {
079: components.add(new SimpleContentConstructor(exp,
080: StringValue.SINGLE_SPACE).simplify(env));
081: }
082:
083: } else {
084: throw new IllegalStateException(
085: "Internal error parsing AVT");
086: }
087: }
088:
089: // is it empty?
090:
091: if (components.size() == 0) {
092: return StringValue.EMPTY_STRING;
093: }
094:
095: // is it a single component?
096:
097: if (components.size() == 1) {
098: return ((Expression) components.get(0)).simplify(env);
099: }
100:
101: // otherwise, return an expression that concatenates the components
102:
103: Concat fn = (Concat) SystemFunction.makeSystemFunction(
104: "concat", components.size(), env.getNamePool());
105: Expression[] args = new Expression[components.size()];
106: components.toArray(args);
107: fn.setArguments(args);
108: fn.setLocationId(env.getLocationMap().allocateLocationId(
109: env.getSystemId(), lineNumber));
110: return fn.simplify(env);
111:
112: }
113:
114: private static void addStringComponent(List components, String avt,
115: int start, int end) {
116: if (start < end) {
117: components.add(StringValue.makeStringValue(avt.substring(
118: start, end)));
119: }
120: }
121:
122: /**
123: * Make an expression that extracts the first item of a sequence, after atomization
124: */
125:
126: public static Expression makeFirstItem(Expression exp,
127: StaticContext env) {
128: final TypeHierarchy th = env.getNamePool().getTypeHierarchy();
129: if (!exp.getItemType(th).isAtomicType()) {
130: exp = new Atomizer(exp, env.getConfiguration());
131: }
132: if (Cardinality.allowsMany(exp.getCardinality())) {
133: exp = new FirstItemExpression(exp);
134: }
135: if (!th.isSubType(exp.getItemType(th), Type.STRING_TYPE)) {
136: exp = new AtomicSequenceConverter(exp, Type.STRING_TYPE);
137: }
138: return exp;
139: }
140:
141: }
142:
143: //
144: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
145: // you may not use this file except in compliance with the License. You may obtain a copy of the
146: // License at http://www.mozilla.org/MPL/
147: //
148: // Software distributed under the License is distributed on an "AS IS" basis,
149: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
150: // See the License for the specific language governing rights and limitations under the License.
151: //
152: // The Original Code is: all this file.
153: //
154: // The Initial Developer of the Original Code is Michael H. Kay.
155: //
156: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
157: //
158: // Contributor(s): none.
159: //
|