/// <summary>
        /// Appends the specified text.
        /// </summary>
        /// <param name="text">The text.</param>
        public void Append(string text)
        {
            if (text != "")
            {
                var snippet = new TokenControlReplacerSnippet();
                snippet.OriginalText = text;

                ExtractTokens(snippet);

                for (int i = 0; i < snippet.Tokens.Count; i++)
                {
                    Token token = snippet.Tokens[i];
                    if (i == 0)
                    {
                        snippet.Controls.Controls.Add(new LiteralControl(text.Substring(0, token.Start)));
                    }
                    else
                    {
                        snippet.Controls.Controls.Add(
                            new LiteralControl(text.Substring(snippet.Tokens[i - 1].End,
                                token.Start - snippet.Tokens[i - 1].End)));
                    }

                    snippet.Controls.Controls.Add(new PlaceHolder {ID = token.Id});
                }

                snippet.Controls.Controls.Add(
                    new LiteralControl(text.Substring(snippet.Tokens[snippet.Tokens.Count - 1].End)));

                Snippets.Add(snippet);
            }
        }
        /// <summary>
        /// Extracts the tokens.
        /// </summary>
        /// <param name="snippet">The snippet.</param>
        /// <exception cref="System.ArgumentException"></exception>
        private void ExtractTokens(TokenControlReplacerSnippet snippet)
        {
            int last = 0;
            while (last < snippet.OriginalText.Length)
            {
                // Find next token position in snippet.Text:
                int start = snippet.OriginalText.IndexOf(TokenOpen, last, StringComparison.InvariantCultureIgnoreCase);
                if (start == -1)
                    return;
                int end = snippet.OriginalText.IndexOf(TokenClose, start + TokenOpen.Length,
                    StringComparison.InvariantCultureIgnoreCase);
                if (end == -1)
                    throw new ArgumentException(string.Format("Token is opened but not closed in text \"{0}\".",
                        snippet.OriginalText));
                int eol = snippet.OriginalText.IndexOf('\n', start + TokenOpen.Length);
                if (eol != -1 && eol < end)
                {
                    last = eol + 1;
                    continue;
                }

                // Take the token from snippet.Text:
                end += TokenClose.Length;
                string token =
                    snippet.OriginalText.Substring(start, end - start).Replace(TokenOpen, "").Replace(TokenClose, "");

                var objToken = new Token
                {
                    Start = start,
                    End = end,
                    TokenName = token
                };

                if (token.Contains(":"))
                {
                    string[] nameAndAttributes = token.Split(':');
                    objToken.TokenName = nameAndAttributes[0];

                    var xml = new XmlDocument();
                    string xmlText = @"<root " + nameAndAttributes[1] + " />";
                    xml.LoadXml(xmlText);
                    if (xml.DocumentElement.Attributes != null)
                        foreach (XmlAttribute attribute in xml.DocumentElement.Attributes)
                        {
                            objToken.Attributes.Add(attribute.Name, attribute.Value);
                        }
                }

                snippet.Tokens.Add(objToken);

                last = end;
            }
        }