001: package net.sf.saxon.style;
002:
003: import net.sf.saxon.Configuration;
004: import net.sf.saxon.event.LocationProvider;
005: import net.sf.saxon.om.AttributeCollectionImpl;
006: import net.sf.saxon.om.NamePool;
007: import net.sf.saxon.om.NamespaceConstant;
008: import net.sf.saxon.om.NodeInfo;
009: import net.sf.saxon.sort.IntHashMap;
010: import net.sf.saxon.trans.StaticError;
011: import net.sf.saxon.trans.XPathException;
012: import net.sf.saxon.tree.ElementImpl;
013: import net.sf.saxon.tree.NodeFactory;
014:
015: import javax.xml.transform.TransformerException;
016: import javax.xml.transform.TransformerFactoryConfigurationError;
017: import java.math.BigDecimal;
018:
019: /**
020: * Class StyleNodeFactory. <br>
021: * A Factory for nodes in the stylesheet tree. <br>
022: * Currently only allows Element nodes to be user-constructed.
023: * @author Michael H. Kay
024: */
025:
026: public class StyleNodeFactory implements NodeFactory {
027:
028: IntHashMap userStyles = new IntHashMap(4);
029: Configuration config;
030: NamePool namePool;
031: boolean allowExtensions;
032:
033: public StyleNodeFactory(Configuration config) {
034:
035: this .config = config;
036: namePool = config.getNamePool();
037: this .allowExtensions = config.isAllowExternalFunctions();
038: }
039:
040: /**
041: * Create an Element node. Note, if there is an error detected while constructing
042: * the Element, we add the element anyway, and return success, but flag the element
043: * with a validation error. This allows us to report more than
044: * one error from a single compilation.
045: * @param nameCode The element name
046: * @param attlist the attribute list
047: */
048:
049: public ElementImpl makeElementNode(NodeInfo parent, int nameCode,
050: AttributeCollectionImpl attlist, int[] namespaces,
051: int namespacesUsed, LocationProvider locator,
052: int locationId, int sequence) {
053: boolean toplevel = (parent instanceof XSLStylesheet);
054: String baseURI = null;
055: int lineNumber = -1;
056:
057: if (locator != null) {
058: baseURI = locator.getSystemId(locationId);
059: lineNumber = locator.getLineNumber(locationId);
060: }
061:
062: if (parent instanceof DataElement) {
063: DataElement d = new DataElement();
064: d.setNamespaceDeclarations(namespaces, namespacesUsed);
065: d.initialise(nameCode, attlist, parent, baseURI,
066: lineNumber, sequence);
067: return d;
068: }
069:
070: int f = nameCode & 0xfffff;
071:
072: // Try first to make an XSLT element
073:
074: StyleElement e = makeXSLElement(f);
075:
076: if (e != null) { // recognized as an XSLT element
077: try {
078: e.setNamespaceDeclarations(namespaces, namespacesUsed);
079: e.setLineNumber(lineNumber);
080: e.initialise(nameCode, attlist, parent, baseURI, -1,
081: sequence);
082: e
083: .processDefaultCollationAttribute(StandardNames.DEFAULT_COLLATION);
084: e
085: .processExtensionElementAttribute(StandardNames.EXTENSION_ELEMENT_PREFIXES);
086: e
087: .processExcludedNamespaces(StandardNames.EXCLUDE_RESULT_PREFIXES);
088: e.processVersionAttribute(StandardNames.VERSION);
089: e
090: .processDefaultXPathNamespaceAttribute(StandardNames.XPATH_DEFAULT_NAMESPACE);
091: } catch (TransformerException err) {
092: e.setValidationError(err, StyleElement.REPORT_ALWAYS);
093: }
094: return e;
095:
096: } else { // not recognized as an XSLT element
097:
098: short uriCode = namePool.getURICode(nameCode);
099: String localname = namePool.getLocalName(nameCode);
100: StyleElement temp = null;
101:
102: // Detect a misspelt XSLT declaration
103:
104: if (uriCode == NamespaceConstant.XSLT_CODE
105: && (parent instanceof XSLStylesheet)
106: && ((XSLStylesheet) parent).getVersion().compareTo(
107: BigDecimal.valueOf('2')) <= 0) {
108: temp = new AbsentExtensionElement();
109: temp.setValidationError(new StaticError(
110: "Unknown top-level XSLT declaration"),
111: StyleElement.REPORT_UNLESS_FORWARDS_COMPATIBLE);
112: }
113:
114: Class assumedClass = LiteralResultElement.class;
115:
116: // We can't work out the final class of the node until we've examined its attributes
117: // such as version and extension-element-prefixes; but we can have a good guess, and
118: // change it later if need be.
119:
120: boolean assumedSaxonElement = false;
121:
122: // recognize Saxon extension elements
123:
124: if (temp == null) {
125: if (uriCode == NamespaceConstant.SAXON_CODE) {
126: temp = makeSaxonElement(f);
127: if (temp != null) {
128: assumedClass = temp.getClass();
129: assumedSaxonElement = true;
130: }
131: } else if (toplevel && uriCode != 0) {
132: DataElement d = new DataElement();
133: d.setNamespaceDeclarations(namespaces,
134: namespacesUsed);
135: d.initialise(nameCode, attlist, parent, baseURI,
136: lineNumber, sequence);
137: return d;
138: }
139: }
140:
141: if (temp == null) {
142: temp = new LiteralResultElement();
143: }
144:
145: temp.setNamespaceDeclarations(namespaces, namespacesUsed);
146:
147: try {
148: temp.initialise(nameCode, attlist, parent, baseURI,
149: lineNumber, sequence);
150: temp.setLineNumber(lineNumber);
151: temp
152: .processDefaultCollationAttribute(StandardNames.XSL_DEFAULT_COLLATION_CLARK);
153: temp
154: .processExtensionElementAttribute(StandardNames.XSL_EXTENSION_ELEMENT_PREFIXES_CLARK);
155: temp
156: .processExcludedNamespaces(StandardNames.XSL_EXCLUDE_RESULT_PREFIXES_CLARK);
157: temp
158: .processVersionAttribute(StandardNames.XSL_VERSION_CLARK);
159: temp
160: .processDefaultXPathNamespaceAttribute(StandardNames.XSL_XPATH_DEFAULT_NAMESPACE_CLARK);
161: } catch (XPathException err) {
162: temp
163: .setValidationError(err,
164: StyleElement.REPORT_ALWAYS);
165: }
166:
167: // Now we work out what class of element we really wanted, and change it if necessary
168:
169: TransformerException reason;
170: Class actualClass;
171:
172: if (uriCode == NamespaceConstant.XSLT_CODE) {
173: reason = new StaticError("Unknown XSLT element: "
174: + localname);
175: ((StaticError) reason).setErrorCode("XTSE0010");
176: actualClass = AbsentExtensionElement.class;
177: temp.setValidationError(reason,
178: StyleElement.REPORT_UNLESS_FALLBACK_AVAILABLE);
179: } else if (uriCode == NamespaceConstant.SAXON_CODE) {
180: if (toplevel || temp.isExtensionNamespace(uriCode)) {
181: if (assumedSaxonElement) {
182: // all is well
183: actualClass = assumedClass;
184: } else {
185: actualClass = AbsentExtensionElement.class;
186: reason = new StaticError(
187: "Unknown Saxon extension element: "
188: + localname);
189: temp
190: .setValidationError(
191: reason,
192: StyleElement.REPORT_UNLESS_FALLBACK_AVAILABLE);
193: }
194: } else {
195: actualClass = LiteralResultElement.class;
196: }
197: } else if (temp.isExtensionNamespace(uriCode) && !toplevel) {
198: actualClass = (Class) userStyles
199: .get(nameCode & 0xfffff);
200: if (actualClass == null) {
201: if (allowExtensions) {
202: ExtensionElementFactory factory = getFactory(uriCode);
203: if (factory != null) {
204: actualClass = factory
205: .getExtensionClass(localname);
206: if (actualClass != null) {
207: userStyles.put(nameCode & 0xfffff,
208: actualClass); // for quicker access next time
209: }
210: }
211: } else {
212: actualClass = AbsentExtensionElement.class;
213: reason = new StaticError(
214: "Extension elements are disabled");
215: temp.setValidationError(reason,
216: StyleElement.REPORT_IF_INSTANTIATED);
217: }
218:
219: if (actualClass == null) {
220:
221: // if we can't instantiate an extension element, we don't give up
222: // immediately, because there might be an xsl:fallback defined. We
223: // create a surrogate element called AbsentExtensionElement, and
224: // save the reason for failure just in case there is no xsl:fallback
225:
226: actualClass = AbsentExtensionElement.class;
227: StaticError se = new StaticError(
228: "Unknown extension element", temp);
229: se.setErrorCode("XTDE1450");
230: reason = se;
231: temp.setValidationError(reason,
232: StyleElement.REPORT_IF_INSTANTIATED);
233: }
234: }
235: } else {
236: actualClass = LiteralResultElement.class;
237: }
238:
239: StyleElement node;
240: if (actualClass.equals(assumedClass)) {
241: node = temp; // the original element will do the job
242: } else {
243: try {
244: node = (StyleElement) actualClass.newInstance();
245: } catch (InstantiationException err1) {
246: throw new TransformerFactoryConfigurationError(
247: err1, "Failed to create instance of "
248: + actualClass.getName());
249: } catch (IllegalAccessException err2) {
250: throw new TransformerFactoryConfigurationError(
251: err2, "Failed to access class "
252: + actualClass.getName());
253: }
254: node.substituteFor(temp); // replace temporary node with the new one
255: }
256: return node;
257: }
258: }
259:
260: /**
261: * Make an XSL element node
262: */
263:
264: private StyleElement makeXSLElement(int f) {
265: switch (f) {
266: case StandardNames.XSL_ANALYZE_STRING:
267: return new XSLAnalyzeString();
268: case StandardNames.XSL_APPLY_IMPORTS:
269: return new XSLApplyImports();
270: case StandardNames.XSL_APPLY_TEMPLATES:
271: return new XSLApplyTemplates();
272: case StandardNames.XSL_ATTRIBUTE:
273: return new XSLAttribute();
274: case StandardNames.XSL_ATTRIBUTE_SET:
275: return new XSLAttributeSet();
276: case StandardNames.XSL_CALL_TEMPLATE:
277: return new XSLCallTemplate();
278: case StandardNames.XSL_CHARACTER_MAP:
279: return new XSLCharacterMap();
280: case StandardNames.XSL_CHOOSE:
281: return new XSLChoose();
282: case StandardNames.XSL_COMMENT:
283: return new XSLComment();
284: case StandardNames.XSL_COPY:
285: return new XSLCopy();
286: case StandardNames.XSL_COPY_OF:
287: return new XSLCopyOf();
288: case StandardNames.XSL_DECIMAL_FORMAT:
289: return new XSLDecimalFormat();
290: case StandardNames.XSL_DOCUMENT:
291: return new XSLDocument();
292: case StandardNames.XSL_ELEMENT:
293: return new XSLElement();
294: case StandardNames.XSL_FALLBACK:
295: return new XSLFallback();
296: case StandardNames.XSL_FOR_EACH:
297: return new XSLForEach();
298: case StandardNames.XSL_FOR_EACH_GROUP:
299: return new XSLForEachGroup();
300: case StandardNames.XSL_FUNCTION:
301: return new XSLFunction();
302: case StandardNames.XSL_IF:
303: return new XSLIf();
304: case StandardNames.XSL_IMPORT:
305: return new XSLImport();
306: case StandardNames.XSL_IMPORT_SCHEMA:
307: return new XSLImportSchema();
308: case StandardNames.XSL_INCLUDE:
309: return new XSLInclude();
310: case StandardNames.XSL_KEY:
311: return new XSLKey();
312: case StandardNames.XSL_MATCHING_SUBSTRING:
313: return new XSLMatchingSubstring();
314: case StandardNames.XSL_MESSAGE:
315: return new XSLMessage();
316: case StandardNames.XSL_NEXT_MATCH:
317: return new XSLNextMatch();
318: case StandardNames.XSL_NON_MATCHING_SUBSTRING:
319: return new XSLMatchingSubstring(); //sic
320: case StandardNames.XSL_NUMBER:
321: return new XSLNumber();
322: case StandardNames.XSL_NAMESPACE:
323: return new XSLNamespace();
324: case StandardNames.XSL_NAMESPACE_ALIAS:
325: return new XSLNamespaceAlias();
326: case StandardNames.XSL_OTHERWISE:
327: return new XSLOtherwise();
328: case StandardNames.XSL_OUTPUT:
329: return new XSLOutput();
330: case StandardNames.XSL_OUTPUT_CHARACTER:
331: return new XSLOutputCharacter();
332: case StandardNames.XSL_PARAM:
333: return new XSLParam();
334: case StandardNames.XSL_PERFORM_SORT:
335: return new XSLPerformSort();
336: case StandardNames.XSL_PRESERVE_SPACE:
337: return new XSLPreserveSpace();
338: case StandardNames.XSL_PROCESSING_INSTRUCTION:
339: return new XSLProcessingInstruction();
340: case StandardNames.XSL_RESULT_DOCUMENT:
341: return new XSLResultDocument();
342: case StandardNames.XSL_SEQUENCE:
343: return new XSLSequence();
344: case StandardNames.XSL_SORT:
345: return new XSLSort();
346: case StandardNames.XSL_STRIP_SPACE:
347: return new XSLPreserveSpace();
348: case StandardNames.XSL_STYLESHEET:
349: return new XSLStylesheet();
350: case StandardNames.XSL_TEMPLATE:
351: return new XSLTemplate();
352: case StandardNames.XSL_TEXT:
353: return new XSLText();
354: case StandardNames.XSL_TRANSFORM:
355: return new XSLStylesheet();
356: case StandardNames.XSL_VALUE_OF:
357: return new XSLValueOf();
358: case StandardNames.XSL_VARIABLE:
359: return new XSLVariable();
360: case StandardNames.XSL_WITH_PARAM:
361: return new XSLWithParam();
362: case StandardNames.XSL_WHEN:
363: return new XSLWhen();
364: default:
365: return null;
366: }
367: }
368:
369: /**
370: * Make a SAXON extension element
371: */
372:
373: private StyleElement makeSaxonElement(int f) {
374:
375: switch (f) {
376:
377: case StandardNames.SAXON_ASSIGN:
378: return new SaxonAssign();
379: case StandardNames.SAXON_ENTITY_REF:
380: return new SaxonEntityRef();
381: case StandardNames.SAXON_CALL_TEMPLATE:
382: return new SaxonCallTemplate();
383: case StandardNames.SAXON_COLLATION:
384: return new SaxonCollation();
385: case StandardNames.SAXON_DOCTYPE:
386: return new SaxonDoctype();
387: case StandardNames.SAXON_IMPORT_QUERY:
388: return new SaxonImportQuery();
389: case StandardNames.SAXON_SCRIPT:
390: return new SaxonScript();
391: case StandardNames.SAXON_WHILE:
392: return new SaxonWhile();
393: default:
394: return null;
395: }
396: }
397:
398: /**
399: * Get the factory class for user extension elements
400: * If there is no appropriate class, return null
401: */
402:
403: private ExtensionElementFactory getFactory(short uriCode) {
404: String uri = namePool.getURIFromNamespaceCode(uriCode);
405: int lastSlash = uri.lastIndexOf('/');
406: if (lastSlash < 0 || lastSlash == uri.length() - 1) {
407: return null;
408: }
409: String factoryClass = uri.substring(lastSlash + 1);
410: ExtensionElementFactory factory;
411:
412: try {
413: factory = (ExtensionElementFactory) config.getInstance(
414: factoryClass, null);
415: } catch (XPathException err) {
416: return null;
417: }
418: return factory;
419: }
420:
421: /**
422: * Method to support the element-available() function
423: */
424:
425: public boolean isElementAvailable(String uri, String localName) {
426: int fingerprint = namePool.getFingerprint(uri, localName);
427: if (uri.equals(NamespaceConstant.XSLT)) {
428: if (fingerprint == -1)
429: return false; // all names are pre-registered
430: StyleElement e = makeXSLElement(fingerprint);
431: if (e != null)
432: return e.isInstruction();
433: }
434:
435: if (uri.equals(NamespaceConstant.SAXON)) {
436: if (fingerprint == -1)
437: return false; // all names are pre-registered
438: StyleElement e = makeSaxonElement(fingerprint);
439: if (e != null)
440: return e.isInstruction();
441: }
442: if (!allowExtensions) {
443: // extension elements are disabled
444: return false;
445: }
446: short uriCode = namePool.getCodeForURI(uri);
447: ExtensionElementFactory factory = getFactory(uriCode);
448: if (factory == null)
449: return false;
450: Class actualClass = factory.getExtensionClass(localName);
451: return (actualClass != null);
452:
453: }
454:
455: }
456:
457: //
458: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
459: // you may not use this file except in compliance with the License. You may obtain a copy of the
460: // License at http://www.mozilla.org/MPL/
461: //
462: // Software distributed under the License is distributed on an "AS IS" basis,
463: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
464: // See the License for the specific language governing rights and limitations under the License.
465: //
466: // The Original Code is: all this file.
467: //
468: // The Initial Developer of the Original Code is Michael H. Kay.
469: //
470: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
471: //
472: // Contributor(s): none.
473: //
|