001: package net.sf.saxon.style;
002:
003: import net.sf.saxon.Configuration;
004: import net.sf.saxon.Err;
005: import net.sf.saxon.expr.Expression;
006: import net.sf.saxon.expr.ExpressionTool;
007: import net.sf.saxon.expr.ComputedExpression;
008: import net.sf.saxon.instruct.*;
009: import net.sf.saxon.om.*;
010: import net.sf.saxon.trans.XPathException;
011: import net.sf.saxon.type.SchemaType;
012: import net.sf.saxon.value.EmptySequence;
013: import net.sf.saxon.value.StringValue;
014:
015: /**
016: * An xsl:element element in the stylesheet. <br>
017: */
018:
019: public class XSLElement extends StyleElement {
020:
021: private Expression elementName;
022: private Expression namespace = null;
023: private String use;
024: private AttributeSet[] attributeSets = null;
025: private int validation;
026: private SchemaType schemaType = null;
027: private boolean inheritNamespaces = true;
028:
029: /**
030: * Determine whether this node is an instruction.
031: *
032: * @return true - it is an instruction
033: */
034:
035: public boolean isInstruction() {
036: return true;
037: }
038:
039: /**
040: * Determine whether this type of element is allowed to contain a template-body
041: *
042: * @return true: yes, it may contain a template-body
043: */
044:
045: public boolean mayContainSequenceConstructor() {
046: return true;
047: }
048:
049: public void prepareAttributes() throws XPathException {
050:
051: AttributeCollection atts = getAttributeList();
052:
053: String nameAtt = null;
054: String namespaceAtt = null;
055: String validationAtt = null;
056: String typeAtt = null;
057: String inheritAtt = null;
058:
059: for (int a = 0; a < atts.getLength(); a++) {
060: int nc = atts.getNameCode(a);
061: String f = getNamePool().getClarkName(nc);
062: if (f == StandardNames.NAME) {
063: nameAtt = atts.getValue(a).trim();
064: } else if (f == StandardNames.NAMESPACE) {
065: namespaceAtt = atts.getValue(a);
066: } else if (f == StandardNames.VALIDATION) {
067: validationAtt = atts.getValue(a).trim();
068: } else if (f == StandardNames.TYPE) {
069: typeAtt = atts.getValue(a).trim();
070: } else if (f == StandardNames.INHERIT_NAMESPACES) {
071: inheritAtt = atts.getValue(a).trim();
072: } else if (f == StandardNames.USE_ATTRIBUTE_SETS) {
073: use = atts.getValue(a);
074: } else {
075: checkUnknownAttribute(nc);
076: }
077: }
078:
079: if (nameAtt == null) {
080: reportAbsence("name");
081: } else {
082: elementName = makeAttributeValueTemplate(nameAtt);
083: if (elementName instanceof StringValue) {
084: if (!getConfiguration().getNameChecker().isQName(
085: ((StringValue) elementName).getStringValue())) {
086: compileError("Element name "
087: + Err.wrap(((StringValue) elementName)
088: .getStringValue(), Err.ELEMENT)
089: + " is not a valid QName", "XTDE0820");
090: // to prevent duplicate error messages:
091: elementName = new StringValue("saxon-error-element");
092: }
093: }
094: }
095:
096: if (namespaceAtt != null) {
097: namespace = makeAttributeValueTemplate(namespaceAtt);
098: }
099:
100: if (validationAtt != null) {
101: validation = Validation.getCode(validationAtt);
102: if (validation != Validation.STRIP
103: && !getConfiguration().isSchemaAware(
104: Configuration.XSLT)) {
105: compileError(
106: "To perform validation, a schema-aware XSLT processor is needed",
107: "XTSE1660");
108: }
109: if (validation == Validation.INVALID) {
110: compileError(
111: "Invalid value for @validation attribute. "
112: + "Permitted values are (strict, lax, preserve, strip)",
113: "XTSE0020");
114: }
115: } else {
116: validation = getContainingStylesheet()
117: .getDefaultValidation();
118: }
119:
120: if (typeAtt != null) {
121: if (!getConfiguration().isSchemaAware(Configuration.XSLT)) {
122: compileError(
123: "The @type attribute is available only with a schema-aware XSLT processor",
124: "XTSE1660");
125: }
126: schemaType = getSchemaType(typeAtt);
127: }
128:
129: if (typeAtt != null && validationAtt != null) {
130: compileError(
131: "The @validation and @type attributes are mutually exclusive",
132: "XTSE1505");
133: }
134:
135: if (inheritAtt != null) {
136: if (inheritAtt.equals("yes")) {
137: inheritNamespaces = true;
138: } else if (inheritAtt.equals("no")) {
139: inheritNamespaces = false;
140: } else {
141: compileError(
142: "The @inherit-namespaces attribute has permitted values (yes, no)",
143: "XTSE0020");
144: }
145: }
146: }
147:
148: public void validate() throws XPathException {
149: checkWithinTemplate();
150: if (use != null) {
151: attributeSets = getAttributeSets(use, null); // find any referenced attribute sets
152: }
153: elementName = typeCheck("name", elementName);
154: namespace = typeCheck("namespace", namespace);
155: }
156:
157: public Expression compile(Executable exec) throws XPathException {
158:
159: NamespaceResolver nsContext = null;
160:
161: // deal specially with the case where the element name is known statically
162:
163: if (elementName instanceof StringValue) {
164: CharSequence qName = ((StringValue) elementName)
165: .getStringValueCS();
166:
167: String[] parts;
168: try {
169: parts = getConfiguration().getNameChecker()
170: .getQNameParts(qName);
171: } catch (QNameException e) {
172: compileError("Invalid element name: " + qName,
173: "XTDE0820");
174: return null;
175: }
176:
177: String nsuri = null;
178: if (namespace instanceof StringValue) {
179: nsuri = ((StringValue) namespace).getStringValue();
180: if (nsuri.equals("")) {
181: parts[0] = "";
182: }
183: } else if (namespace == null) {
184: nsuri = getURIForPrefix(parts[0], true);
185: if (nsuri == null) {
186: undeclaredNamespaceError(parts[0], "XTDE0280");
187: }
188: }
189: if (nsuri != null) {
190: // Local name and namespace are both known statically: generate a FixedElement instruction
191: int nameCode = getTargetNamePool().allocate(parts[0],
192: nsuri, parts[1]);
193: FixedElement inst = new FixedElement(nameCode, null,
194: inheritNamespaces, schemaType, validation);
195: Expression content = compileSequenceConstructor(exec,
196: iterateAxis(Axis.CHILD), true);
197:
198: if (attributeSets != null) {
199: UseAttributeSets use = new UseAttributeSets(
200: attributeSets);
201: if (content == null) {
202: content = use;
203: } else {
204: content = Block.makeBlock(use, content);
205: if (content instanceof ComputedExpression) {
206: ((ComputedExpression) content)
207: .setLocationId(allocateLocationId(
208: getSystemId(),
209: getLineNumber()));
210: }
211: }
212: }
213: if (content == null) {
214: content = EmptySequence.getInstance();
215: }
216: inst.setContentExpression(content);
217: ExpressionTool.makeParentReferences(inst);
218: return inst;
219: }
220: } else {
221: // if the namespace URI must be deduced at run-time from the element name
222: // prefix, we need to save the namespace context of the instruction
223:
224: if (namespace == null) {
225: nsContext = makeNamespaceContext();
226: }
227: }
228:
229: ComputedElement inst = new ComputedElement(elementName,
230: namespace, nsContext, schemaType, validation,
231: inheritNamespaces, false);
232: Expression content = compileSequenceConstructor(exec,
233: iterateAxis(Axis.CHILD), true);
234: if (attributeSets != null) {
235: UseAttributeSets use = new UseAttributeSets(attributeSets);
236: if (content == null) {
237: content = use;
238: } else {
239: content = Block.makeBlock(use, content);
240: if (content instanceof ComputedExpression) {
241: ((ComputedExpression) content)
242: .setLocationId(allocateLocationId(
243: getSystemId(), getLineNumber()));
244: }
245: }
246: }
247: if (content == null) {
248: content = EmptySequence.getInstance();
249: }
250: inst.setContentExpression(content);
251: ExpressionTool.makeParentReferences(inst);
252: return inst;
253: }
254:
255: }
256:
257: //
258: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
259: // you may not use this file except in compliance with the License. You may obtain a copy of the
260: // License at http://www.mozilla.org/MPL/
261: //
262: // Software distributed under the License is distributed on an "AS IS" basis,
263: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
264: // See the License for the specific language governing rights and limitations under the License.
265: //
266: // The Original Code is: all this file.
267: //
268: // The Initial Developer of the Original Code is Michael H. Kay.
269: //
270: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
271: //
272: // Contributor(s): none.
273: //
|