public override XmlParserState PushChar(char c, XmlParserContext context, ref string rollback) { var namedObject = context.Nodes.Peek() as INamedXObject; if (namedObject == null || namedObject.Name.Prefix != null) { throw new InvalidOperationException("Invalid state"); } Debug.Assert(context.CurrentStateLength > 0 || IsValidNameStart(c), "First character pushed to a XmlTagNameState must be a letter."); Debug.Assert(context.CurrentStateLength > 0 || context.KeywordBuilder.Length == 0, "Keyword builder must be empty when state begins."); if (XmlChar.IsWhitespace(c) || c == '<' || c == '>' || c == '/' || c == '=') { rollback = string.Empty; if (context.KeywordBuilder.Length == 0) { context.Diagnostics?.LogError("Zero-length name.", context.Position); namedObject.Name = XName.Empty; } else { string s = context.KeywordBuilder.ToString(); int i = s.IndexOf(':'); if (i < 0) { namedObject.Name = s; } else { namedObject.Name = new XName(s.Substring(0, i), s.Substring(i + 1)); } } return(Parent); } if (c == ':') { if (context.KeywordBuilder.ToString().IndexOf(':') > 0 && context.BuildTree) { context.Diagnostics?.LogError("Unexpected ':' in name.", context.Position); } context.KeywordBuilder.Append(c); return(null); } if (XmlChar.IsNameChar(c)) { context.KeywordBuilder.Append(c); return(null); } rollback = string.Empty; context.Diagnostics?.LogError($"Unexpected character '{c}' in name", context.Position); return(Parent); }
/// <summary> /// Gets the XML name at the parser's position. /// </summary> /// <param name="spine">A spine parser. It will not be modified.</param> /// <param name="text">The text snapshot corresponding to the parser.</param> /// <returns></returns> public static XName GetCompleteName(this XmlSpineParser spine, ITextSource text, int maximumReadahead = DEFAULT_READAHEAD_LIMIT) { Debug.Assert(spine.CurrentState is XmlNameState); int end = spine.Position; int start = end - spine.CurrentStateLength; int mid = -1; int limit = Math.Min(text.Length, end + maximumReadahead); //try to find the end of the name, but don't go too far for (; end < limit; end++) { char c = text[end]; if (c == ':') { if (mid == -1) { mid = end; } else { break; } } else if (!XmlChar.IsNameChar(c)) { break; } } if (mid > 0 && end > mid + 1) { return(new XName(text.GetText(start, mid - start), text.GetText(mid + 1, end - mid - 1))); } return(new XName(text.GetText(start, end - start))); }