private void ParseElement()
{
int pos = _ps.charPos;
char[] chars = _ps.chars;
int colonPos = -1;
_curNode.SetLineInfo(_ps.LineNo, _ps.LinePos);
// PERF: we intentionally don't call ParseQName here to parse the element name unless a special
// case occurs (like end of buffer, invalid name char)
ContinueStartName:
// check element name start char
unsafe
{
if (_xmlCharType.IsStartNCNameSingleChar(chars[pos]))
{
pos++;
}
#if XML10_FIFTH_EDITION
else if (pos + 1 < ps.charsUsed && xmlCharType.IsNCNameSurrogateChar(chars[pos + 1], chars[pos]))
{
pos += 2;
}
#endif
else
{
goto ParseQNameSlow;
}
}
ContinueName:
unsafe
{
// parse element name
for (;;)
{
if (_xmlCharType.IsNCNameSingleChar(chars[pos]))
{
pos++;
}
#if XML10_FIFTH_EDITION
else if (pos < ps.charsUsed && xmlCharType.IsNCNameSurrogateChar(chars[pos + 1], chars[pos]))
{
pos += 2;
}
#endif
else
{
break;
}
}
}
// colon -> save prefix end position and check next char if it's name start char
if (chars[pos] == ':')
{
if (colonPos != -1)
{
if (_supportNamespaces)
{
Throw(pos, SR.Xml_BadNameChar, XmlException.BuildCharExceptionArgs(':', '\0'));
}
else
{
pos++;
goto ContinueName;
}
}
else
{
colonPos = pos;
pos++;
goto ContinueStartName;
}
}
else if (pos + 1 < _ps.charsUsed)
{
goto SetElement;
}
ParseQNameSlow:
pos = ParseQName(out colonPos);
chars = _ps.chars;
SetElement:
// push namespace context
_namespaceManager.PushScope();
// init the NodeData class
if (colonPos == -1 || !_supportNamespaces)
{
_curNode.SetNamedNode(XmlNodeType.Element,
_nameTable.Add(chars, _ps.charPos, pos - _ps.charPos));
}
else
{
int startPos = _ps.charPos;
int prefixLen = colonPos - startPos;
if (prefixLen == _lastPrefix.Length && XmlConvert.StrEqual(chars, startPos, prefixLen, _lastPrefix))
{
_curNode.SetNamedNode(XmlNodeType.Element,
_nameTable.Add(chars, colonPos + 1, pos - colonPos - 1),
_lastPrefix,
null);
}
else
{
_curNode.SetNamedNode(XmlNodeType.Element,
_nameTable.Add(chars, colonPos + 1, pos - colonPos - 1),
_nameTable.Add(chars, _ps.charPos, prefixLen),
null);
_lastPrefix = _curNode.prefix;
}
}
char ch = chars[pos];
// white space after element name -> there are probably some attributes
bool isWs;
unsafe
{
isWs = _xmlCharType.IsWhiteSpace(ch);
}
if (isWs)
{
_ps.charPos = pos;
ParseAttributes();
return;
}
// no attributes
else
{
// non-empty element
if (ch == '>')
{
_ps.charPos = pos + 1;
_parsingFunction = ParsingFunction.MoveToElementContent;
}
// empty element
else if (ch == '/')
{
if (pos + 1 == _ps.charsUsed)
{
_ps.charPos = pos;
if (ReadData() == 0)
{
Throw(pos, SR.Xml_UnexpectedEOF, ">");
}
pos = _ps.charPos;
chars = _ps.chars;
}
if (chars[pos + 1] == '>')
{
_curNode.IsEmptyElement = true;
_nextParsingFunction = _parsingFunction;
_parsingFunction = ParsingFunction.PopEmptyElementContext;
_ps.charPos = pos + 2;
}
else
{
ThrowUnexpectedToken(pos, ">");
}
}
// something else after the element name
else
{
Throw(pos, SR.Xml_BadNameChar, XmlException.BuildCharExceptionArgs(chars, _ps.charsUsed, pos));
}
// add default attributes & strip spaces in attributes with type other than CDATA
if (_addDefaultAttributesAndNormalize)
{
AddDefaultAttributesAndNormalize();
}
// lookup element namespace
ElementNamespaceLookup();
}
}