0001: package net.sf.saxon.style;
0002:
0003: import net.sf.saxon.Err;
0004: import net.sf.saxon.PreparedStylesheet;
0005: import net.sf.saxon.Configuration;
0006: import net.sf.saxon.event.LocationProvider;
0007: import net.sf.saxon.expr.*;
0008: import net.sf.saxon.instruct.*;
0009: import net.sf.saxon.om.*;
0010: import net.sf.saxon.pattern.*;
0011: import net.sf.saxon.sort.SortKeyDefinition;
0012: import net.sf.saxon.trace.InstructionInfo;
0013: import net.sf.saxon.trace.Location;
0014: import net.sf.saxon.trans.DynamicError;
0015: import net.sf.saxon.trans.SaxonErrorCode;
0016: import net.sf.saxon.trans.StaticError;
0017: import net.sf.saxon.trans.XPathException;
0018: import net.sf.saxon.tree.ElementWithAttributes;
0019: import net.sf.saxon.type.*;
0020: import net.sf.saxon.value.*;
0021: import org.xml.sax.Locator;
0022:
0023: import javax.xml.transform.SourceLocator;
0024: import javax.xml.transform.TransformerConfigurationException;
0025: import javax.xml.transform.TransformerException;
0026: import java.math.BigDecimal;
0027: import java.util.ArrayList;
0028: import java.util.Iterator;
0029: import java.util.List;
0030: import java.util.StringTokenizer;
0031: import java.net.URI;
0032: import java.net.URISyntaxException;
0033:
0034: /**
0035: * Abstract superclass for all element nodes in the stylesheet. <BR>
0036: * Note: this class implements Locator. The element
0037: * retains information about its own location in the stylesheet, which is useful when
0038: * an XSL error is found.
0039: */
0040:
0041: public abstract class StyleElement extends ElementWithAttributes
0042: implements Locator, Container, InstructionInfo {
0043:
0044: protected short[] extensionNamespaces = null; // a list of URI codes
0045: private short[] excludedNamespaces = null; // a list of URI codes
0046: protected BigDecimal version = null;
0047: protected StaticContext staticContext = null;
0048: protected StaticError validationError = null;
0049: protected int reportingCircumstances = REPORT_ALWAYS;
0050: protected String defaultXPathNamespace = null;
0051: protected String defaultCollationName = null;
0052: private int lineNumber; // maintained here because it's more efficient
0053: // than using the lineNumberMap
0054: private boolean explaining = false;
0055: // true if saxon:explain="yes"
0056: private int objectNameCode = -1;
0057: // for instructions that define an XSLT named object, the name of that object
0058: private XSLStylesheet containingStylesheet;
0059:
0060: // Conditions under which an error is to be reported
0061:
0062: public static final int REPORT_ALWAYS = 1;
0063: public static final int REPORT_UNLESS_FORWARDS_COMPATIBLE = 2;
0064: public static final int REPORT_IF_INSTANTIATED = 3;
0065: public static final int REPORT_UNLESS_FALLBACK_AVAILABLE = 4;
0066:
0067: /**
0068: * Constructor
0069: */
0070:
0071: public StyleElement() {
0072: }
0073:
0074: public Executable getExecutable() {
0075: return getPrincipalStylesheet().getExecutable();
0076: }
0077:
0078: /**
0079: * Get the LocationProvider allowing location identifiers to be resolved.
0080: */
0081:
0082: public LocationProvider getLocationProvider() {
0083: return getExecutable().getLocationMap();
0084: }
0085:
0086: /**
0087: * Get the namepool to be used at run-time, this namepool holds the names used in
0088: * all XPath expressions and patterns
0089: */
0090:
0091: public NamePool getTargetNamePool() {
0092: return getPrincipalStylesheet().getTargetNamePool();
0093: }
0094:
0095: /**
0096: * Get the static context for expressions on this element
0097: *
0098: * @return the static context
0099: */
0100:
0101: public StaticContext getStaticContext() {
0102: if (staticContext == null) {
0103: staticContext = new ExpressionContext(this );
0104: }
0105: return staticContext;
0106: }
0107:
0108: public int getLineNumber() {
0109: return lineNumber;
0110: }
0111:
0112: public void setLineNumber(int lineNumber) {
0113: this .lineNumber = lineNumber;
0114: }
0115:
0116: /**
0117: * Determine whether saxon:explain has been set to "yes"
0118: */
0119:
0120: protected boolean isExplaining() {
0121: return explaining;
0122: }
0123:
0124: /**
0125: * Make this node a substitute for a temporary one previously added to the tree. See
0126: * StyleNodeFactory for details. "A node like the other one in all things but its class".
0127: * Note that at this stage, the node will not yet be known to its parent, though it will
0128: * contain a reference to its parent; and it will have no children.
0129: */
0130:
0131: public void substituteFor(StyleElement temp) {
0132: this .parent = temp.parent;
0133: this .attributeList = temp.attributeList;
0134: this .namespaceList = temp.namespaceList;
0135: this .nameCode = temp.nameCode;
0136: this .sequence = temp.sequence;
0137: this .extensionNamespaces = temp.extensionNamespaces;
0138: this .excludedNamespaces = temp.excludedNamespaces;
0139: this .version = temp.version;
0140: this .root = temp.root;
0141: this .staticContext = temp.staticContext;
0142: this .validationError = temp.validationError;
0143: this .reportingCircumstances = temp.reportingCircumstances;
0144: this .lineNumber = temp.lineNumber;
0145: }
0146:
0147: /**
0148: * Set a validation error
0149: */
0150:
0151: protected void setValidationError(TransformerException reason,
0152: int circumstances) {
0153: validationError = StaticError.makeStaticError(reason);
0154: reportingCircumstances = circumstances;
0155: }
0156:
0157: /**
0158: * Determine whether this node is an instruction. The default implementation says it isn't.
0159: */
0160:
0161: public boolean isInstruction() {
0162: return false;
0163: }
0164:
0165: /**
0166: * Determine the type of item returned by this instruction (only relevant if
0167: * it is an instruction). Default implementation returns Type.ITEM, indicating
0168: * that we don't know, it might be anything. Returns null in the case of an element
0169: * such as xsl:sort or xsl:variable that can appear in a sequence constructor but
0170: * contributes nothing to the result sequence.
0171: *
0172: * @return the item type returned
0173: */
0174:
0175: protected ItemType getReturnedItemType() {
0176: return AnyItemType.getInstance();
0177: }
0178:
0179: /**
0180: * Get the most general type of item returned by the children of this instruction
0181: *
0182: * @return the lowest common supertype of the item types returned by the children
0183: */
0184:
0185: protected ItemType getCommonChildItemType() {
0186: final TypeHierarchy th = getNamePool().getTypeHierarchy();
0187: ItemType t = NoNodeTest.getInstance();
0188: AxisIterator children = iterateAxis(Axis.CHILD);
0189: while (true) {
0190: NodeInfo next = (NodeInfo) children.next();
0191: if (next == null) {
0192: return t;
0193: }
0194: if (next instanceof StyleElement) {
0195: ItemType ret = ((StyleElement) next)
0196: .getReturnedItemType();
0197: if (ret != null) {
0198: t = Type.getCommonSuperType(t, ret, th);
0199: }
0200: } else {
0201: t = Type.getCommonSuperType(t, NodeKindTest.TEXT, th);
0202: }
0203: if (t == AnyItemType.getInstance()) {
0204: return t; // no point looking any further
0205: }
0206: }
0207: }
0208:
0209: /**
0210: * Mark tail-recursive calls on templates and functions.
0211: * For most instructions, this does nothing.
0212: */
0213:
0214: public void markTailCalls() {
0215: // no-op
0216: }
0217:
0218: /**
0219: * Determine whether this type of element is allowed to contain a sequence constructor
0220: */
0221:
0222: public boolean mayContainSequenceConstructor() {
0223: return false;
0224: }
0225:
0226: /**
0227: * Determine whether this type of element is allowed to contain an xsl:fallback
0228: * instruction
0229: */
0230:
0231: public boolean mayContainFallback() {
0232: return mayContainSequenceConstructor();
0233: }
0234:
0235: /**
0236: * Get the containing XSLStylesheet element
0237: */
0238:
0239: public XSLStylesheet getContainingStylesheet() {
0240: if (containingStylesheet == null) {
0241: if (this instanceof XSLStylesheet) {
0242: containingStylesheet = (XSLStylesheet) this ;
0243: } else {
0244: containingStylesheet = ((StyleElement) getParent())
0245: .getContainingStylesheet();
0246: }
0247: }
0248: return containingStylesheet;
0249: }
0250:
0251: /**
0252: * Get the import precedence of this stylesheet element.
0253: */
0254:
0255: public int getPrecedence() {
0256: return getContainingStylesheet().getPrecedence();
0257: }
0258:
0259: /**
0260: * Get the URI for a namespace prefix using the in-scope namespaces for
0261: * this element in the stylesheet
0262: *
0263: * @param prefix The namespace prefix: may be the empty string
0264: * @param useDefault True if the default namespace is to be used when the
0265: * prefix is "".
0266: * @return the namespace URI if the prefix is bound to a namespace; "" if the
0267: * prefix ("") is bound to no namespace; null if the prefix is not bound.
0268: */
0269:
0270: // public String getURIForPrefix(String prefix, boolean useDefault) {
0271: // if ("".equals(prefix) && !useDefault) {
0272: // return "";
0273: // } else {
0274: // try {
0275: // short uricode = getURICodeForPrefix(prefix);
0276: // return getNamePool().getURIFromURICode(uricode);
0277: // } catch (NamespaceException e) {
0278: // return null;
0279: // }
0280: // }
0281: // }
0282: /**
0283: * Make a NameCode, using this Element as the context for namespace resolution, and
0284: * registering the code in the namepool. If the name is unprefixed, the
0285: * default namespace is <b>not</b> used.
0286: *
0287: * @param qname The name as written, in the form "[prefix:]localname". The name must have
0288: * already been validated as a syntactically-correct QName.
0289: * @throws XPathException if the qname is not a lexically-valid QName, or if the name
0290: * is in a reserved namespace.
0291: * @throws NamespaceException if the prefix of the qname has not been declared
0292: */
0293:
0294: public final int makeNameCode(String qname) throws XPathException,
0295: NamespaceException {
0296:
0297: NamePool namePool = getTargetNamePool();
0298: String[] parts;
0299: try {
0300: parts = getConfiguration().getNameChecker().getQNameParts(
0301: qname);
0302: } catch (QNameException err) {
0303: StaticError e2 = new StaticError(err.getMessage());
0304: e2.setErrorCode("XTSE0020");
0305: throw e2;
0306: }
0307: String prefix = parts[0];
0308: if ("".equals(prefix)) {
0309: return namePool.allocate(prefix, (short) 0, qname);
0310:
0311: } else {
0312:
0313: String uri = getURIForPrefix(prefix, false);
0314: if (uri == null) {
0315: throw new NamespaceException(prefix);
0316: }
0317: if (NamespaceConstant.isReserved(uri)) {
0318: StaticError err = new StaticError("Namespace prefix "
0319: + prefix + " refers to a reserved namespace");
0320: err.setErrorCode("XTSE0080");
0321: throw err;
0322: }
0323: return namePool.allocate(prefix, uri, parts[1]);
0324: }
0325:
0326: }
0327:
0328: /**
0329: * Make a NamespaceContext object representing the list of in-scope namespaces. The NamePool
0330: * used for numeric codes in the NamespaceContext will be the target name pool.
0331: */
0332:
0333: public SavedNamespaceContext makeNamespaceContext() {
0334: return new SavedNamespaceContext(getInScopeNamespaceCodes(),
0335: getNamePool());
0336: }
0337:
0338: /**
0339: * Process the attributes of this element and all its children
0340: */
0341:
0342: public void processAllAttributes() throws XPathException {
0343: staticContext = new ExpressionContext(this );
0344: processAttributes();
0345: AxisIterator kids = iterateAxis(Axis.CHILD);
0346: while (true) {
0347: NodeInfo child = (NodeInfo) kids.next();
0348: if (child == null) {
0349: return;
0350: }
0351: if (child instanceof StyleElement) {
0352: ((StyleElement) child).processAllAttributes();
0353: if (((StyleElement) child).explaining) {
0354: // saxon:explain on any element in a template/function now causes an explanation at the
0355: // level of the template/function
0356: explaining = true;
0357: }
0358: }
0359: }
0360: }
0361:
0362: /**
0363: * Get an attribute value given the Clark name of the attribute (that is,
0364: * the name in {uri}local format).
0365: */
0366:
0367: public String getAttributeValue(String clarkName) {
0368: int fp = getNamePool().allocateClarkName(clarkName);
0369: return getAttributeValue(fp);
0370: }
0371:
0372: /**
0373: * Process the attribute list for the element. This is a wrapper method that calls
0374: * prepareAttributes (provided in the subclass) and traps any exceptions
0375: */
0376:
0377: public final void processAttributes() throws XPathException {
0378: try {
0379: prepareAttributes();
0380: } catch (XPathException err) {
0381: // if (forwardsCompatibleModeIsEnabled()) {
0382: // setValidationError(err, REPORT_IF_INSTANTIATED);
0383: // } else {
0384: compileError(err);
0385: // }
0386: }
0387: }
0388:
0389: /**
0390: * Check whether an unknown attribute is permitted.
0391: *
0392: * @param nc The name code of the attribute name
0393: */
0394:
0395: protected void checkUnknownAttribute(int nc) throws XPathException {
0396:
0397: String attributeURI = getNamePool().getURI(nc);
0398: String elementURI = getURI();
0399: String clarkName = getNamePool().getClarkName(nc);
0400:
0401: if (clarkName.equals(StandardNames.SAXON_EXPLAIN)) {
0402: explaining = "yes".equals(getAttributeValue(nc & 0xfffff));
0403: }
0404:
0405: if (forwardsCompatibleModeIsEnabled()) {
0406: // then unknown attributes are permitted and ignored
0407: return;
0408: }
0409:
0410: // allow xsl:extension-element-prefixes etc on an extension element
0411:
0412: if (isInstruction()
0413: && clarkName.startsWith('{' + NamespaceConstant.XSLT)
0414: && !(elementURI.equals(NamespaceConstant.XSLT))
0415: && (clarkName.endsWith("}default-collation")
0416: || clarkName
0417: .endsWith("}xpath-default-namespace")
0418: || clarkName
0419: .endsWith("}extension-element-prefixes")
0420: || clarkName
0421: .endsWith("}exclude-result-prefixes")
0422: || clarkName.endsWith("}version") || clarkName
0423: .endsWith("}use-when"))) {
0424: return;
0425: }
0426:
0427: // allow standard attributes on an XSLT element
0428:
0429: if (elementURI.equals(NamespaceConstant.XSLT)
0430: && (clarkName == StandardNames.DEFAULT_COLLATION
0431: || clarkName == StandardNames.XPATH_DEFAULT_NAMESPACE
0432: || clarkName == StandardNames.EXTENSION_ELEMENT_PREFIXES
0433: || clarkName == StandardNames.EXCLUDE_RESULT_PREFIXES
0434: || clarkName == StandardNames.VERSION || clarkName == StandardNames.USE_WHEN)) {
0435: return;
0436: }
0437:
0438: if ("".equals(attributeURI)
0439: || NamespaceConstant.XSLT.equals(attributeURI)) {
0440: compileError("Attribute "
0441: + Err.wrap(getNamePool().getDisplayName(nc),
0442: Err.ATTRIBUTE)
0443: + " is not allowed on element "
0444: + Err.wrap(getDisplayName(), Err.ELEMENT),
0445: "XTSE0010");
0446: }
0447: }
0448:
0449: /**
0450: * Set the attribute list for the element. This is called to process the attributes (note
0451: * the distinction from processAttributes in the superclass).
0452: * Must be supplied in a subclass
0453: */
0454:
0455: public abstract void prepareAttributes() throws XPathException;
0456:
0457: /**
0458: * Find the last child instruction of this instruction. Returns null if
0459: * there are no child instructions, or if the last child is a text node.
0460: */
0461:
0462: protected StyleElement getLastChildInstruction() {
0463: StyleElement last = null;
0464: AxisIterator kids = iterateAxis(Axis.CHILD);
0465: while (true) {
0466: NodeInfo child = (NodeInfo) kids.next();
0467: if (child == null) {
0468: return last;
0469: }
0470: if (child instanceof StyleElement) {
0471: last = (StyleElement) child;
0472: } else {
0473: last = null;
0474: }
0475: }
0476: }
0477:
0478: /**
0479: * Make an expression in the context of this stylesheet element
0480: */
0481:
0482: public Expression makeExpression(String expression)
0483: throws XPathException {
0484: try {
0485: Expression exp = ExpressionTool.make(expression,
0486: staticContext, 0, Token.EOF, getLineNumber());
0487: return exp;
0488: } catch (XPathException err) {
0489: err.setLocator(this );
0490: compileError(err);
0491: // if (!forwardsCompatibleModeIsEnabled()) {
0492: // compileError(err);
0493: // } else if (err.isTypeError()) {
0494: // compileError(err);
0495: // }
0496: ErrorExpression erexp = new ErrorExpression(err);
0497: erexp.setLocationId(allocateLocationId(getSystemId(),
0498: getLineNumber()));
0499: erexp.setParentExpression(this );
0500: return erexp;
0501: }
0502: }
0503:
0504: /**
0505: * Make a pattern in the context of this stylesheet element
0506: */
0507:
0508: public Pattern makePattern(String pattern) throws XPathException {
0509: try {
0510: return Pattern.make(pattern, staticContext,
0511: getPrincipalStylesheet().getExecutable());
0512: } catch (XPathException err) {
0513: // if (forwardsCompatibleModeIsEnabled()) {
0514: // compileWarning("Invalid pattern, ignored because in forwards-compatibility mode. " +
0515: // err.getMessage(), err.getErrorCodeLocalPart());
0516: // return new NodeTestPattern(NoNodeTest.getInstance());
0517: // } else {
0518: compileError(err);
0519: return new NodeTestPattern(AnyNodeTest.getInstance());
0520: // }
0521: }
0522: }
0523:
0524: /**
0525: * Make an attribute value template in the context of this stylesheet element
0526: */
0527:
0528: public Expression makeAttributeValueTemplate(String expression)
0529: throws XPathException {
0530: try {
0531: return AttributeValueTemplate.make(expression,
0532: getLineNumber(), staticContext);
0533: } catch (XPathException err) {
0534: compileError(err);
0535: return new StringValue(expression);
0536: }
0537: }
0538:
0539: /**
0540: * Process an attribute whose value is a SequenceType
0541: */
0542:
0543: public SequenceType makeSequenceType(String sequenceType)
0544: throws XPathException {
0545: getStaticContext();
0546: try {
0547: ExpressionParser parser = new ExpressionParser();
0548: return parser
0549: .parseSequenceType(sequenceType, staticContext);
0550: } catch (XPathException err) {
0551: compileError(err);
0552: // recovery path after reporting an error, e.g. undeclared namespace prefix
0553: return SequenceType.ANY_SEQUENCE;
0554: }
0555: }
0556:
0557: /**
0558: * Process the [xsl:]extension-element-prefixes attribute if there is one
0559: *
0560: * @param nc the Clark name of the attribute required
0561: */
0562:
0563: protected void processExtensionElementAttribute(String nc)
0564: throws XPathException {
0565: String ext = getAttributeValue(nc);
0566: if (ext != null) {
0567: // go round twice, once to count the values and next to add them to the array
0568: int count = 0;
0569: StringTokenizer st1 = new StringTokenizer(ext);
0570: while (st1.hasMoreTokens()) {
0571: st1.nextToken();
0572: count++;
0573: }
0574: extensionNamespaces = new short[count];
0575: count = 0;
0576: StringTokenizer st2 = new StringTokenizer(ext);
0577: while (st2.hasMoreTokens()) {
0578: String s = st2.nextToken();
0579: if ("#default".equals(s)) {
0580: s = "";
0581: }
0582: try {
0583: short uriCode = getURICodeForPrefix(s);
0584: extensionNamespaces[count++] = uriCode;
0585: } catch (NamespaceException err) {
0586: extensionNamespaces = null;
0587: compileError(err.getMessage(), "XT0280");
0588: }
0589: }
0590: }
0591: }
0592:
0593: /**
0594: * Process the [xsl:]exclude-result-prefixes attribute if there is one
0595: *
0596: * @param nc the Clark name of the attribute required
0597: */
0598:
0599: protected void processExcludedNamespaces(String nc)
0600: throws XPathException {
0601: String ext = getAttributeValue(nc);
0602: if (ext != null) {
0603: if ("#all".equals(ext.trim())) {
0604: int[] codes = getInScopeNamespaceCodes();
0605: excludedNamespaces = new short[codes.length];
0606: for (int i = 0; i < codes.length; i++) {
0607: excludedNamespaces[i] = (short) (codes[i] & 0xffff);
0608: }
0609: } else {
0610: // go round twice, once to count the values and next to add them to the array
0611: int count = 0;
0612: StringTokenizer st1 = new StringTokenizer(ext);
0613: while (st1.hasMoreTokens()) {
0614: st1.nextToken();
0615: count++;
0616: }
0617: excludedNamespaces = new short[count];
0618: count = 0;
0619: StringTokenizer st2 = new StringTokenizer(ext);
0620: while (st2.hasMoreTokens()) {
0621: String s = st2.nextToken();
0622: if ("#default".equals(s)) {
0623: s = "";
0624: } else if ("#all".equals(s)) {
0625: compileError(
0626: "In exclude-result-prefixes, cannot mix #all with other values",
0627: "XTSE0020");
0628: }
0629: try {
0630: short uriCode = getURICodeForPrefix(s);
0631: excludedNamespaces[count++] = uriCode;
0632: } catch (NamespaceException err) {
0633: excludedNamespaces = null;
0634: compileError(err.getMessage(), "XTSE0280");
0635: }
0636: }
0637: }
0638: }
0639: }
0640:
0641: /**
0642: * Process the [xsl:]version attribute if there is one
0643: *
0644: * @param nc the Clark name of the attribute required
0645: */
0646:
0647: protected void processVersionAttribute(String nc)
0648: throws XPathException {
0649: String v = getAttributeValue(nc);
0650: if (v != null) {
0651: AtomicValue val = DecimalValue.makeDecimalValue(v, true);
0652: if (val instanceof ValidationErrorValue) {
0653: compileError("The version attribute must be a decimal literal");
0654: }
0655: version = ((DecimalValue) val).getValue();
0656: }
0657: }
0658:
0659: /**
0660: * Get the numeric value of the version number on this element,
0661: * or inherited from its ancestors
0662: */
0663:
0664: public BigDecimal getVersion() {
0665: if (version == null) {
0666: NodeInfo node = getParent();
0667: if (node instanceof StyleElement) {
0668: version = ((StyleElement) node).getVersion();
0669: } else {
0670: version = new BigDecimal("2.0"); // defensive programming
0671: }
0672: }
0673: return version;
0674: }
0675:
0676: /**
0677: * Determine whether forwards-compatible mode is enabled for this element
0678: */
0679:
0680: public boolean forwardsCompatibleModeIsEnabled() {
0681: return getVersion().compareTo(BigDecimal.valueOf(2)) > 0;
0682: }
0683:
0684: /**
0685: * Determine whether backwards-compatible mode is enabled for this element
0686: */
0687:
0688: public boolean backwardsCompatibleModeIsEnabled() {
0689: return getVersion().compareTo(BigDecimal.valueOf(2)) < 0;
0690: }
0691:
0692: /**
0693: * Process the [xsl:]default-xpath-namespace attribute if there is one
0694: *
0695: * @param nc the Clark name of the attribute required
0696: */
0697:
0698: protected void processDefaultCollationAttribute(String nc)
0699: throws XPathException {
0700: String v = getAttributeValue(nc);
0701: if (v != null) {
0702: StringTokenizer st = new StringTokenizer(v);
0703: while (st.hasMoreTokens()) {
0704: String uri = st.nextToken();
0705: if (uri
0706: .equals(NamespaceConstant.CODEPOINT_COLLATION_URI)) {
0707: defaultCollationName = uri;
0708: return;
0709: } else if (uri.startsWith("http://saxon.sf.net/")) {
0710: defaultCollationName = uri;
0711: return;
0712: } else {
0713: URI collationURI;
0714: try {
0715: collationURI = new URI(uri);
0716: if (!collationURI.isAbsolute()) {
0717: URI base = new URI(getBaseURI());
0718: collationURI = base.resolve(collationURI);
0719: uri = collationURI.toString();
0720: }
0721: } catch (URISyntaxException err) {
0722: compileError("default collation '" + uri
0723: + "' is not a valid URI");
0724: uri = NamespaceConstant.CODEPOINT_COLLATION_URI;
0725: }
0726:
0727: if (uri.startsWith("http://saxon.sf.net/")) {
0728: defaultCollationName = uri;
0729: return;
0730: }
0731:
0732: if (getPrincipalStylesheet().getExecutable()
0733: .getNamedCollation(uri) != null) {
0734: defaultCollationName = uri;
0735: return;
0736: }
0737: }
0738: // if not recognized, try the next URI in order
0739: }
0740: compileError(
0741: "No recognized collation URI found in default-collation attribute",
0742: "XTSE0125");
0743: }
0744: }
0745:
0746: /**
0747: * Get the default collation for this element
0748: */
0749:
0750: protected String getDefaultCollationName() {
0751: StyleElement e = this ;
0752: while (true) {
0753: if (e.defaultCollationName != null) {
0754: return e.defaultCollationName;
0755: }
0756: NodeInfo p = e.getParent();
0757: if (!(p instanceof StyleElement)) {
0758: break;
0759: }
0760: e = (StyleElement) p;
0761: }
0762: return getPrincipalStylesheet().getDefaultCollationName();
0763: }
0764:
0765: /**
0766: * Check whether a particular extension element namespace is defined on this node.
0767: * This checks this node only, not the ancestor nodes.
0768: * The implementation checks whether the prefix is included in the
0769: * [xsl:]extension-element-prefixes attribute.
0770: *
0771: * @param uriCode the namespace URI code being tested
0772: */
0773:
0774: protected boolean definesExtensionElement(short uriCode) {
0775: if (extensionNamespaces == null) {
0776: return false;
0777: }
0778: for (int i = 0; i < extensionNamespaces.length; i++) {
0779: if (extensionNamespaces[i] == uriCode) {
0780: return true;
0781: }
0782: }
0783: return false;
0784: }
0785:
0786: /**
0787: * Check whether a namespace uri defines an extension element. This checks whether the
0788: * namespace is defined as an extension namespace on this or any ancestor node.
0789: *
0790: * @param uriCode the namespace URI code being tested
0791: */
0792:
0793: public boolean isExtensionNamespace(short uriCode) {
0794: NodeInfo anc = this ;
0795: while (anc instanceof StyleElement) {
0796: if (((StyleElement) anc).definesExtensionElement(uriCode)) {
0797: return true;
0798: }
0799: anc = anc.getParent();
0800: }
0801: return false;
0802: }
0803:
0804: /**
0805: * Check whether this node excludes a particular namespace from the result.
0806: * This method checks this node only, not the ancestor nodes.
0807: *
0808: * @param uriCode the code of the namespace URI being tested
0809: */
0810:
0811: protected boolean definesExcludedNamespace(short uriCode) {
0812: if (excludedNamespaces == null) {
0813: return false;
0814: }
0815: for (int i = 0; i < excludedNamespaces.length; i++) {
0816: if (excludedNamespaces[i] == uriCode) {
0817: return true;
0818: }
0819: }
0820: return false;
0821: }
0822:
0823: /**
0824: * Check whether a namespace uri defines an namespace excluded from the result.
0825: * This checks whether the namespace is defined as an excluded namespace on this
0826: * or any ancestor node.
0827: *
0828: * @param uriCode the code of the namespace URI being tested
0829: */
0830:
0831: public boolean isExcludedNamespace(short uriCode) {
0832: if (uriCode == NamespaceConstant.XSLT_CODE) {
0833: return true;
0834: }
0835: if (isExtensionNamespace(uriCode)) {
0836: return true;
0837: }
0838: NodeInfo anc = this ;
0839: while (anc instanceof StyleElement) {
0840: if (((StyleElement) anc).definesExcludedNamespace(uriCode)) {
0841: return true;
0842: }
0843: anc = anc.getParent();
0844: }
0845: return false;
0846: }
0847:
0848: /**
0849: * Process the [xsl:]default-xpath-namespace attribute if there is one
0850: *
0851: * @param nc the Clark name of the attribute required
0852: */
0853:
0854: protected void processDefaultXPathNamespaceAttribute(String nc) {
0855: String v = getAttributeValue(nc);
0856: if (v != null) {
0857: defaultXPathNamespace = v;
0858: }
0859: }
0860:
0861: /**
0862: * Get the default XPath namespace code applicable to this element
0863: */
0864:
0865: protected short getDefaultXPathNamespace() {
0866: NodeInfo anc = this ;
0867: while (anc instanceof StyleElement) {
0868: String x = ((StyleElement) anc).defaultXPathNamespace;
0869: if (x != null) {
0870: return getTargetNamePool().allocateCodeForURI(x);
0871: }
0872: anc = anc.getParent();
0873: }
0874: return NamespaceConstant.NULL_CODE;
0875: // indicates that the default namespace is the null namespace
0876: }
0877:
0878: /**
0879: * Get the Schema type definition for a type named in the stylesheet (in a
0880: * "type" attribute).
0881: *
0882: * @throws XPathException if the type is not declared in an
0883: * imported schema, or is not a built-in type
0884: */
0885:
0886: public SchemaType getSchemaType(String typeAtt)
0887: throws XPathException {
0888: try {
0889: String[] parts = getConfiguration().getNameChecker()
0890: .getQNameParts(typeAtt);
0891: String lname = parts[1];
0892: String uri;
0893: if ("".equals(parts[0])) {
0894: // Name is unprefixed: use the default-xpath-namespace
0895: short uricode = getDefaultXPathNamespace();
0896: uri = getTargetNamePool().getURIFromURICode(uricode);
0897: nameCode = getTargetNamePool().allocate(parts[0],
0898: uricode, lname);
0899: } else {
0900: uri = getURIForPrefix(parts[0], false);
0901: if (uri == null) {
0902: compileError(
0903: "Namespace prefix for type annotation is undeclared",
0904: "XTSE0280");
0905: return null;
0906: }
0907: }
0908: int nameCode = getTargetNamePool().allocate(parts[0], uri,
0909: lname);
0910: if (uri.equals(NamespaceConstant.SCHEMA)) {
0911: SchemaType t = BuiltInSchemaFactory
0912: .getSchemaType(StandardNames.getFingerprint(
0913: uri, lname));
0914: if (t == null) {
0915: compileError("Unknown built-in type " + typeAtt);
0916: return null;
0917: }
0918: return t;
0919: } else if (NamespaceConstant.isXDTNamespace(uri)) {
0920: ItemType t = Type.getBuiltInItemType(
0921: NamespaceConstant.XDT, lname);
0922: if (t == null) {
0923: if ("untyped".equals(lname)) {
0924: compileError("Cannot validate a node as 'untyped'");
0925: } else {
0926: compileError("Unknown built-in type " + typeAtt);
0927: }
0928: }
0929: return (BuiltInAtomicType) t;
0930: }
0931:
0932: // not a built-in type: look in the imported schemas
0933:
0934: if (!getPrincipalStylesheet().isImportedSchema(uri)) {
0935: compileError("There is no imported schema for the namespace of type "
0936: + typeAtt);
0937: return null;
0938: }
0939: SchemaType stype = getConfiguration().getSchemaType(
0940: nameCode & 0xfffff);
0941: if (stype == null) {
0942: compileError("There is no type named " + typeAtt
0943: + " in an imported schema");
0944: }
0945: return stype;
0946:
0947: } catch (QNameException err) {
0948: compileError("Invalid type name. " + err.getMessage());
0949: }
0950: return null;
0951: }
0952:
0953: /**
0954: * Get the type annotation to use for a given schema type
0955: */
0956:
0957: public int getTypeAnnotation(SchemaType schemaType) {
0958: if (schemaType != null) {
0959: return schemaType.getFingerprint();
0960: } else {
0961: return -1;
0962: }
0963: }
0964:
0965: /**
0966: * Check that the stylesheet element is valid. This is called once for each element, after
0967: * the entire tree has been built. As well as validation, it can perform first-time
0968: * initialisation. The default implementation does nothing; it is normally overriden
0969: * in subclasses.
0970: */
0971:
0972: public void validate() throws XPathException {
0973: }
0974:
0975: /**
0976: * Hook to allow additional validation of a parent element immediately after its
0977: * children have been validated.
0978: */
0979:
0980: public void postValidate() throws XPathException {
0981: }
0982:
0983: /**
0984: * Type-check an expression. This is called to check each expression while the containing
0985: * instruction is being validated. It is not just a static type-check, it also adds code
0986: * to perform any necessary run-time type checking and/or conversion.
0987: */
0988:
0989: // Note: the typeCheck() call is done at the level of individual path expression; the optimize() call is done
0990: // for a template or function as a whole. We can't do it all at the function/template level because
0991: // the static context (e.g. namespaces) changes from one XPath expression to another.
0992: public Expression typeCheck(String name, Expression exp)
0993: throws XPathException {
0994:
0995: if (exp == null) {
0996: return null;
0997: }
0998:
0999: //ExpressionTool.makeParentReferences(exp);
1000: if (exp instanceof ComputedExpression) {
1001: ((ComputedExpression) exp).setParentExpression(this );
1002: // temporary, until the instruction is compiled
1003: }
1004:
1005: try {
1006: exp = exp.typeCheck(staticContext, Type.ITEM_TYPE);
1007: exp = ExpressionTool.resolveCallsToCurrentFunction(exp,
1008: getConfiguration());
1009: // if (explaining) {
1010: // System.err.println("Attribute '" + name + "' of element '" + getDisplayName() + "' at line " + getLineNumber() + ':');
1011: // System.err.println("Static type: " +
1012: // SequenceType.makeSequenceType(exp.getItemType(), exp.getCardinality()));
1013: // System.err.println("Optimized expression tree:");
1014: // exp.display(10, getNamePool(), System.err);
1015: // }
1016: if (getConfiguration().getTraceListener() != null) {
1017: InstructionDetails details = new InstructionDetails();
1018: details.setConstructType(Location.XPATH_IN_XSLT);
1019: details.setLineNumber(getLineNumber());
1020: details.setSystemId(getSystemId());
1021: details.setProperty("attribute-name", name);
1022: TraceWrapper trace = new TraceInstruction(exp, details);
1023: trace.setLocationId(allocateLocationId(getSystemId(),
1024: getLineNumber()));
1025: trace.setParentExpression(this );
1026: exp = trace;
1027: }
1028: return exp;
1029: } catch (DynamicError err) {
1030: // we can't report a dynamic error such as divide by zero unless the expression
1031: // is actually executed.
1032: if (err.isTypeError()) {
1033: compileError(err);
1034: return exp;
1035: } else {
1036: ErrorExpression erexp = new ErrorExpression(err);
1037: erexp.setLocationId(allocateLocationId(getSystemId(),
1038: getLineNumber()));
1039: return erexp;
1040: }
1041: } catch (XPathException err) {
1042: compileError(err);
1043: ErrorExpression erexp = new ErrorExpression(err);
1044: erexp.setLocationId(allocateLocationId(getSystemId(),
1045: getLineNumber()));
1046: return erexp;
1047: }
1048: }
1049:
1050: /**
1051: * Allocate slots in the local stack frame to range variables used in an XPath expression
1052: *
1053: * @param exp the XPath expression for which slots are to be allocated
1054: */
1055:
1056: public void allocateSlots(Expression exp) {
1057: SlotManager slotManager = getContainingSlotManager();
1058: if (slotManager == null) {
1059: throw new AssertionError(
1060: "Slot manager has not been allocated");
1061: // previous code: ExpressionTool.allocateSlots(exp, 0, null);
1062: } else {
1063: int firstSlot = slotManager.getNumberOfVariables();
1064: int highWater = ExpressionTool.allocateSlots(exp,
1065: firstSlot, slotManager);
1066: if (highWater > firstSlot) {
1067: slotManager.setNumberOfVariables(highWater);
1068: // This algorithm is not very efficient because it never reuses
1069: // a slot when a variable goes out of scope. But at least it is safe.
1070: // Note that range variables within XPath expressions need to maintain
1071: // a slot until the instruction they are part of finishes, e.g. in
1072: // xsl:for-each.
1073: }
1074: }
1075: }
1076:
1077: /**
1078: * Type-check a pattern. This is called to check each pattern while the containing
1079: * instruction is being validated. It is not just a static type-check, it also adds code
1080: * to perform any necessary run-time type checking and/or conversion.
1081: */
1082:
1083: public Pattern typeCheck(String name, Pattern pattern)
1084: throws XPathException {
1085: if (pattern == null) {
1086: return null;
1087: }
1088: try {
1089: pattern = pattern.analyze(staticContext, Type.NODE_TYPE);
1090: boolean usesCurrent = false;
1091: int current = getNamePool().allocate("",
1092: NamespaceConstant.FN, "current")
1093: & NamePool.FP_MASK;
1094: if (pattern instanceof LocationPathPattern) {
1095: Iterator sub = pattern.iterateSubExpressions();
1096: while (sub.hasNext()) {
1097: Expression filter = (Expression) sub.next();
1098: if (ExpressionTool.callsFunction(filter, current)) {
1099: usesCurrent = true;
1100: break;
1101: }
1102: }
1103: if (usesCurrent) {
1104: Configuration config = getConfiguration();
1105: RangeVariableDeclaration decl = new RangeVariableDeclaration();
1106: decl.setNameCode(config.getNamePool().allocate(
1107: "saxon", NamespaceConstant.SAXON,
1108: "current" + hashCode()));
1109: decl.setVariableName("saxon:current");
1110: decl.setRequiredType(SequenceType.SINGLE_ITEM);
1111: LetExpression let = new LetExpression();
1112: let.setSequence(new ContextItemExpression());
1113: let.setVariableDeclaration(decl);
1114: let.setAction(EmptySequence.getInstance());
1115: PromotionOffer offer = new PromotionOffer(config
1116: .getOptimizer());
1117: offer.action = PromotionOffer.REPLACE_CURRENT;
1118: offer.containingExpression = let;
1119: ((LocationPathPattern) pattern).resolveCurrent(let,
1120: offer);
1121: allocateSlots(let);
1122: decl.fixupReferences(let);
1123: }
1124: }
1125: return pattern;
1126: } catch (DynamicError err) {
1127: // we can't report a dynamic error such as divide by zero unless the pattern
1128: // is actually executed. We don't have an error pattern available, so we
1129: // construct one
1130: LocationPathPattern errpat = new LocationPathPattern();
1131: errpat.addFilter(new ErrorExpression(err));
1132: return errpat;
1133: } catch (XPathException err) {
1134: StaticError e2 = new StaticError("Error in " + name
1135: + " pattern", err);
1136: e2.setLocator(err.getLocator());
1137: e2.setErrorCode(err.getErrorCodeLocalPart());
1138: throw e2;
1139: }
1140: }
1141:
1142: /**
1143: * Fix up references from XPath expressions. Overridden for function declarations
1144: * and variable declarations
1145: */
1146:
1147: public void fixupReferences() throws XPathException {
1148: AxisIterator kids = iterateAxis(Axis.CHILD);
1149: while (true) {
1150: NodeInfo child = (NodeInfo) kids.next();
1151: if (child == null) {
1152: return;
1153: }
1154: if (child instanceof StyleElement) {
1155: ((StyleElement) child).fixupReferences();
1156: }
1157: }
1158: }
1159:
1160: /**
1161: * Get the SlotManager for the containing Procedure definition
1162: *
1163: * @return the SlotManager associated with the containing Function, Template, etc,
1164: * or null if there is no such containing Function, Template etc.
1165: */
1166:
1167: public SlotManager getContainingSlotManager() {
1168: NodeInfo node = this ;
1169: while (true) {
1170: NodeInfo next = node.getParent();
1171: if (next instanceof XSLStylesheet) {
1172: if (node instanceof StylesheetProcedure) {
1173: return ((StylesheetProcedure) node)
1174: .getSlotManager();
1175: } else {
1176: return null;
1177: }
1178: }
1179: node = next;
1180: }
1181: }
1182:
1183: /**
1184: * Recursive walk through the stylesheet to validate all nodes
1185: */
1186:
1187: public void validateSubtree() throws XPathException {
1188: if (validationError != null) {
1189: if (reportingCircumstances == REPORT_ALWAYS) {
1190: compileError(validationError);
1191: } else if (reportingCircumstances == REPORT_UNLESS_FORWARDS_COMPATIBLE
1192: && !forwardsCompatibleModeIsEnabled()) {
1193: compileError(validationError);
1194: } else if (reportingCircumstances == REPORT_UNLESS_FALLBACK_AVAILABLE) {
1195: boolean hasFallback = false;
1196: AxisIterator kids = iterateAxis(Axis.CHILD);
1197: while (true) {
1198: NodeInfo child = (NodeInfo) kids.next();
1199: if (child == null) {
1200: break;
1201: }
1202: if (child instanceof XSLFallback) {
1203: hasFallback = true;
1204: }
1205: }
1206: if (!hasFallback) {
1207: compileError(validationError);
1208: }
1209: }
1210: }
1211: try {
1212: validate();
1213: } catch (XPathException err) {
1214: // if (forwardsCompatibleModeIsEnabled()) {
1215: // setValidationError(err, REPORT_IF_INSTANTIATED);
1216: // } else {
1217: compileError(err);
1218: // }
1219: }
1220:
1221: validateChildren();
1222: postValidate();
1223: }
1224:
1225: /**
1226: * Validate the children of this node, recursively. Overridden for top-level
1227: * data elements.
1228: */
1229:
1230: protected void validateChildren() throws XPathException {
1231: boolean containsInstructions = mayContainSequenceConstructor();
1232: AxisIterator kids = iterateAxis(Axis.CHILD);
1233: StyleElement lastChild = null;
1234: while (true) {
1235: NodeInfo child = (NodeInfo) kids.next();
1236: if (child == null) {
1237: break;
1238: }
1239: if (child instanceof StyleElement) {
1240: if (containsInstructions
1241: && !((StyleElement) child).isInstruction()
1242: && !isPermittedChild((StyleElement) child)) {
1243: ((StyleElement) child).compileError("An "
1244: + getDisplayName()
1245: + " element must not contain an "
1246: + child.getDisplayName() + " element",
1247: "XTSE0010");
1248: }
1249: ((StyleElement) child).validateSubtree();
1250: lastChild = (StyleElement) child;
1251: }
1252: }
1253: if (lastChild instanceof XSLVariable
1254: && !(this instanceof XSLStylesheet)) {
1255: lastChild
1256: .compileWarning(
1257: "A variable with no following sibling instructions has no effect",
1258: SaxonErrorCode.SXWN9001);
1259: }
1260: }
1261:
1262: /**
1263: * Specify that certain children are permitted for this element
1264: */
1265:
1266: protected boolean isPermittedChild(StyleElement child) {
1267: return false;
1268: }
1269:
1270: /**
1271: * Get the principal XSLStylesheet node. This gets the principal style sheet, i.e. the
1272: * one originally loaded, that forms the root of the import/include tree
1273: */
1274:
1275: protected XSLStylesheet getPrincipalStylesheet() {
1276: XSLStylesheet sheet = getContainingStylesheet();
1277: while (true) {
1278: XSLStylesheet next = sheet.getImporter();
1279: if (next == null) {
1280: return sheet;
1281: }
1282: sheet = next;
1283: }
1284: }
1285:
1286: /**
1287: * Get the PreparedStylesheet object.
1288: *
1289: * @return the PreparedStylesheet to which this stylesheet element belongs
1290: */
1291:
1292: public PreparedStylesheet getPreparedStylesheet() {
1293: return getPrincipalStylesheet().getPreparedStylesheet();
1294: }
1295:
1296: /**
1297: * Check that the stylesheet element is within a sequence constructor
1298: *
1299: * @throws XPathException if not within a sequence constructor
1300: */
1301:
1302: public void checkWithinTemplate() throws XPathException {
1303: // Parent elements now check their children, not the other way around
1304: // StyleElement parent = (StyleElement)getParent();
1305: // if (!parent.mayContainSequenceConstructor()) {
1306: // compileError("Element must be used only within a sequence constructor", "XT0010");
1307: // }
1308: }
1309:
1310: /**
1311: * Check that among the children of this element, any xsl:sort elements precede any other elements
1312: *
1313: * @param sortRequired true if there must be at least one xsl:sort element
1314: * @throws XPathException if invalid
1315: */
1316:
1317: protected void checkSortComesFirst(boolean sortRequired)
1318: throws XPathException {
1319: AxisIterator kids = iterateAxis(Axis.CHILD);
1320: boolean sortFound = false;
1321: boolean nonSortFound = false;
1322: while (true) {
1323: NodeInfo child = (NodeInfo) kids.next();
1324: if (child == null) {
1325: break;
1326: }
1327: if (child instanceof XSLSort) {
1328: if (nonSortFound) {
1329: ((XSLSort) child)
1330: .compileError(
1331: "Within "
1332: + getDisplayName()
1333: + ", xsl:sort elements must come before other instructions",
1334: "XTSE0010");
1335: }
1336: sortFound = true;
1337: } else if (child.getNodeKind() == Type.TEXT) {
1338: // with xml:space=preserve, white space nodes may still be there
1339: if (!Whitespace.isWhite(child.getStringValueCS())) {
1340: nonSortFound = true;
1341: }
1342: } else {
1343: nonSortFound = true;
1344: }
1345: }
1346: if (sortRequired && !sortFound) {
1347: compileError(getDisplayName()
1348: + " must have at least one xsl:sort child",
1349: "XTSE0010");
1350: }
1351: }
1352:
1353: /**
1354: * Convenience method to check that the stylesheet element is at the top level
1355: *
1356: * @throws XPathException if not at top level
1357: */
1358:
1359: public void checkTopLevel(String errorCode) throws XPathException {
1360: if (errorCode == null) {
1361: errorCode = "XTSE0010";
1362: }
1363: if (!(getParent() instanceof XSLStylesheet)) {
1364: compileError(
1365: "Element must be used only at top level of stylesheet",
1366: errorCode);
1367: }
1368: }
1369:
1370: /**
1371: * Convenience method to check that the stylesheet element is empty
1372: *
1373: * @throws XPathException if it is not empty
1374: */
1375:
1376: public void checkEmpty() throws XPathException {
1377: if (hasChildNodes()) {
1378: compileError("Element must be empty", "XTSE0260");
1379: }
1380: }
1381:
1382: /**
1383: * Convenience method to report the absence of a mandatory attribute
1384: *
1385: * @throws XPathException if the attribute is missing
1386: */
1387:
1388: public void reportAbsence(String attribute) throws XPathException {
1389: compileError("Element must have a \"" + attribute
1390: + "\" attribute", "XTSE0010");
1391: }
1392:
1393: /**
1394: * Compile the instruction on the stylesheet tree into an executable instruction
1395: * for use at run-time.
1396: *
1397: * @return either a ComputedExpression, or null. The value null is returned when compiling an instruction
1398: * that returns a no-op, or when compiling a top-level object such as an xsl:template that compiles
1399: * into something other than an instruction.
1400: */
1401:
1402: public abstract Expression compile(Executable exec)
1403: throws XPathException;
1404:
1405: /**
1406: * Compile the children of this instruction on the stylesheet tree, adding the
1407: * subordinate instructions to the parent instruction on the execution tree.
1408: *
1409: * @return the array of children
1410: */
1411:
1412: // public Expression compileSequenceConstructor(Executable exec, AxisIterator iter, boolean includeParams)
1413: // throws XPathException {
1414: // // TODO: the use of recursion in this method imposes a limit on the number of sibling instructions,
1415: // // which can prove a problem with software-generated stylesheets.
1416: // int lineNumber = getLineNumber();
1417: // NodeInfo node = (NodeInfo)iter.next();
1418: // if (node == null) {
1419: // return null;
1420: // }
1421: // if (node instanceof StyleElement) {
1422: // lineNumber = node.getLineNumber(); // this is to get a line number for the next text node
1423: // }
1424: // if (node.getNodeKind() == Type.TEXT) {
1425: // // handle literal text nodes by generating an xsl:value-of instruction
1426: // ValueOf text = new ValueOf(StringValue.makeStringValue(node.getStringValueCS()), false, false);
1427: // text.setLocationId(allocateLocationId(getSystemId(), lineNumber));
1428: // Expression tail = compileSequenceConstructor(exec, iter, includeParams);
1429: // if (tail == null) {
1430: // return text;
1431: // } else {
1432: // ComputedExpression e = (ComputedExpression)Block.makeBlock(text, tail);
1433: // e.setLocationId(allocateLocationId(getSystemId(), getLineNumber()));
1434: // return e;
1435: // }
1436: //
1437: // } else if (node instanceof XSLVariable) {
1438: // Expression var = ((XSLVariable)node).compileLocalVariable(exec);
1439: // if (var == null) {
1440: // // this can happen if the variable declaration is redundant
1441: // return compileSequenceConstructor(exec, iter, includeParams);
1442: // } else {
1443: // LocalVariable lv = (LocalVariable)var;
1444: // Expression tail = compileSequenceConstructor(exec, iter, includeParams);
1445: // if (tail == null) {
1446: // // this doesn't happen, because if there are no instructions following
1447: // // a variable, we'll have taken the var==null path above
1448: // return null;
1449: // } else {
1450: // LetExpression let = new LetExpression();
1451: // RangeVariableDeclaration rvar = new RangeVariableDeclaration();
1452: // rvar.setRequiredType(lv.getRequiredType());
1453: // rvar.setNameCode(lv.getNameCode());
1454: // rvar.setVariableName(lv.getVariableName());
1455: // rvar.setReferenceList(((XSLVariable)node).getReferenceList());
1456: // let.setVariableDeclaration(rvar);
1457: // let.setSequence(lv.getSelectExpression());
1458: // //let.setSlotNumber(lv.getSlotNumber());
1459: // let.setAction(tail);
1460: // ((XSLVariable)node).fixupBinding(let);
1461: // let.setLocationId(allocateLocationId(node.getSystemId(), node.getLineNumber()));
1462: // if (getConfiguration().getTraceListener() != null) {
1463: // TraceExpression t = new TraceExpression(let);
1464: // t.setConstructType(Location.LET_EXPRESSION);
1465: // t.setObjectNameCode(lv.getNameCode());
1466: // t.setSystemId(node.getSystemId());
1467: // t.setLineNumber(node.getLineNumber());
1468: // return t;
1469: // }
1470: // return let;
1471: // }
1472: // }
1473: //
1474: //
1475: // } else if (node instanceof StyleElement) {
1476: // StyleElement snode = (StyleElement)node;
1477: // Expression child;
1478: // if (snode.validationError != null) {
1479: // child = fallbackProcessing(exec, snode);
1480: //
1481: // } else {
1482: // child = snode.compile(exec);
1483: // if (child instanceof ComputedExpression) {
1484: // ComputedExpression childi = (ComputedExpression)child;
1485: // childi.setLocationId(allocateLocationId(getSystemId(), snode.getLineNumber()));
1486: // }
1487: // if (child != null) {
1488: // if (includeParams || !(node instanceof XSLParam)) {
1489: // if (getConfiguration().getTraceListener() != null) {
1490: // TraceWrapper trace = makeTraceInstruction(snode, child);
1491: // child = trace;
1492: // }
1493: // }
1494: // }
1495: // }
1496: // Expression tail = compileSequenceConstructor(exec, iter, includeParams);
1497: // if (tail == null) {
1498: // return child;
1499: // } else if (child == null) {
1500: // return tail;
1501: // } else {
1502: // ComputedExpression e = (ComputedExpression)Block.makeBlock(child, tail);
1503: // e.setLocationId(allocateLocationId(getSystemId(), getLineNumber()));
1504: // return e;
1505: // }
1506: // }
1507: // return null;
1508: // }
1509: /**
1510: * Compile the children of this instruction on the stylesheet tree, adding the
1511: * subordinate instructions to the parent instruction on the execution tree.
1512: *
1513: * @return the array of children
1514: */
1515:
1516: public Expression compileSequenceConstructor(Executable exec,
1517: AxisIterator iter, boolean includeParams)
1518: throws XPathException {
1519:
1520: Expression result = EmptySequence.getInstance();
1521: int locationId = allocateLocationId(getSystemId(),
1522: getLineNumber());
1523: while (true) {
1524: int lineNumber = getLineNumber();
1525: NodeInfo node = (NodeInfo) iter.next();
1526: if (node == null) {
1527: return result;
1528: }
1529: if (node instanceof StyleElement) {
1530: lineNumber = node.getLineNumber(); // this is to get a line number for the next text node
1531: }
1532: if (node.getNodeKind() == Type.TEXT) {
1533: // handle literal text nodes by generating an xsl:value-of instruction
1534: ValueOf text = new ValueOf(StringValue
1535: .makeStringValue(node.getStringValueCS()),
1536: false, false);
1537: text.setLocationId(allocateLocationId(getSystemId(),
1538: lineNumber));
1539: result = Block.makeBlock(result, text);
1540: if (result instanceof ComputedExpression) {
1541: ((ComputedExpression) result)
1542: .setLocationId(locationId);
1543: }
1544: continue;
1545:
1546: } else if (node instanceof XSLVariable) {
1547: Expression var = ((XSLVariable) node)
1548: .compileLocalVariable(exec);
1549: if (var == null || var instanceof EmptySequence) {
1550: // this can happen if the variable declaration is redundant
1551: continue;
1552: } else {
1553: LocalVariable lv = (LocalVariable) var;
1554: Expression tail = compileSequenceConstructor(exec,
1555: iter, includeParams);
1556: if (tail == null || tail instanceof EmptySequence) {
1557: // this doesn't happen, because if there are no instructions following
1558: // a variable, we'll have taken the var==null path above
1559: return result;
1560: } else {
1561: LetExpression let = new LetExpression();
1562: RangeVariableDeclaration rvar = new RangeVariableDeclaration();
1563: rvar.setRequiredType(lv.getRequiredType());
1564: rvar.setNameCode(lv.getNameCode());
1565: rvar.setVariableName(lv.getVariableName());
1566: rvar.setReferenceList(((XSLVariable) node)
1567: .getReferenceList());
1568: let.setVariableDeclaration(rvar);
1569: let.setSequence(lv.getSelectExpression());
1570: //let.setSlotNumber(lv.getSlotNumber());
1571: let.setAction(tail);
1572: ((XSLVariable) node).fixupBinding(let);
1573: let.setLocationId(allocateLocationId(node
1574: .getSystemId(), node.getLineNumber()));
1575: if (getConfiguration().getTraceListener() != null) {
1576: TraceExpression t = new TraceExpression(let);
1577: t.setConstructType(Location.LET_EXPRESSION);
1578: t.setObjectNameCode(lv.getNameCode());
1579: t.setSystemId(node.getSystemId());
1580: t.setLineNumber(node.getLineNumber());
1581: result = Block.makeBlock(result, t);
1582: } else {
1583: result = Block.makeBlock(result, let);
1584: }
1585: if (result instanceof ComputedExpression) {
1586: ((ComputedExpression) result)
1587: .setLocationId(locationId);
1588: }
1589: return result;
1590: }
1591: }
1592:
1593: } else if (node instanceof StyleElement) {
1594: StyleElement snode = (StyleElement) node;
1595: Expression child;
1596: if (snode.validationError != null) {
1597: child = fallbackProcessing(exec, snode);
1598:
1599: } else {
1600: child = snode.compile(exec);
1601: if (child instanceof ComputedExpression) {
1602: ComputedExpression childi = (ComputedExpression) child;
1603: childi.setLocationId(allocateLocationId(
1604: getSystemId(), snode.getLineNumber()));
1605: }
1606: if (child != null) {
1607: if (includeParams
1608: || !(node instanceof XSLParam)) {
1609: if (getConfiguration().getTraceListener() != null) {
1610: TraceWrapper trace = makeTraceInstruction(
1611: snode, child);
1612: child = trace;
1613: }
1614: }
1615: }
1616: }
1617: result = Block.makeBlock(result, child);
1618: if (result instanceof ComputedExpression) {
1619: ((ComputedExpression) result)
1620: .setLocationId(locationId);
1621: }
1622: }
1623: }
1624: }
1625:
1626: /**
1627: * Create a trace instruction to wrap a real instruction
1628: */
1629:
1630: protected static TraceWrapper makeTraceInstruction(
1631: StyleElement source, Expression child) {
1632: if (child instanceof TraceWrapper) {
1633: return (TraceWrapper) child;
1634: // this can happen, for example, after optimizing a compile-time xsl:if
1635: }
1636:
1637: TraceWrapper trace = new TraceInstruction(child, source);
1638: trace.setLocationId(source.allocateLocationId(source
1639: .getSystemId(), source.getLineNumber()));
1640: return trace;
1641: }
1642:
1643: /**
1644: * Perform fallback processing. Generate fallback code for an extension
1645: * instruction that is not recognized by the implementation.
1646: *
1647: * @param instruction The unknown extension instruction
1648: */
1649:
1650: protected Expression fallbackProcessing(Executable exec,
1651: StyleElement instruction) throws XPathException {
1652: // process any xsl:fallback children; if there are none,
1653: // generate code to report the original failure reason
1654: Expression fallback = null;
1655: AxisIterator kids = instruction.iterateAxis(Axis.CHILD);
1656: while (true) {
1657: NodeInfo child = (NodeInfo) kids.next();
1658: if (child == null) {
1659: break;
1660: }
1661: if (child instanceof XSLFallback) {
1662: //fallback.setLocationId(allocateLocationId(getSystemId(), child.getLineNumber()));
1663: //((XSLFallback)child).compileChildren(exec, fallback, true);
1664: Expression b = ((XSLFallback) child)
1665: .compileSequenceConstructor(exec, child
1666: .iterateAxis(Axis.CHILD), true);
1667: if (b == null) {
1668: b = EmptySequence.getInstance();
1669: }
1670: if (fallback == null) {
1671: fallback = b;
1672: } else {
1673: fallback = Block.makeBlock(fallback, b);
1674: if (fallback instanceof ComputedExpression) {
1675: ((ComputedExpression) fallback)
1676: .setLocationId(allocateLocationId(
1677: getSystemId(), getLineNumber()));
1678: }
1679: }
1680: }
1681: }
1682: if (fallback != null) {
1683: return fallback;
1684: } else {
1685: compileError(instruction.validationError);
1686: return EmptySequence.getInstance();
1687: }
1688:
1689: }
1690:
1691: /**
1692: * Allocate a location identifier
1693: */
1694:
1695: public int allocateLocationId(String systemId, int lineNumber) {
1696: return getStaticContext().getLocationMap().allocateLocationId(
1697: systemId, lineNumber);
1698: }
1699:
1700: /**
1701: * Construct sort keys for a SortedIterator
1702: *
1703: * @return an array of SortKeyDefinition objects if there are any sort keys;
1704: * or null if there are none.
1705: */
1706:
1707: protected SortKeyDefinition[] makeSortKeys() {
1708: // handle sort keys if any
1709:
1710: int numberOfSortKeys = 0;
1711: AxisIterator kids = iterateAxis(Axis.CHILD);
1712: while (true) {
1713: Item child = kids.next();
1714: if (child == null) {
1715: break;
1716: }
1717: if (child instanceof XSLSort) {
1718: numberOfSortKeys++;
1719: }
1720: }
1721:
1722: if (numberOfSortKeys > 0) {
1723: SortKeyDefinition[] keys = new SortKeyDefinition[numberOfSortKeys];
1724: kids = iterateAxis(Axis.CHILD);
1725: int k = 0;
1726: while (true) {
1727: NodeInfo child = (NodeInfo) kids.next();
1728: if (child == null) {
1729: break;
1730: }
1731: if (child instanceof XSLSort) {
1732: keys[k++] = ((XSLSort) child)
1733: .getSortKeyDefinition();
1734: }
1735: }
1736: return keys;
1737:
1738: } else {
1739: return null;
1740: }
1741: }
1742:
1743: /**
1744: * Get the list of attribute-sets associated with this element.
1745: * This is used for xsl:element, xsl:copy, xsl:attribute-set, and on literal
1746: * result elements
1747: *
1748: * @param use the original value of the [xsl:]use-attribute-sets attribute
1749: * @param list an empty list to hold the list of XSLAttributeSet elements in the stylesheet tree.
1750: * Or null, if these are not required.
1751: * @return an array of AttributeList instructions representing the compiled attribute sets
1752: */
1753:
1754: protected AttributeSet[] getAttributeSets(String use, List list)
1755: throws XPathException {
1756:
1757: if (list == null) {
1758: list = new ArrayList(4);
1759: }
1760:
1761: XSLStylesheet stylesheet = getPrincipalStylesheet();
1762: List toplevel = stylesheet.getTopLevel();
1763:
1764: StringTokenizer st = new StringTokenizer(use);
1765: while (st.hasMoreTokens()) {
1766: String asetname = st.nextToken();
1767: int fprint;
1768: try {
1769: fprint = makeNameCode(asetname) & 0xfffff;
1770: } catch (NamespaceException err) {
1771: compileError(err.getMessage(), "XTSE0710");
1772: fprint = -1;
1773: } catch (XPathException err) {
1774: compileError(err.getMessage(), "XTSE0710");
1775: fprint = -1;
1776: }
1777: boolean found = false;
1778:
1779: // search for the named attribute set, using all of them if there are several with the
1780: // same name
1781:
1782: for (int i = 0; i < toplevel.size(); i++) {
1783: if (toplevel.get(i) instanceof XSLAttributeSet) {
1784: XSLAttributeSet t = (XSLAttributeSet) toplevel
1785: .get(i);
1786: if (t.getAttributeSetFingerprint() == fprint) {
1787: list.add(t);
1788: found = true;
1789: }
1790: }
1791: }
1792:
1793: if (!found) {
1794: compileError("No attribute-set exists named "
1795: + asetname, "XTSE0710");
1796: }
1797: }
1798:
1799: AttributeSet[] array = new AttributeSet[list.size()];
1800: for (int i = 0; i < list.size(); i++) {
1801: XSLAttributeSet aset = (XSLAttributeSet) list.get(i);
1802: aset.incrementReferenceCount();
1803: array[i] = aset.getInstruction();
1804: }
1805: return array;
1806: }
1807:
1808: /**
1809: * Get the list of xsl:with-param elements for a calling element (apply-templates,
1810: * call-template, apply-imports, next-match). This method can be used to get either
1811: * the tunnel parameters, or the non-tunnel parameters.
1812: *
1813: * @param tunnel true if the tunnel="yes" parameters are wanted, false to get
1814: * @param caller
1815: */
1816:
1817: protected WithParam[] getWithParamInstructions(Executable exec,
1818: boolean tunnel, Instruction caller) throws XPathException {
1819: int count = 0;
1820: AxisIterator kids = iterateAxis(Axis.CHILD);
1821: while (true) {
1822: NodeInfo child = (NodeInfo) kids.next();
1823: if (child == null) {
1824: break;
1825: }
1826: if (child instanceof XSLWithParam) {
1827: XSLWithParam wp = (XSLWithParam) child;
1828: if (wp.isTunnelParam() == tunnel) {
1829: count++;
1830: }
1831: }
1832: }
1833: WithParam[] array = new WithParam[count];
1834: count = 0;
1835: kids = iterateAxis(Axis.CHILD);
1836: while (true) {
1837: NodeInfo child = (NodeInfo) kids.next();
1838: if (child == null) {
1839: return array;
1840: }
1841: if (child instanceof XSLWithParam) {
1842: XSLWithParam wp = (XSLWithParam) child;
1843: if (wp.isTunnelParam() == tunnel) {
1844: WithParam p = (WithParam) wp.compile(exec);
1845: p.setParentExpression(caller);
1846: array[count++] = p;
1847: }
1848:
1849: }
1850: }
1851: }
1852:
1853: /**
1854: * Construct an exception with diagnostic information
1855: */
1856:
1857: protected void compileError(TransformerException error)
1858: throws XPathException {
1859:
1860: // Set the location of the error if there is not current location information,
1861: // or if the current location information is local to the XPath expression
1862: if (error.getLocator() == null
1863: || error.getLocator() instanceof ExpressionLocation) {
1864: error.setLocator(this );
1865: }
1866: PreparedStylesheet pss = getPreparedStylesheet();
1867: try {
1868: if (pss == null) {
1869: // it is null before the stylesheet has been fully built
1870: throw error;
1871: } else {
1872: pss.reportError(error);
1873: }
1874: } catch (TransformerException err2) {
1875: if (err2.getLocator() == null) {
1876: err2.setLocator(this );
1877: }
1878: throw StaticError.makeStaticError(err2);
1879: }
1880: }
1881:
1882: protected void compileError(String message) throws XPathException {
1883: StaticError tce = new StaticError(message);
1884: tce.setLocator(this );
1885: compileError(tce);
1886: }
1887:
1888: /**
1889: * Compile time error, specifying an error code
1890: *
1891: * @param message the error message
1892: * @param errorCode the error code. May be null if not known or not defined
1893: * @throws XPathException
1894: */
1895:
1896: protected void compileError(String message, String errorCode)
1897: throws XPathException {
1898: StaticError tce = new StaticError(message);
1899: tce.setErrorCode(errorCode);
1900: tce.setLocator(this );
1901: compileError(tce);
1902: }
1903:
1904: protected void undeclaredNamespaceError(String prefix,
1905: String errorCode) throws XPathException {
1906: if (errorCode == null) {
1907: errorCode = "XTSE0280";
1908: }
1909: compileError("Undeclared namespace prefix " + Err.wrap(prefix),
1910: errorCode);
1911: }
1912:
1913: protected void compileWarning(String message, String errorCode)
1914: throws XPathException {
1915: StaticError tce = new StaticError(message);
1916: tce.setErrorCode(errorCode);
1917: tce.setLocator(this );
1918: PreparedStylesheet pss = getPreparedStylesheet();
1919: if (pss != null) {
1920: pss.reportWarning(tce);
1921: }
1922: }
1923:
1924: /**
1925: * Construct an exception with diagnostic information
1926: */
1927:
1928: protected void issueWarning(TransformerException error) {
1929: if (error.getLocator() == null) {
1930: error.setLocator(this );
1931: }
1932: PreparedStylesheet pss = getPreparedStylesheet();
1933: if (pss != null) {
1934: // it is null before the stylesheet has been fully built - ignore it
1935: pss.reportWarning(error);
1936: }
1937: }
1938:
1939: protected void issueWarning(String message, SourceLocator locator) {
1940: TransformerConfigurationException tce = new TransformerConfigurationException(
1941: message);
1942: if (locator == null) {
1943: tce.setLocator(this );
1944: } else {
1945: tce.setLocator(locator);
1946: }
1947: issueWarning(tce);
1948: }
1949:
1950: /**
1951: * Test whether this is a top-level element
1952: */
1953:
1954: public boolean isTopLevel() {
1955: return (getParent() instanceof XSLStylesheet);
1956: }
1957:
1958: /**
1959: * Bind a variable used in this element to the compiled form of the XSLVariable element in which it is
1960: * declared
1961: *
1962: * @param fingerprint The fingerprint of the name of the variable
1963: * @return the XSLVariableDeclaration (that is, an xsl:variable or xsl:param instruction) for the variable
1964: * @throws net.sf.saxon.trans.StaticError if the variable has not been declared
1965: */
1966:
1967: public XSLVariableDeclaration bindVariable(int fingerprint)
1968: throws StaticError {
1969: XSLVariableDeclaration binding = getVariableBinding(fingerprint);
1970: if (binding == null) {
1971: StaticError err = new StaticError("Variable "
1972: + getTargetNamePool().getDisplayName(fingerprint)
1973: + " has not been declared");
1974: err.setErrorCode("XPST0008");
1975: throw err;
1976: }
1977: return binding;
1978: }
1979:
1980: /**
1981: * Bind a variable used in this element to the declaration in the stylesheet
1982: *
1983: * @param fprint The absolute name of the variable (prefixed by namespace URI)
1984: * @return the XSLVariableDeclaration, or null if it has not been declared
1985: */
1986:
1987: private XSLVariableDeclaration getVariableBinding(int fprint) {
1988: NodeInfo curr = this ;
1989: NodeInfo prev = this ;
1990:
1991: // first search for a local variable declaration
1992: if (!isTopLevel()) {
1993: AxisIterator preceding = curr
1994: .iterateAxis(Axis.PRECEDING_SIBLING);
1995: while (true) {
1996: curr = (NodeInfo) preceding.next();
1997: while (curr == null) {
1998: curr = prev.getParent();
1999: while (curr instanceof XSLFallback) {
2000: // a local variable is not visible within a sibling xsl:fallback element
2001: curr = curr.getParent();
2002: }
2003: prev = curr;
2004: if (curr.getParent() instanceof XSLStylesheet) {
2005: break; // top level
2006: }
2007: preceding = curr
2008: .iterateAxis(Axis.PRECEDING_SIBLING);
2009: curr = (NodeInfo) preceding.next();
2010: }
2011: if (curr.getParent() instanceof XSLStylesheet) {
2012: break;
2013: }
2014: if (curr instanceof XSLVariableDeclaration) {
2015: XSLVariableDeclaration var = (XSLVariableDeclaration) curr;
2016: if (var.getVariableFingerprint() == fprint) {
2017: return var;
2018: }
2019: }
2020: }
2021: }
2022:
2023: // Now check for a global variable
2024: // we rely on the search following the order of decreasing import precedence.
2025:
2026: XSLStylesheet root = getPrincipalStylesheet();
2027: XSLVariableDeclaration var = root.getGlobalVariable(fprint);
2028: return var;
2029: }
2030:
2031: /**
2032: * List the variables that are in scope for this stylesheet element.
2033: * Designed for a debugger, not used by the processor.
2034: * @return two Enumeration of Strings, the global ones [0] and the local ones [1]
2035: */
2036:
2037: /**
2038: * Get a FunctionCall declared using an xsl:function element in the stylesheet
2039: *
2040: * @param fingerprint the fingerprint of the name of the function
2041: * @param arity the number of arguments in the function call. The value -1
2042: * indicates that any arity will do (this is used to support the function-available() function).
2043: * @return the XSLFunction object representing the function declaration
2044: * in the stylesheet, or null if no such function is defined.
2045: */
2046:
2047: public XSLFunction getStylesheetFunction(int fingerprint, int arity) {
2048:
2049: // we rely on the search following the order of decreasing import precedence.
2050:
2051: XSLStylesheet root = getPrincipalStylesheet();
2052: List toplevel = root.getTopLevel();
2053: for (int i = toplevel.size() - 1; i >= 0; i--) {
2054: Object child = toplevel.get(i);
2055: if (child instanceof XSLFunction
2056: && ((XSLFunction) child).getFunctionFingerprint() == fingerprint
2057: && (arity == -1 || ((XSLFunction) child)
2058: .getNumberOfArguments() == arity)) {
2059: XSLFunction func = (XSLFunction) child;
2060: return func;
2061: }
2062: }
2063: return null;
2064: }
2065:
2066: /**
2067: * Get the type of construct. This will be a constant in
2068: * class {@link Location}. This method is part of the {@link InstructionInfo} interface
2069: */
2070:
2071: public int getConstructType() {
2072: return getFingerprint();
2073: }
2074:
2075: /**
2076: * Get a name identifying the object of the expression, for example a function name, template name,
2077: * variable name, key name, element name, etc. This is used only where the name is known statically.
2078: * If there is no name, the value will be -1.
2079: */
2080:
2081: public int getObjectNameCode() {
2082: return objectNameCode;
2083: }
2084:
2085: /**
2086: * Get a fingerprint identifying the object of the expression, for example a function name, template name,
2087: * variable name, key name, element name, etc. This is used only where the name is known statically.
2088: * If there is no name, the value will be -1.
2089: */
2090:
2091: public int getObjectFingerprint() {
2092: return (objectNameCode == -1 ? -1 : objectNameCode & 0xfffff);
2093: }
2094:
2095: /**
2096: * Set the object name code
2097: */
2098:
2099: public void setObjectNameCode(int nameCode) {
2100: objectNameCode = nameCode;
2101: }
2102:
2103: /**
2104: * Get the namespace context of the instruction.
2105: */
2106:
2107: public NamespaceResolver getNamespaceResolver() {
2108: return makeNamespaceContext();
2109: }
2110:
2111: /**
2112: * Get the value of a particular property of the instruction. This is part of the
2113: * {@link InstructionInfo} interface for run-time tracing and debugging. The properties
2114: * available include all the attributes of the source instruction (named by the attribute name):
2115: * these are all provided as string values.
2116: *
2117: * @param name The name of the required property
2118: * @return The value of the requested property, or null if the property is not available
2119: */
2120:
2121: public Object getProperty(String name) {
2122: return getAttributeValue(name);
2123: }
2124:
2125: /**
2126: * Get an iterator over all the properties available. The values returned by the iterator
2127: * will be of type String, and each string can be supplied as input to the getProperty()
2128: * method to retrieve the value of the property.
2129: */
2130:
2131: public Iterator getProperties() {
2132: NamePool pool = getNamePool();
2133: List list = new ArrayList(10);
2134: AxisIterator it = iterateAxis(Axis.ATTRIBUTE);
2135: while (true) {
2136: NodeInfo a = (NodeInfo) it.next();
2137: if (a == null) {
2138: break;
2139: }
2140: list.add(pool.getClarkName(a.getNameCode()));
2141: }
2142: return list.iterator();
2143: }
2144:
2145: public String getSystemId(int locationId) {
2146: return getSystemId();
2147: }
2148:
2149: public int getLineNumber(int locationId) {
2150: return getLineNumber();
2151: }
2152: }
2153:
2154: //
2155: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
2156: // you may not use this file except in compliance with the License. You may obtain a copy of the
2157: // License at http://www.mozilla.org/MPL/
2158: //
2159: // Software distributed under the License is distributed on an "AS IS" basis,
2160: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
2161: // See the License for the specific language governing rights and limitations under the License.
2162: //
2163: // The Original Code is: all this file.
2164: //
2165: // The Initial Developer of the Original Code is Michael H. Kay.
2166: //
2167: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
2168: //
2169: // Contributor(s):
2170: //
|