private void endTag() { if (!finalPass) return; String tagName = scan.getToken().trim(); String ns = scan.getNamespace(); if (tagMetaStack.isEmpty()) throw new GrailsTagException( "Found closing Grails tag with no opening [" + tagName + "]", pageName, getCurrentOutputLineNumber()); TagMeta tm = tagMetaStack.pop(); String lastInStack = tm.name; String lastNamespaceInStack = tm.namespace; // if the tag name is blank then it has been closed by the start tag ie <tag /> if (GrailsStringUtils.isBlank(tagName)) { tagName = lastInStack; } if (!lastInStack.equals(tagName) || !lastNamespaceInStack.equals(ns)) { throw new GrailsTagException( "Grails tag [" + lastNamespaceInStack + ":" + lastInStack + "] was not closed", pageName, getCurrentOutputLineNumber()); } if (GroovyPage.DEFAULT_NAMESPACE.equals(ns) && tagRegistry.isSyntaxTag(tagName)) { if (tm.instance instanceof GroovySyntaxTag) { GroovySyntaxTag tag = (GroovySyntaxTag) tm.instance; tag.doEndTag(); } else { throw new GrailsTagException( "Grails tag [" + tagName + "] was not closed", pageName, getCurrentOutputLineNumber()); } } else { int bodyTagIndex = -1; if (!tm.emptyTag && !tm.bufferMode) { bodyTagIndex = tagIndex; out.println("})"); closureLevel--; } if (tm.bufferMode && tm.bufferPartNumber != -1) { if (!bodyVarsDefined.contains(tm.tagIndex)) { // out.print("def "); bodyVarsDefined.add(tm.tagIndex); } out.println("createClosureForHtmlPart(" + tm.bufferPartNumber + ", " + tm.tagIndex + ")"); bodyTagIndex = tm.tagIndex; tm.bufferMode = false; } if (jspTags.containsKey(ns)) { String uri = jspTags.get(ns); out.println("jspTag = getJspTag('" + uri + "', '" + tagName + "')"); out.println( "if (!jspTag) throw new GrailsTagException('Unknown JSP tag " + ns + ":" + tagName + "')"); out.print("jspTag.doTag(out," + attrsVarsMapDefinition.get(tagIndex) + ","); if (bodyTagIndex > -1) { out.print("getBodyClosure(" + bodyTagIndex + ")"); } else { out.print("null"); } out.println(")"); } else { if (tm.hasAttributes) { out.println( "invokeTag('" + tagName + "','" + ns + "'," + getCurrentOutputLineNumber() + "," + attrsVarsMapDefinition.get(tagIndex) + "," + bodyTagIndex + ")"); } else { out.println( "invokeTag('" + tagName + "','" + ns + "'," + getCurrentOutputLineNumber() + ",[:]," + bodyTagIndex + ")"); } } } tm.bufferMode = false; tagIndex--; }
@SuppressWarnings({"unchecked", "rawtypes"}) private void startTag() { if (!finalPass) return; tagIndex++; String text; StringBuilder buf = new StringBuilder(scan.getToken()); String ns = scan.getNamespace(); boolean emptyTag = false; state = scan.nextToken(); while (state != HTML && state != GEND_TAG && state != GEND_EMPTY_TAG && state != EOF) { if (state == GTAG_EXPR) { buf.append("${"); buf.append(scan.getToken().trim()); buf.append("}"); } else { buf.append(scan.getToken()); } state = scan.nextToken(); } if (state == GEND_EMPTY_TAG) { emptyTag = true; } doNextScan = false; text = buf.toString(); String tagName; Map attrs = new LinkedHashMap(); Matcher m = Pattern.compile("\\s").matcher(text); if (m.find()) { // ignores carriage returns and new lines tagName = text.substring(0, m.start()); if (state != EOF) { String attrTokens = text.substring(m.start(), text.length()); populateMapWithAttributes(attrs, attrTokens); } } else { tagName = text; } if (state == EOF) { throw new GrailsTagException( "Unexpected end of file encountered parsing Tag [" + tagName + "] for " + className + ". Are you missing a closing brace '}'?", pageName, getCurrentOutputLineNumber()); } flushTagBuffering(); TagMeta tm = new TagMeta(); tm.name = tagName; tm.namespace = ns; tm.hasAttributes = !attrs.isEmpty(); tm.lineNumber = getCurrentOutputLineNumber(); tm.emptyTag = emptyTag; tm.tagIndex = tagIndex; tagMetaStack.push(tm); if (GroovyPage.DEFAULT_NAMESPACE.equals(ns) && tagRegistry.isSyntaxTag(tagName)) { if (tagContext == null) { tagContext = new HashMap<Object, Object>(); tagContext.put(GroovyPage.OUT, out); tagContext.put(GroovyPageParser.class, this); } GroovySyntaxTag tag = (GroovySyntaxTag) tagRegistry.newTag(tagName); tag.init(tagContext); tag.setAttributes(attrs); if (tag.isKeepPrecedingWhiteSpace() && currentlyBufferingWhitespace) { flushBufferedWhiteSpace(); } else if (!tag.isAllowPrecedingContent() && previousContentWasNonWhitespace) { throw new GrailsTagException( "Tag [" + tag.getName() + "] cannot have non-whitespace characters directly preceding it.", pageName, getCurrentOutputLineNumber()); } else { // If tag does not specify buffering of WS, we swallow it here clearBufferedWhiteSpace(); } tag.doStartTag(); tm.instance = tag; } else { // Custom taglibs have to always flush the whitespace, there's no // "allowPrecedingWhitespace" property on tags yet flushBufferedWhiteSpace(); if (attrs.size() > 0) { FastStringWriter buffer = new FastStringWriter(); buffer.print("["); for (Iterator<?> i = attrs.keySet().iterator(); i.hasNext(); ) { String name = (String) i.next(); String cleanedName = name; if (name.startsWith("\"") && name.endsWith("\"")) { cleanedName = "'" + name.substring(1, name.length() - 1) + "'"; } buffer.print(cleanedName); buffer.print(':'); buffer.print(getExpressionText(attrs.get(name).toString())); if (i.hasNext()) { buffer.print(','); } else { buffer.print("]"); } } attrsVarsMapDefinition.put(tagIndex, buffer.toString()); buffer.close(); } if (!emptyTag) { tm.bufferMode = true; } } }