in wicket-core/src/main/java/org/apache/wicket/markup/parser/XmlPullParser.java [167:324]
public final HttpTagType next() throws ParseException
{
// Reached end of markup file?
if (input.getPosition() >= input.size())
{
return HttpTagType.NOT_INITIALIZED;
}
if (skipUntilText != null)
{
skipUntil();
return lastType;
}
// Any more tags in the markup?
final int openBracketIndex = input.find('<');
// Tag or Body?
if (input.charAt(input.getPosition()) != '<')
{
// It's a BODY
if (openBracketIndex == -1)
{
// There is no next matching tag.
lastText = input.getSubstring(-1);
input.setPosition(input.size());
lastType = HttpTagType.BODY;
return lastType;
}
lastText = input.getSubstring(openBracketIndex);
input.setPosition(openBracketIndex);
lastType = HttpTagType.BODY;
return lastType;
}
// Determine the line number
input.countLinesTo(openBracketIndex);
// Get index of closing tag and advance past the tag
int closeBracketIndex = -1;
if (openBracketIndex != -1 && openBracketIndex < input.size() - 1)
{
char nextChar = input.charAt(openBracketIndex + 1);
if ((nextChar == '!') || (nextChar == '?'))
closeBracketIndex = input.find('>', openBracketIndex);
else
closeBracketIndex = input.findOutOfQuotes('>', openBracketIndex);
}
if (closeBracketIndex == -1)
{
throw new ParseException("No matching close bracket at" + getLineAndColumnText(),
input.getPosition());
}
// Get the complete tag text
lastText = input.getSubstring(openBracketIndex, closeBracketIndex + 1);
// Get the tagtext between open and close brackets
String tagText = lastText.subSequence(1, lastText.length() - 1).toString();
if (tagText.length() == 0)
{
throw new ParseException("Found empty tag: '<>' at" + getLineAndColumnText(),
input.getPosition());
}
// Type of the tag, to be determined next
final TagType type;
// If the tag ends in '/', it's a "simple" tag like <foo/>
if (tagText.endsWith("/"))
{
type = TagType.OPEN_CLOSE;
tagText = tagText.substring(0, tagText.length() - 1);
}
else if (tagText.startsWith("/"))
{
// The tag text starts with a '/', it's a simple close tag
type = TagType.CLOSE;
tagText = tagText.substring(1);
}
else
{
// It must be an open tag
type = TagType.OPEN;
// If open tag and starts with "s" like "script" or "style", than ...
if ((tagText.length() > STYLE.length()) &&
((tagText.charAt(0) == 's') || (tagText.charAt(0) == 'S')))
{
final String lowerCase = tagText.toLowerCase(Locale.ROOT);
if (lowerCase.startsWith(SCRIPT))
{
String typeAttr = "type=";
int idxOfType = lowerCase.indexOf(typeAttr);
if (idxOfType > 0)
{
// +1 to remove the ' or "
String typePrefix = lowerCase.substring(idxOfType + typeAttr.length() + 1);
if (typePrefix.startsWith("text/javascript") || typePrefix.startsWith("module")
|| typePrefix.startsWith("importmap"))
{
// prepare to skip everything between the open and close tag
skipUntilText = SCRIPT;
}
// any other type is assumed to be a template so it can contain child nodes.
// See WICKET-5288
}
else
{
// no type attribute so it is 'text/javascript'
// prepare to skip everything between the open and close tag
skipUntilText = SCRIPT;
}
}
else if (lowerCase.startsWith(STYLE))
{
// prepare to skip everything between the open and close tag
skipUntilText = STYLE;
}
}
}
// Handle special tags like <!-- and <![CDATA ...
final char firstChar = tagText.charAt(0);
if ((firstChar == '!') || (firstChar == '?'))
{
specialTagHandling(tagText, openBracketIndex, closeBracketIndex);
input.countLinesTo(openBracketIndex);
TextSegment text = new TextSegment(lastText, openBracketIndex, input.getLineNumber(),
input.getColumnNumber());
lastTag = new XmlTag(text, type);
return lastType;
}
TextSegment text = new TextSegment(lastText, openBracketIndex, input.getLineNumber(),
input.getColumnNumber());
XmlTag tag = new XmlTag(text, type);
lastTag = tag;
// Parse the tag text and populate tag attributes
if (parseTagText(tag, tagText))
{
// Move to position after the tag
input.setPosition(closeBracketIndex + 1);
lastType = HttpTagType.TAG;
return lastType;
}
else
{
throw new ParseException("Malformed tag" + getLineAndColumnText(), openBracketIndex);
}
}