/// <summary> /// End tags handler /// </summary> /// <param name="context">Markup parsing context</param> /// <param name="tagName">Tag name</param> private void EndTagHandler(MarkupParsingContext context, string tagName) { XmlNodeType previousNodeType = _currentNodeType; string previousText = _currentText; _currentNodeType = XmlNodeType.EndTag; _currentText = string.Empty; if (_settings.CollapseTagsWithoutContent && previousNodeType == XmlNodeType.StartTag && previousText.Length == 0) { if (TransformLastStartTagToEmptyTag()) { FlushBuffer(); return; } } if (_settings.MinifyWhitespace && previousNodeType == XmlNodeType.Text && (_endTagBeforeText || _emptyTagBeforeText)) { RemoveLastWhitespaceBufferItems(); } // Add end tag to buffer _buffer.Add("</"); _buffer.Add(tagName); _buffer.Add(">"); FlushBuffer(); }
/// <summary> /// Parses a Angular comment directive /// </summary> /// <param name="commentText">Comment text</param> /// <param name="commentDirectiveHandler">Angular comment directive handler</param> public static void ParseCommentDirective(string commentText, CommentDirectiveDelegate commentDirectiveHandler) { Match match = _ngCommentDirectiveRegex.Match(commentText); if (match.Success) { var innerContext = new InnerMarkupParsingContext(commentText); var context = new MarkupParsingContext(innerContext); GroupCollection groups = match.Groups; Group directiveNameGroup = groups["directiveName"]; string directiveName = directiveNameGroup.Value; Group expressionGroup = groups["expression"]; if (expressionGroup.Success) { int expressionPosition = expressionGroup.Index; string expression = expressionGroup.Value.Trim(); innerContext.IncreasePosition(expressionPosition); commentDirectiveHandler?.Invoke(context, directiveName, expression); } } }
/// <summary> /// End tags handler /// </summary> /// <param name="context">Markup parsing context</param> /// <param name="tagName">Tag name</param> private void EndTagHandler(MarkupParsingContext context, string tagName) { XmlNodeType previousNodeType = _currentNodeType; string previousText = _currentText; _currentNodeType = XmlNodeType.EndTag; _currentText = string.Empty; XmlMinificationOutputWriter output = _output; if (_settings.CollapseTagsWithoutContent && previousNodeType == XmlNodeType.StartTag && previousText.Length == 0) { if (output.TransformLastStartTagToEmptyTag(_settings.RenderEmptyTagsWithSpace)) { output.Flush(); return; } } if (_settings.MinifyWhitespace && previousNodeType == XmlNodeType.Text && (_endTagBeforeText || _emptyTagBeforeText)) { output.RemoveLastWhitespaceItems(); } // Add end tag to buffer output.Write("</"); output.Write(tagName); output.Write(">"); output.Flush(); }
/// <summary> /// Parses a Angular class directive /// </summary> /// <param name="className">Class name</param> /// <param name="classDirectiveHandler">Angular class directive handler</param> /// <param name="otherContentHandler">Other сontent handler</param> public static void ParseClassDirective(string className, ClassDirectiveDelegate classDirectiveHandler, OtherContentDelegate otherContentHandler) { int classNameLength = className.Length; int currentPosition = 0; int remainderLength = classNameLength; var innerContext = new InnerMarkupParsingContext(className); var context = new MarkupParsingContext(innerContext); Match match = _ngClassDirectiveRegex.Match(className, currentPosition, remainderLength); while (match.Success) { GroupCollection groups = match.Groups; Group directiveNameGroup = groups["directiveName"]; int directiveNamePosition = directiveNameGroup.Index; string directiveName = directiveNameGroup.Value; if (directiveNamePosition > currentPosition) { string otherContent = className.Substring(currentPosition, directiveNamePosition - currentPosition); otherContentHandler?.Invoke(context, otherContent); } Group expressionGroup = groups["expression"]; string expression = string.Empty; if (expressionGroup.Success) { int expressionPosition = expressionGroup.Index; expression = expressionGroup.Value.Trim(); innerContext.IncreasePosition(expressionPosition - currentPosition); currentPosition = expressionPosition; remainderLength = classNameLength - currentPosition; } Group semicolonGroup = groups["semicolon"]; bool endsWithSemicolon = semicolonGroup.Success; classDirectiveHandler?.Invoke(context, directiveName, expression, endsWithSemicolon); int nextItemPosition = match.Index + match.Length; innerContext.IncreasePosition(nextItemPosition - currentPosition); currentPosition = nextItemPosition; remainderLength = classNameLength - currentPosition; match = _ngClassDirectiveRegex.Match(className, currentPosition, remainderLength); } if (remainderLength > 0) { string otherContent = className.Substring(currentPosition, remainderLength); otherContentHandler?.Invoke(context, otherContent); } }
/// <summary> /// Parses a Angular comment directive /// </summary> /// <param name="commentText">Comment text</param> /// <param name="directiveNameHandler">Directive name handler</param> /// <param name="expressionHandler">Binding expression handler</param> public static void ParseCommentDirective(string commentText, DirectiveNameDelegate directiveNameHandler, ExpressionDelegate expressionHandler) { Match match = _ngCommentDirectiveRegex.Match(commentText); if (match.Success) { var innerContext = new InnerMarkupParsingContext(commentText); var context = new MarkupParsingContext(innerContext); GroupCollection groups = match.Groups; Group directiveNameGroup = groups["directiveName"]; int directiveNamePosition = directiveNameGroup.Index; string originalDirectiveName = directiveNameGroup.Value; string normalizedDirectiveName = NormalizeDirectiveName(originalDirectiveName); innerContext.IncreasePosition(directiveNamePosition); directiveNameHandler?.Invoke(context, originalDirectiveName, normalizedDirectiveName); Group expressionGroup = groups["expression"]; if (expressionGroup.Success) { int expressionPosition = expressionGroup.Index; string expression = expressionGroup.Value.Trim(); innerContext.IncreasePosition(expressionPosition - directiveNamePosition); expressionHandler?.Invoke(context, expression); } } }
/// <summary> /// Start tags handler /// </summary> /// <param name="context">Markup parsing context</param> /// <param name="tagName">Tag name</param> /// <param name="attributes">List of attributes</param> private void StartTagHandler(MarkupParsingContext context, string tagName, List <XmlAttribute> attributes) { XmlNodeType previousNodeType = _currentNodeType; _currentNodeType = XmlNodeType.StartTag; _currentText = string.Empty; XmlMinificationOutputWriter output = _output; if (_settings.MinifyWhitespace && previousNodeType == XmlNodeType.Text && (_startTagBeforeText || _endTagBeforeText || _emptyTagBeforeText || _ignoredFragmentBeforeText || _xmlDeclarationBeforeText || _processingInstructionBeforeText || _doctypeBeforeText)) { output.RemoveLastWhitespaceItems(); } output.Flush(); output.Write("<"); output.Write(tagName); WriteAttributes(attributes); output.Write(">"); }
/// <summary> /// Parses a Angular class directive /// </summary> /// <param name="className">Class name</param> /// <param name="directiveNameHandler">Directive name handler</param> /// <param name="expressionHandler">Binding expression handler</param> /// <param name="semicolonHandler">Semicolon handler</param> public static void ParseClassDirective(string className, DirectiveNameDelegate directiveNameHandler, ExpressionDelegate expressionHandler, SemicolonDelegate semicolonHandler) { MatchCollection ngClassDirectiveMatches = _ngClassDirectiveRegex.Matches(className); if (ngClassDirectiveMatches.Count > 0) { var innerContext = new InnerMarkupParsingContext(className); var context = new MarkupParsingContext(innerContext); int currentPosition = 0; foreach (Match ngClassDirectiveMatch in ngClassDirectiveMatches) { GroupCollection groups = ngClassDirectiveMatch.Groups; Group directiveNameGroup = groups["directiveName"]; int directiveNamePosition = directiveNameGroup.Index; string originalDirectiveName = directiveNameGroup.Value; string normalizedDirectiveName = NormalizeDirectiveName(originalDirectiveName); innerContext.IncreasePosition(directiveNamePosition - currentPosition); currentPosition = directiveNamePosition; if (directiveNameHandler != null) { directiveNameHandler(context, originalDirectiveName, normalizedDirectiveName); } Group expressionGroup = groups["expression"]; if (expressionGroup.Success) { int expressionPosition = expressionGroup.Index; string expression = expressionGroup.Value.Trim(); innerContext.IncreasePosition(expressionPosition - currentPosition); currentPosition = expressionPosition; if (expressionHandler != null) { expressionHandler(context, expression); } } Group semicolonGroup = groups["semicolon"]; if (semicolonGroup.Success) { int semicolonPosition = semicolonGroup.Index; innerContext.IncreasePosition(semicolonPosition - currentPosition); currentPosition = semicolonPosition; if (semicolonHandler != null) { semicolonHandler(context); } } } } }
/// <summary> /// CDATA sections handler /// </summary> /// <param name="context">Markup parsing context</param> /// <param name="cdataText">CDATA text</param> private void CdataSectionHandler(MarkupParsingContext context, string cdataText) { _currentNodeType = XmlNodeType.CdataSection; _buffer.Add("<![CDATA["); _buffer.Add(cdataText); _buffer.Add("]]>"); }
/// <summary> /// CDATA sections handler /// </summary> /// <param name="context">Markup parsing context</param> /// <param name="cdataText">CDATA text</param> private void CdataSectionHandler(MarkupParsingContext context, string cdataText) { _currentNodeType = XmlNodeType.CdataSection; XmlMinificationOutputWriter output = _output; output.Write("<![CDATA["); output.Write(cdataText); output.Write("]]>"); }
/// <summary> /// Comments handler /// </summary> /// <param name="context">Markup parsing context</param> /// <param name="commentText">Comment text</param> private void CommentHandler(MarkupParsingContext context, string commentText) { if (!_settings.RemoveXmlComments) { _currentNodeType = XmlNodeType.Comment; _buffer.Add("<!--"); _buffer.Add(commentText); _buffer.Add("-->"); } }
/// <summary> /// Document type declaration handler /// </summary> /// <param name="context">Markup parsing context</param> /// <param name="doctype">Document type declaration</param> private void DoctypeDelegateHandler(MarkupParsingContext context, string doctype) { _currentNodeType = XmlNodeType.Doctype; if (_settings.MinifyWhitespace) { RemoveLastWhitespaceBufferItems(); } _buffer.Add(Utils.CollapseWhitespace(doctype)); }
/// <summary> /// Parses a markup of template /// </summary> /// <param name="content">Markup of template</param> /// <param name="templateTagHandler">Template tags delegate</param> /// <param name="textHandler">Text delegate</param> public static void ParseMarkup(string content, HtmlParsingHandlers.TemplateTagDelegate templateTagHandler, HtmlParsingHandlers.TextDelegate textHandler) { var innerContext = new InnerMarkupParsingContext(content); var context = new MarkupParsingContext(innerContext); MatchCollection matches = _templateTagRegex.Matches(content); int matchCount = matches.Count; if (matchCount == 0) { textHandler?.Invoke(context, content); innerContext.IncreasePosition(content.Length); return; } int currentPosition = 0; int endPosition = content.Length - 1; for (int matchIndex = 0; matchIndex < matchCount; matchIndex++) { Match match = matches[matchIndex]; int templateTagPosition = match.Index; int templateTagLength = match.Length; if (templateTagPosition > currentPosition) { string text = content.Substring(currentPosition, templateTagPosition - currentPosition); textHandler?.Invoke(context, text); innerContext.IncreasePosition(text.Length); } GroupCollection groups = match.Groups; string expression = groups["expression"].Value; string startDelimiter = groups["startDelimiter"].Value; string endDelimiter = groups["endDelimiter"].Value; templateTagHandler?.Invoke(context, expression, startDelimiter, endDelimiter); innerContext.IncreasePosition(templateTagLength); currentPosition = templateTagPosition + templateTagLength; } if (currentPosition > 0 && currentPosition <= endPosition) { string text = content.Substring(currentPosition, endPosition - currentPosition + 1); textHandler?.Invoke(context, text); innerContext.IncreasePosition(text.Length); } }
/// <summary> /// Comments handler /// </summary> /// <param name="context">Markup parsing context</param> /// <param name="commentText">Comment text</param> private void CommentHandler(MarkupParsingContext context, string commentText) { if (!_settings.RemoveXmlComments) { _currentNodeType = XmlNodeType.Comment; XmlMinificationOutputWriter output = _output; output.Write("<!--"); output.Write(commentText); output.Write("-->"); } }
/// <summary> /// Parses a Angular class directive /// </summary> /// <param name="className">Class name</param> /// <param name="directiveNameHandler">Directive name handler</param> /// <param name="expressionHandler">Binding expression handler</param> /// <param name="semicolonHandler">Semicolon handler</param> public static void ParseClassDirective(string className, DirectiveNameDelegate directiveNameHandler, ExpressionDelegate expressionHandler, SemicolonDelegate semicolonHandler) { MatchCollection matches = _ngClassDirectiveRegex.Matches(className); int matchCount = matches.Count; if (matchCount > 0) { var innerContext = new InnerMarkupParsingContext(className); var context = new MarkupParsingContext(innerContext); int currentPosition = 0; for (int matchIndex = 0; matchIndex < matchCount; matchIndex++) { Match match = matches[matchIndex]; GroupCollection groups = match.Groups; Group directiveNameGroup = groups["directiveName"]; int directiveNamePosition = directiveNameGroup.Index; string originalDirectiveName = directiveNameGroup.Value; string normalizedDirectiveName = NormalizeDirectiveName(originalDirectiveName); innerContext.IncreasePosition(directiveNamePosition - currentPosition); currentPosition = directiveNamePosition; directiveNameHandler?.Invoke(context, originalDirectiveName, normalizedDirectiveName); Group expressionGroup = groups["expression"]; if (expressionGroup.Success) { int expressionPosition = expressionGroup.Index; string expression = expressionGroup.Value.Trim(); innerContext.IncreasePosition(expressionPosition - currentPosition); currentPosition = expressionPosition; expressionHandler?.Invoke(context, expression); } Group semicolonGroup = groups["semicolon"]; if (semicolonGroup.Success) { int semicolonPosition = semicolonGroup.Index; innerContext.IncreasePosition(semicolonPosition - currentPosition); currentPosition = semicolonPosition; semicolonHandler?.Invoke(context); } } } }
/// <summary> /// XML declaration handler /// </summary> /// <param name="context">Markup parsing context</param> /// <param name="attributes">List of attributes</param> private void XmlDeclarationHandler(MarkupParsingContext context, IList <XmlAttribute> attributes) { _currentNodeType = XmlNodeType.XmlDeclaration; if (_settings.MinifyWhitespace) { RemoveLastWhitespaceBufferItems(); } _buffer.Add("<?xml"); RenderAttributes(attributes); _buffer.Add("?>"); }
/// <summary> /// Ignored fragments handler /// </summary> /// <param name="context">Markup parsing context</param> /// <param name="fragment">Ignored fragment</param> private void IgnoredFragmentHandler(MarkupParsingContext context, string fragment) { _currentNodeType = XmlNodeType.IgnoredFragment; if (_settings.MinifyWhitespace) { RemoveLastWhitespaceBufferItems(); } if (fragment.Length > 0) { _buffer.Add(fragment); } }
/// <summary> /// Document type declaration handler /// </summary> /// <param name="context">Markup parsing context</param> /// <param name="doctype">Document type declaration</param> private void DoctypeDelegateHandler(MarkupParsingContext context, string doctype) { _currentNodeType = XmlNodeType.Doctype; XmlMinificationOutputWriter output = _output; if (_settings.MinifyWhitespace) { output.RemoveLastWhitespaceItems(); } output.Write(Utils.CollapseWhitespace(doctype)); output.Flush(); }
/// <summary> /// Processing instruction handler /// </summary> /// <param name="context">Markup parsing context</param> /// <param name="instructionName">Instruction name</param> /// <param name="attributes">List of attributes</param> private void ProcessingInstructionHandler(MarkupParsingContext context, string instructionName, IList <XmlAttribute> attributes) { _currentNodeType = XmlNodeType.ProcessingInstruction; if (_settings.MinifyWhitespace) { RemoveLastWhitespaceBufferItems(); } _buffer.Add("<?"); _buffer.Add(instructionName); RenderAttributes(attributes); _buffer.Add("?>"); }
/// <summary> /// XML declaration handler /// </summary> /// <param name="context">Markup parsing context</param> /// <param name="attributes">List of attributes</param> private void XmlDeclarationHandler(MarkupParsingContext context, List <XmlAttribute> attributes) { _currentNodeType = XmlNodeType.XmlDeclaration; XmlMinificationOutputWriter output = _output; if (_settings.MinifyWhitespace) { output.RemoveLastWhitespaceItems(); } output.Write("<?xml"); WriteAttributes(attributes); output.Write("?>"); output.Flush(); }
/// <summary> /// Ignored fragments handler /// </summary> /// <param name="context">Markup parsing context</param> /// <param name="fragment">Ignored fragment</param> private void IgnoredFragmentHandler(MarkupParsingContext context, string fragment) { _currentNodeType = XmlNodeType.IgnoredFragment; XmlMinificationOutputWriter output = _output; if (_settings.MinifyWhitespace) { output.RemoveLastWhitespaceItems(); } if (fragment.Length > 0) { output.Write(fragment); output.Flush(); } }
/// <summary> /// Parses a Knockout begin containerless comment /// </summary> /// <param name="commentText">Comment text</param> /// <param name="expressionHandler">Binding expression handler</param> public static void ParseBeginContainerlessComment(string commentText, ExpressionDelegate expressionHandler) { Match match = _koBeginContainerlessCommentRegex.Match(commentText); if (match.Success) { var innerContext = new InnerMarkupParsingContext(commentText); var context = new MarkupParsingContext(innerContext); Group expressionGroup = match.Groups["expression"]; int expressionPosition = expressionGroup.Index; string expression = expressionGroup.Value.TrimEnd(null); innerContext.IncreasePosition(expressionPosition); expressionHandler?.Invoke(context, expression); } }
/// <summary> /// Empty tags handler /// </summary> /// <param name="context">Markup parsing context</param> /// <param name="tagName">Tag name</param> /// <param name="attributes">List of attributes</param> private void EmptyTagHandler(MarkupParsingContext context, string tagName, IList <XmlAttribute> attributes) { XmlNodeType previousNodeType = _currentNodeType; _currentNodeType = XmlNodeType.EmptyTag; _currentText = string.Empty; if (_settings.MinifyWhitespace && previousNodeType == XmlNodeType.Text && (_startTagBeforeText || _endTagBeforeText || _emptyTagBeforeText)) { RemoveLastWhitespaceBufferItems(); } _buffer.Add("<"); _buffer.Add(tagName); RenderAttributes(attributes); _buffer.Add(_settings.RenderEmptyTagsWithSpace ? " />" : "/>"); }
/// <summary> /// Processing instruction handler /// </summary> /// <param name="context">Markup parsing context</param> /// <param name="instructionName">Instruction name</param> /// <param name="attributes">List of attributes</param> private void ProcessingInstructionHandler(MarkupParsingContext context, string instructionName, List <XmlAttribute> attributes) { _currentNodeType = XmlNodeType.ProcessingInstruction; XmlMinificationOutputWriter output = _output; if (_settings.MinifyWhitespace) { output.RemoveLastWhitespaceItems(); } output.Write("<?"); output.Write(instructionName); WriteAttributes(attributes); output.Write("?>"); output.Flush(); }
/// <summary> /// Start tags handler /// </summary> /// <param name="context">Markup parsing context</param> /// <param name="tagName">Tag name</param> /// <param name="attributes">List of attributes</param> private void StartTagHandler(MarkupParsingContext context, string tagName, IList <XmlAttribute> attributes) { XmlNodeType previousNodeType = _currentNodeType; _currentNodeType = XmlNodeType.StartTag; _currentText = string.Empty; if (_settings.MinifyWhitespace && previousNodeType == XmlNodeType.Text && (_startTagBeforeText || _endTagBeforeText || _emptyTagBeforeText || _xmlDeclarationBeforeText || _processingInstructionBeforeText || _doctypeBeforeText)) { RemoveLastWhitespaceBufferItems(); } _buffer.Add("<"); _buffer.Add(tagName); RenderAttributes(attributes); _buffer.Add(">"); }
/// <summary> /// Empty tags handler /// </summary> /// <param name="context">Markup parsing context</param> /// <param name="tagName">Tag name</param> /// <param name="attributes">List of attributes</param> private void EmptyTagHandler(MarkupParsingContext context, string tagName, List <XmlAttribute> attributes) { XmlNodeType previousNodeType = _currentNodeType; _currentNodeType = XmlNodeType.EmptyTag; _currentText = string.Empty; XmlMinificationOutputWriter output = _output; if (_settings.MinifyWhitespace && previousNodeType == XmlNodeType.Text && (_startTagBeforeText || _endTagBeforeText || _emptyTagBeforeText)) { output.RemoveLastWhitespaceItems(); } output.Write("<"); output.Write(tagName); WriteAttributes(attributes); output.Write(_settings.RenderEmptyTagsWithSpace ? " />" : "/>"); output.Flush(); }
/// <summary> /// Text handler /// </summary> /// <param name="context">Markup parsing context</param> /// <param name="text">Text</param> private void TextHandler(MarkupParsingContext context, string text) { XmlNodeType previousNodeType = _currentNodeType; _currentNodeType = XmlNodeType.Text; XmlMinificationOutputWriter output = _output; if (previousNodeType == XmlNodeType.Text) { _currentText = text; output.Write(text); return; } _xmlDeclarationBeforeText = false; _processingInstructionBeforeText = false; _doctypeBeforeText = false; _startTagBeforeText = false; _endTagBeforeText = false; _emptyTagBeforeText = false; _ignoredFragmentBeforeText = false; switch (previousNodeType) { case XmlNodeType.StartTag: _startTagBeforeText = true; break; case XmlNodeType.EndTag: _endTagBeforeText = true; break; case XmlNodeType.EmptyTag: _emptyTagBeforeText = true; break; case XmlNodeType.IgnoredFragment: _ignoredFragmentBeforeText = true; break; case XmlNodeType.XmlDeclaration: _xmlDeclarationBeforeText = true; break; case XmlNodeType.ProcessingInstruction: _processingInstructionBeforeText = true; break; case XmlNodeType.Doctype: _doctypeBeforeText = true; break; } if (_settings.MinifyWhitespace) { if (context.Position == 0) { // Processing starting whitespace text = text.TrimStart(null); } else if (context.Position + text.Length == context.Length) { // Processing ending whitespace text = text.TrimEnd(null); } else if (_xmlDeclarationBeforeText || _processingInstructionBeforeText || _doctypeBeforeText) { // Processing whitespace, that followed after // the XML declaration, processing instruction // or document type declaration if (string.IsNullOrWhiteSpace(text)) { text = string.Empty; } } } _currentText = text; if (text.Length > 0) { output.Write(text); } }
/// <summary> /// Parses a Mustache-style markup /// </summary> /// <param name="content">Mustache-style markup</param> /// <param name="mustacheStyleTagHandler">Mustache-style tags handler</param> /// <param name="textHandler">Text handler</param> public static void ParseMarkup(string content, MustacheStyleTagDelegate mustacheStyleTagHandler, TextDelegate textHandler) { var innerContext = new InnerMarkupParsingContext(content); var context = new MarkupParsingContext(innerContext); MatchCollection mustacheStyleTagMatches = _mustacheStyleTagRegex.Matches(content); if (mustacheStyleTagMatches.Count == 0) { if (textHandler != null) { textHandler(context, content); } innerContext.IncreasePosition(content.Length); return; } int currentPosition = 0; int endPosition = content.Length - 1; foreach (Match mustacheStyleTagMatch in mustacheStyleTagMatches) { int mustacheStyleTagPosition = mustacheStyleTagMatch.Index; int mustacheStyleTagLength = mustacheStyleTagMatch.Length; if (mustacheStyleTagPosition > currentPosition) { string text = content.Substring(currentPosition, mustacheStyleTagPosition - currentPosition); if (textHandler != null) { textHandler(context, text); } innerContext.IncreasePosition(text.Length); } GroupCollection mustacheStyleTagGroups = mustacheStyleTagMatch.Groups; string expression = mustacheStyleTagGroups["expression"].Value; string startDelimiter = mustacheStyleTagGroups["startDelimiter"].Value; string endDelimiter = mustacheStyleTagGroups["endDelimiter"].Value; if (expression.StartsWith("{") && expression.EndsWith("}")) { expression = expression.Substring(1, expression.Length - 2); startDelimiter = "{{{"; endDelimiter = "}}}"; } if (mustacheStyleTagHandler != null) { mustacheStyleTagHandler(context, expression, startDelimiter, endDelimiter); } innerContext.IncreasePosition(mustacheStyleTagLength); currentPosition = mustacheStyleTagPosition + mustacheStyleTagLength; } if (currentPosition > 0 && currentPosition <= endPosition) { string text = content.Substring(currentPosition, endPosition - currentPosition + 1); if (textHandler != null) { textHandler(context, text); } innerContext.IncreasePosition(text.Length); } }