private TagNode tag() throws IOException, TemplateParsingException {
OpenTagToken token = (OpenTagToken) currentToken;
Cambridge bindings = Cambridge.getInstance();
TagNode node = null;
if (token.getNameSpace() != null) {
String namespaceUri = getNamespaceUri(token.getNameSpace());
if (namespaceUri != null) {
node = bindings.getDynamicTag(new DynamicAttributeKey(namespaceUri, token.getNameSpace(), token.getTagName()));
}
}
boolean dynamicTag = true;
if (node == null) {
node = new TagNode();
dynamicTag = false;
}
node.setBeginLine(token.getLineNo());
node.setBeginColumn(token.getColumn());
node.setTagName(token.getTagName());
node.setNameSpace(token.getNameSpace());
node.setTagNameString(token.value);
// Match the open tag
while (peek(1).getType() != TokenType.EOF) {
nextToken();
switch (currentToken.getType()) {
case WS:
case EOL:
TextTagPart e = new TextTagPart(currentToken.getActualValue(), currentToken.getLineNo(), currentToken.getColumn());
e.whitespace = true;
node.addText(e);
break;
case TAG_STRING:
case ASSIGN:
node.addText(new TextTagPart(currentToken.getActualValue(), currentToken.getLineNo(), currentToken.getColumn()));
break;
case ATTRIBUTE_NAME:
AttributeNameToken tok = (AttributeNameToken) currentToken;
if (dynamicTag && tok.getNameSpace() == null) {
tok.setNameSpace(node.getNameSpace());
}
Attribute element = null;
StringBuilder textContent = new StringBuilder();
textContent.append(tok.getActualValue());
boolean dynamic = false;
boolean staticAttribute = false;
String namespaceUri = getNamespaceUri(tok.getNameSpace());
if (namespaceUri != null && bindings.isRegisteredNamespace(namespaceUri)) {
dynamic = true;
if (bindings.isStaticAttribute(namespaceUri, tok.getAttributeName())) {
staticAttribute = true;
element = new StaticAttribute(namespaceUri, tok.getLineNo(), tok.getColumn());
} else {
element = new DynamicAttribute(namespaceUri, tok.getLineNo(), tok.getColumn());
}
}
while (true) {
if (peek(1).getType() == TokenType.EOF
|| peek(1).getType() == TokenType.TAG_END
|| peek(1).getType() == TokenType.EXPRESSION
|| peek(1).getType() == TokenType.EXTENSION
|| peek(1).getType() == TokenType.ATTRIBUTE_NAME
) {
break;
}
nextToken();
boolean exitLoop = false;
switch (currentToken.getType()) {
case WS:
case EOL:
case ASSIGN:
textContent.append(currentToken.getActualValue());
break;
case ATTRIBUTE_VALUE:
textContent.append(currentToken.getActualValue());
if (dynamic) {
if (staticAttribute) {
((StaticAttribute) element).setValue(currentToken.value);
} else {
((DynamicAttribute) element).setValue(currentToken.value, expressionLanguage.parse(currentToken.value, currentToken.getLineNo(), currentToken.getColumn()));
}
exitLoop = true;
break;
}
TemplateTokenizer at = new TemplateTokenizer(new StringReader(currentToken.getValue()));
ArrayList<AttributeFragment> fragments = new ArrayList<AttributeFragment>();
while (at.hasMoreTokens()) {
Token attrToken = at.nextToken();
switch (attrToken.getType()) {
case EXPRESSION:
ExpressionToken expTok = (ExpressionToken) attrToken;
try {
ExpressionNode expNode = new ExpressionNode(attrToken.value, expressionLanguage.parse(attrToken.value, attrToken.getLineNo(), attrToken.getColumn()), expTok.isRawExpression());
if (expTok.getFilters() != null) {
expNode.setFilters(expTok.getFilters());
}
fragments.add(expNode);
} catch (ExpressionParsingException e1) {
throw new TemplateParsingException("Error parsing expression", e1, currentToken.getLineNo(), currentToken.getColumn());
}
break;
case EXTENSION:
ExtensionToken extensionToken = (ExtensionToken) attrToken;
ExtensionNode extensionNode = extensionToken.createNode(expressionLanguage);
fragments.add(extensionNode);
break;
case WS:
case STRING:
StaticFragment st = new StaticFragment(attrToken.value);
fragments.add(st);
break;
}
}
if (fragments.size() == 0 || fragments.size() == 1 && fragments.get(0) instanceof StaticFragment) {
element = new SimpleAttribute(currentToken.getLineNo(), currentToken.getColumn());
((SimpleAttribute) element).setValue(currentToken.value);
} else {
element = new ComplexAttribute(currentToken.getLineNo(), currentToken.getColumn());
((ComplexAttribute) element).setFragments(fragments);
AttributeValueToken aTok = (AttributeValueToken) currentToken;
if (aTok.getQuotes() == -2) {
((ComplexAttribute) element).setQuote('"');
} else if (aTok.getQuotes() == -3) {
((ComplexAttribute) element).setQuote('\'');
}
}
exitLoop = true;
break;
}
if (exitLoop) break;
}
if (element == null) {
if (tok != null) {
element = new SimpleAttribute(tok.getAttributeName(), tok.getNameSpace(), tok.getLineNo(), tok.getLineNo());
} else {
throw new TemplateParsingException("Error parsing template file. Unterminated tag?", currentToken.getLineNo(), currentToken.getColumn());
}
}
element.setAttributeName(tok.getAttributeName());
element.setAttributeNameSpace(tok.getNameSpace());
element.setTextContent(textContent.toString());
int s = node.getTagParts().size();
if (s > 0) {
TagPart te = node.getTagParts().get(s - 1);
if (te instanceof TextTagPart) {
if (te.isWhiteSpace()) {
node.getTagParts().remove(s - 1);
}
}
}
if (firstTag && "xmlns".equalsIgnoreCase(element.getAttributeNameSpace())) {
putNamespaceMapping(element.getAttributeName(), element.getValue());
}
node.addAttribute(element);
break;
case EXPRESSION:
try {
ExpressionToken t = (ExpressionToken) currentToken;
ExpressionTagPart p = new ExpressionTagPart(currentToken.value,
expressionLanguage.parse(currentToken.value, currentToken.getLineNo(), currentToken.getColumn()),
t.isRawExpression(), currentToken.getLineNo(), currentToken.getColumn());
if (t.getFilters() != null) {
p.setFilters(t.getFilters());
}
node.addExpression(p);
} catch (ExpressionParsingException e1) {
throw new TemplateParsingException("Error parsing expression", e1, currentToken.getLineNo(), currentToken.getColumn());
}
break;
case EXTENSION:
ExtensionToken extensionToken = (ExtensionToken) currentToken;
ExtensionNode extensionTagPart = extensionToken.createNode(expressionLanguage);
node.addTagPart(extensionTagPart);
break;
case TAG_END:
node.setTagEndText(currentToken.getActualValue());
break;
}
if (currentToken.getType() == TokenType.TAG_END) {
if (currentToken.getValue().equals("/>")) {
node.setEndLine(peek(1).getLineNo());
node.setEndColumn(peek(1).getColumn());
if (dynamicTag) {
((DynamicTag) node).init();
}
firstTag = false;