package client.net.sf.saxon.ce.style; import client.net.sf.saxon.ce.PreparedStylesheet; import client.net.sf.saxon.ce.expr.Expression; import client.net.sf.saxon.ce.expr.instruct.Executable; import client.net.sf.saxon.ce.functions.DocumentFn; import client.net.sf.saxon.ce.om.AttributeCollection; import client.net.sf.saxon.ce.om.DocumentInfo; import client.net.sf.saxon.ce.om.DocumentURI; import client.net.sf.saxon.ce.om.StandardNames; import client.net.sf.saxon.ce.trans.XPathException; import client.net.sf.saxon.ce.tree.linked.DocumentImpl; import client.net.sf.saxon.ce.tree.linked.ElementImpl; import client.net.sf.saxon.ce.tree.util.URI; import client.net.sf.saxon.ce.value.Whitespace; /** * Abstract class to represent xsl:include or xsl:import element in the stylesheet. <br> * The xsl:include and xsl:import elements have mandatory attribute href */ public abstract class XSLGeneralIncorporate extends StyleElement { private String href; /** * Ask whether this node is a declaration, that is, a permitted child of xsl:stylesheet * (including xsl:include and xsl:import). * @return true for this element */ @Override public boolean isDeclaration() { return true; } /** * isImport() returns true if this is an xsl:import declaration rather than an xsl:include * @return true if this is an xsl:import declaration, false if it is an xsl:include */ public abstract boolean isImport(); public void prepareAttributes() throws XPathException { AttributeCollection atts = getAttributeList(); for (int a=0; a<atts.getLength(); a++) { int nc = atts.getNameCode(a); String f = getNamePool().getClarkName(nc); if (f.equals(StandardNames.HREF)) { href = Whitespace.trim(atts.getValue(a)); } else { checkUnknownAttribute(nc); } } if (href==null) { reportAbsence("href"); } } public void validate(Declaration decl) throws XPathException { validateInstruction(); } public void validateInstruction() throws XPathException { checkEmpty(); checkTopLevel(isImport() ? "XTSE0190" : "XTSE0170"); } /** * Get the included or imported stylesheet module * @param importer the module that requested the include or import (used to check for cycles) * @param precedence the import precedence to be allocated to the included or imported module * @return the xsl:stylesheet element at the root of the included/imported module * @throws XPathException if any failure occurs */ public StylesheetModule getIncludedStylesheet(StylesheetModule importer, int precedence) throws XPathException { if (href==null) { // error already reported return null; } //checkEmpty(); //checkTopLevel((this instanceof XSLInclude ? "XTSE0170" : "XTSE0190")); try { PrincipalStylesheetModule psm = importer.getPrincipalStylesheetModule(); PreparedStylesheet pss = psm.getPreparedStylesheet(); XSLStylesheet includedSheet; StylesheetModule incModule; DocumentURI key = DocumentFn.computeDocumentKey(href, getBaseURI()); includedSheet = psm.getStylesheetDocument(key); if (includedSheet != null) { // we already have the stylesheet document in cache; but we need to create a new module, // because the import precedence might be different. See test impincl30. incModule = new StylesheetModule(includedSheet, precedence); incModule.setImporter(importer); } else { //System.err.println("GeneralIncorporate: href=" + href + " base=" + getBaseURI()); String relative = href; String fragment = null; int hash = relative.indexOf('#'); if (hash == 0 || relative.length() == 0) { compileError("A stylesheet cannot " + getLocalPart() + " itself", (this instanceof XSLInclude ? "XTSE0180" : "XTSE0210")); return null; } else if (hash == relative.length() - 1) { relative = relative.substring(0, hash); } else if (hash > 0) { if (hash+1 < relative.length()) { fragment = relative.substring(hash+1); } relative = relative.substring(0, hash); } String source; try { URI base = new URI(getBaseURI()); URI abs = base.resolve(relative); source = abs.toString(); } catch (URI.URISyntaxException e) { throw new XPathException(e); } // check for recursion StylesheetModule anc = importer; if (source != null) { while(anc!=null) { if (source.equals(anc.getSourceElement().getSystemId())) { compileError("A stylesheet cannot " + getLocalPart() + " itself", (this instanceof XSLInclude ? "XTSE0180" : "XTSE0210")); return null; } anc = anc.getImporter(); } } DocumentInfo rawDoc = getConfiguration().buildDocument(source); getConfiguration().getDocumentPool().add(rawDoc, key); DocumentImpl includedDoc = pss.loadStylesheetModule(rawDoc); // allow the included document to use "Literal Result Element as Stylesheet" syntax ElementImpl outermost = includedDoc.getDocumentElement(); if (outermost instanceof LiteralResultElement) { includedDoc = ((LiteralResultElement)outermost) .makeStylesheet(getPreparedStylesheet()); outermost = includedDoc.getDocumentElement(); } if (!(outermost instanceof XSLStylesheet)) { compileError("Included document " + href + " is not a stylesheet", "XTSE0165"); return null; } includedSheet = (XSLStylesheet)outermost; includedSheet.setPrincipalStylesheetModule(psm); psm.putStylesheetDocument(key, includedSheet); incModule = new StylesheetModule(includedSheet, precedence); incModule.setImporter(importer); Declaration decl = new Declaration(incModule, includedSheet); includedSheet.validate(decl); if (includedSheet.validationError!=null) { if (reportingCircumstances == REPORT_ALWAYS) { includedSheet.compileError(includedSheet.validationError); } else if (includedSheet.reportingCircumstances == REPORT_UNLESS_FORWARDS_COMPATIBLE // not sure if this can still happen /*&& !incSheet.forwardsCompatibleModeIsEnabled()*/) { includedSheet.compileError(includedSheet.validationError); } } } incModule.spliceIncludes(); // resolve any nested imports and includes; // Check the consistency of input-type-annotations //assert thisSheet != null; importer.setInputTypeAnnotations(includedSheet.getInputTypeAnnotationsAttribute() | incModule.getInputTypeAnnotations()); return incModule; } catch (XPathException err) { err.setErrorCode("XTSE0165"); err.setIsStaticError(true); compileError(err); return null; } } public Expression compile(Executable exec, Declaration decl) throws XPathException { return null; // no action. The node will never be compiled, because it replaces itself // by the contents of the included file. } } // This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. // If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. // This Source Code Form is “Incompatible With Secondary Licenses”, as defined by the Mozilla Public License, v. 2.0.