src/Markdig/Extensions/GenericAttributes/GenericAttributesParser.cs
/// <summary>
/// Tries to extra from the current position of a slice an HTML attributes {...}
/// </summary>
/// <param name="slice">The slice to parse.</param>
/// <param name="attributes">The output attributes or null if not found or invalid</param>
/// <returns><c>true</c> if parsing the HTML attributes was successful</returns>
Tries to extra from the current position of a slice an HTML attributes {...}
Tries to extra from the current position of a slice an HTML attributes { ... }
public static bool TryParse(ref StringSlice slice, [NotNullWhen(true)] out HtmlAttributes? attributes)
        {
            attributes = null;
            if (slice.PeekCharExtra(-1) == '{')
            {
                return false;
            }
            var line = slice;
            string? id = null;
            List<string>? classes = null;
            List<KeyValuePair<string, string?>>? properties = null;
            bool isValid = false;
            var c = line.NextChar();
            while (true)
            {
                if (c == '}')
                {
                    isValid = true;
                    line.SkipChar(); 
                    break;
                }
                if (c == '\0')
                {
                    break;
                }
                bool isClass = c == '.';
                if (c == '#' || isClass)
                {
                    c = line.NextChar(); 
                    var start = line.Start;
                    while (c != '}' && c != '\0' && !c.IsWhitespace())
                    {
                        c = line.NextChar();
                    }
                    var end = line.Start - 1;
                    if (end == start)
                    {
                        break;
                    }
                    var text = slice.Text.Substring(start, end - start + 1);
                    if (isClass)
                    {
                        if (classes is null)
                        {
                            classes = new List<string>();
                        }
                        classes.Add(text);
                    }
                    else
                    {
                        id = text;
                    }
                    continue;
                }
                if (!c.IsWhitespace())
                {
                    if (!IsStartAttributeName(c))
                    {
                        break;
                    }
                    var startName = line.Start;
                    while (true)
                    {
                        c = line.NextChar();
                        if (!(c.IsAlphaNumeric() || c == '_' || c == ':' || c == '.' || c == '-'))
                        {
                            break;
                        }
                    }
                    var name = slice.Text.Substring(startName, line.Start - startName);
                    var hasSpace = c.IsSpaceOrTab();
                    line.TrimStart();
                    c = line.CurrentChar;
                    if ((hasSpace && (c == '.' || c == '#' || IsStartAttributeName(c))) || c == '}')
                    {
                        properties ??= new ();
                        properties.Add(new KeyValuePair<string, string?>(name, null));
                        continue;
                    }
                    if (line.CurrentChar != '=')
                    {
                        break;
                    }
                    line.SkipChar();
                    line.TrimStart();
                    int startValue = -1;
                    int endValue = -1;
                    c = line.CurrentChar;
                    if (c == '\'' || c == '"')
                    {
                        char openingStringChar = c;
                        startValue = line.Start + 1;
                        while (true)
                        {
                            c = line.NextChar();
                            if (c == '\0')
                            {
                                return false;
                            }
                            if (c == openingStringChar)
                            {
                                break;
                            }
                        }
                        endValue = line.Start - 1;
                        c = line.NextChar(); 
                    }
                    else
                    {
                        startValue = line.Start;
                        bool valid = false;
                        while (true)
                        {
                            if (c == '\0')
                            {
                                return false;
                            }
                            if (c.IsWhitespace() || c == '}')
                            {
                                break;
                            }
                            c = line.NextChar();
                            valid = true;
                        }
                        endValue = line.Start - 1;
                        if (!valid)
                        {
                            break;
                        }
                    }
                    var value = slice.Text.Substring(startValue, endValue - startValue + 1);
                    properties ??= new();
                    properties.Add(new KeyValuePair<string, string?>(name, value));
                    continue;
                }
                c = line.NextChar();
            }
            if (isValid)
            {
                attributes = new HtmlAttributes()
                {
                    Id = id,
                    Classes = classes,
                    Properties = properties
                };
                slice = line;
            }
            return isValid;
        }
