001: package net.sf.saxon.style;
002:
003: import net.sf.saxon.expr.Expression;
004: import net.sf.saxon.instruct.*;
005: import net.sf.saxon.om.*;
006: import net.sf.saxon.trans.XPathException;
007: import net.sf.saxon.type.AnyItemType;
008: import net.sf.saxon.value.EmptySequence;
009:
010: import java.util.ArrayList;
011: import java.util.Iterator;
012: import java.util.List;
013:
014: /**
015: * An xsl:attribute-set element in the stylesheet. <br>
016: */
017:
018: public class XSLAttributeSet extends StyleElement implements
019: StylesheetProcedure {
020:
021: private String nameAtt;
022: // the name of the attribute set as written
023:
024: private String useAtt;
025: // the value of the use-attribute-sets attribute, as supplied
026:
027: private SlotManager stackFrameMap;
028: // needed if variables are used
029:
030: private List attributeSetElements = null;
031: // list of XSLAttributeSet objects referenced by this one
032:
033: private AttributeSet[] useAttributeSets = null;
034: // compiled instructions for the attribute sets used by this one
035:
036: private AttributeSet procedure = new AttributeSet();
037: // the compiled form of this attribute set
038:
039: private int referenceCount = 0;
040: // the number of references to this attribute set
041:
042: private boolean validated = false;
043:
044: public int getAttributeSetFingerprint() {
045: return getObjectFingerprint();
046: }
047:
048: public AttributeSet getInstruction() {
049: return procedure;
050: }
051:
052: public void incrementReferenceCount() {
053: referenceCount++;
054: }
055:
056: public void prepareAttributes() throws XPathException {
057: useAtt = null;
058:
059: AttributeCollection atts = getAttributeList();
060:
061: for (int a = 0; a < atts.getLength(); a++) {
062: int nc = atts.getNameCode(a);
063: String f = getNamePool().getClarkName(nc);
064: if (f == StandardNames.NAME) {
065: nameAtt = atts.getValue(a).trim();
066: } else if (f == StandardNames.USE_ATTRIBUTE_SETS) {
067: useAtt = atts.getValue(a);
068: } else {
069: checkUnknownAttribute(nc);
070: }
071: }
072:
073: if (nameAtt == null) {
074: reportAbsence("name");
075: return;
076: }
077:
078: try {
079: setObjectNameCode(makeNameCode(nameAtt.trim()));
080: } catch (NamespaceException err) {
081: compileError(err.getMessage(), "XTSE0280");
082: } catch (XPathException err) {
083: compileError(err.getMessage(), "XTSE0280");
084: }
085:
086: }
087:
088: public void validate() throws XPathException {
089:
090: if (validated)
091: return;
092:
093: checkTopLevel(null);
094:
095: stackFrameMap = getConfiguration().makeSlotManager();
096:
097: AxisIterator kids = iterateAxis(Axis.CHILD);
098: while (true) {
099: Item child = kids.next();
100: if (child == null) {
101: break;
102: }
103: if (!(child instanceof XSLAttribute)) {
104: compileError(
105: "Only xsl:attribute is allowed within xsl:attribute-set",
106: "XTSE0010");
107: }
108: }
109:
110: if (useAtt != null) {
111: // identify any attribute sets that this one refers to
112:
113: attributeSetElements = new ArrayList(5);
114: useAttributeSets = getAttributeSets(useAtt,
115: attributeSetElements);
116:
117: // check for circularity
118:
119: for (Iterator it = attributeSetElements.iterator(); it
120: .hasNext();) {
121: ((XSLAttributeSet) it.next()).checkCircularity(this );
122: }
123: }
124:
125: validated = true;
126: }
127:
128: /**
129: * Check for circularity: specifically, check that this attribute set does not contain
130: * a direct or indirect reference to the one supplied as a parameter
131: */
132:
133: public void checkCircularity(XSLAttributeSet origin)
134: throws XPathException {
135: if (this == origin) {
136: compileError(
137: "The definition of the attribute set is circular",
138: "XTSE0720");
139: } else {
140: if (!validated) {
141: // if this attribute set isn't validated yet, we don't check it.
142: // The circularity will be detected when the last attribute set in the cycle
143: // gets validated
144: return;
145: }
146: if (attributeSetElements != null) {
147: for (Iterator it = attributeSetElements.iterator(); it
148: .hasNext();) {
149: ((XSLAttributeSet) it.next())
150: .checkCircularity(origin);
151: }
152: }
153: }
154: }
155:
156: /**
157: * Get details of stack frame
158: */
159:
160: public SlotManager getSlotManager() {
161: return stackFrameMap;
162: }
163:
164: /**
165: * Compile the attribute set
166: * @param exec the Executable
167: * @return a Procedure object representing the compiled attribute set
168: * @throws XPathException if a failure is detected
169: */
170: public Expression compile(Executable exec) throws XPathException {
171: if (referenceCount > 0) {
172: Expression body = compileSequenceConstructor(exec,
173: iterateAxis(Axis.CHILD), true);
174: if (body == null) {
175: body = EmptySequence.getInstance();
176: }
177:
178: try {
179:
180: body = body.simplify(getStaticContext());
181: if (getConfiguration().getTraceListener() != null) {
182: TraceWrapper trace = new TraceInstruction(body,
183: this );
184: trace.setLocationId(allocateLocationId(
185: getSystemId(), getLineNumber()));
186: trace.setParentExpression(procedure);
187: body = trace;
188: }
189:
190: procedure.setUseAttributeSets(useAttributeSets);
191: procedure.setNameCode(getObjectNameCode());
192: procedure.setBody(body);
193: procedure.setSystemId(getSystemId());
194: procedure.setLineNumber(getLineNumber());
195: procedure.setExecutable(exec);
196:
197: Expression exp2 = body.optimize(getConfiguration()
198: .getOptimizer(), staticContext, AnyItemType
199: .getInstance());
200: if (body != exp2) {
201: procedure.setBody(exp2);
202: body = exp2;
203: }
204:
205: super .allocateSlots(body);
206: procedure.setStackFrameMap(stackFrameMap);
207: } catch (XPathException e) {
208: compileError(e);
209: }
210: }
211: return null;
212: }
213:
214: /**
215: * Get the type of construct. This will be a constant in
216: * class {@link net.sf.saxon.trace.Location}. This method is part of
217: * the {@link net.sf.saxon.trace.InstructionInfo} interface
218: */
219:
220: public int getConstructType() {
221: return StandardNames.XSL_ATTRIBUTE_SET;
222: }
223:
224: }
225:
226: //
227: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
228: // you may not use this file except in compliance with the License. You may obtain a copy of the
229: // License at http://www.mozilla.org/MPL/
230: //
231: // Software distributed under the License is distributed on an "AS IS" basis,
232: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
233: // See the License for the specific language governing rights and limitations under the License.
234: //
235: // The Original Code is: all this file.
236: //
237: // The Initial Developer of the Original Code is Michael H. Kay.
238: //
239: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
240: //
241: // Contributor(s): none.
242: //
|