public static bool TryParse ( ref StringSlice slice , [ NotNullWhen ( true ) ] out HtmlAttributes ? attributes ) { attributes = null ; if ( slice . PeekCharExtra ( - 1 ) == ' ' ) { return false ; } var line = slice ; string ? id = null ; List < string > ? classes = null ; List < KeyValuePair < string , string ? > > ? properties = null ; bool isValid = false ; var c = line . NextChar ( ) ; while ( true ) { if ( c == ' ' ) { isValid = true ; line . SkipChar ( ) ; break ; } if ( c == ' \0 ' ) { break ; } bool isClass = c == ' ' ; if ( c == ' ' || isClass ) { c = line . NextChar ( ) ; var start = line . Start ; while ( c != ' ' && c != ' \0 ' && ! c . IsWhitespace ( ) ) { c = line . NextChar ( ) ; } var end = line . Start - 1 ; if ( end == start ) { break ; } var text = slice . Text . Substring ( start , end - start + 1 ) ; if ( isClass ) { if ( classes is null ) { classes = new List < string > ( ) ; } classes . Add ( text ) ; } else { id = text ; } continue ; } if ( ! c . IsWhitespace ( ) ) { if ( ! IsStartAttributeName ( c ) ) { break ; } var startName = line . Start ; while ( true ) { c = line . NextChar ( ) ; if ( ! ( c . IsAlphaNumeric ( ) || c == ' ' || c == ' ' || c == ' ' || c == ' ' ) ) { break ; } } var name = slice . Text . Substring ( startName , line . Start - startName ) ; var hasSpace = c . IsSpaceOrTab ( ) ; line . TrimStart ( ) ; c = line . CurrentChar ; if ( ( hasSpace && ( c == ' ' || c == ' ' || IsStartAttributeName ( c ) ) ) || c == ' ' ) { properties ??= new ( ) ; properties . Add ( new KeyValuePair < string , string ? > ( name , null ) ) ; continue ; } if ( line . CurrentChar != ' ' ) { break ; } line . SkipChar ( ) ; line . TrimStart ( ) ; int startValue = - 1 ; int endValue = - 1 ; c = line . CurrentChar ; if ( c == ' \' ' || c == ' ' ) { char openingStringChar = c ; startValue = line . Start + 1 ; while ( true ) { c = line . NextChar ( ) ; if ( c == ' \0 ' ) { return false ; } if ( c == openingStringChar ) { break ; } } endValue = line . Start - 1 ; c = line . NextChar ( ) ; } else { startValue = line . Start ; bool valid = false ; while ( true ) { if ( c == ' \0 ' ) { return false ; } if ( c . IsWhitespace ( ) || c == ' ' ) { break ; } c = line . NextChar ( ) ; valid = true ; } endValue = line . Start - 1 ; if ( ! valid ) { break ; } } var value = slice . Text . Substring ( startValue , endValue - startValue + 1 ) ; properties ??= new ( ) ; properties . Add ( new KeyValuePair < string , string ? > ( name , value ) ) ; continue ; } c = line . NextChar ( ) ; } if ( isValid ) { attributes = new HtmlAttributes ( ) { Id = id , Classes = classes , Properties = properties } ; slice = line ; } return isValid ; }
Tries to extra from the current position of a slice an HTML attributes {...}
Tries to extra from the current position of a slice an HTML attributes { ... }
// skip } // Skip # // Get all non-whitespace characters following a # // But stop if we found a } or \0 // Parse the attribute name // Skip any whitespaces // Handle boolean properties that are not followed by = // Add a null value for the property // Else we expect a regular property // Go to next char, skip any spaces // Parse a quoted string // Skip closing opening string char // Parse until we match a space or a special html character // Assign back the current processor of the line to
None
StringSlice
ref
out
[NotNullWhen(true)]
slice
The slice to parse.
The slice to parse .
attributes
The output attributes or null if not found or invalid
The output attributes or null if not found or invalid