All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sourceforge.htmlunit.cyberneko.HTMLElements Maven / Gradle / Ivy

There is a newer version: 6.0.36
Show newest version
/*
 * Copyright 2002-2009 Andy Clark, Marc Guillemot
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.sourceforge.htmlunit.cyberneko;

import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;

/**
 * Collection of HTML element information.
 *
 * @author Andy Clark
 * @author Ahmed Ashour
 * @author Marc Guillemot
 * @author Ronald Brill
 */
public class HTMLElements {

    //
    // Constants
    //

    // element codes

    // NOTE: The element codes *must* start with 0 and increment in
    //       sequence. The parent and closes references depends on
    //       this assumption. -Ac

    public static final short A = 0;
    public static final short ABBR = A+1;
    public static final short ACRONYM = ABBR+1;
    public static final short ADDRESS = ACRONYM+1;
    public static final short APPLET = ADDRESS+1;
    public static final short AREA = APPLET+1;
    public static final short ARTICLE = AREA+1;
    public static final short ASIDE = ARTICLE+1;
    public static final short B = ASIDE+1;
    public static final short BASE = B+1;
    public static final short BASEFONT = BASE+1;
    public static final short BDO = BASEFONT+1;
    public static final short BGSOUND = BDO+1;
    public static final short BIG = BGSOUND+1;
    public static final short BLINK = BIG+1;
    public static final short BLOCKQUOTE = BLINK+1;
    public static final short BODY = BLOCKQUOTE+1;
    public static final short BR = BODY+1;
    public static final short BUTTON = BR+1;
    public static final short CAPTION = BUTTON+1;
    public static final short CENTER = CAPTION+1;
    public static final short CITE = CENTER+1;
    public static final short CODE = CITE+1;
    public static final short COL = CODE+1;
    public static final short COLGROUP = COL+1;
    public static final short COMMAND = COLGROUP+1;
    public static final short COMMENT = COMMAND+1;
    public static final short DEL = COMMENT+1;
    public static final short DETAILS = DEL+1;
    public static final short DFN = DETAILS+1;
    public static final short DIR = DFN+1;
    public static final short DIV = DIR+1;
    public static final short DD = DIV+1;
    public static final short DL = DD+1;
    public static final short DT = DL+1;
    public static final short EM = DT+1;
    public static final short EMBED = EM+1;
    public static final short FIELDSET = EMBED+1;
    public static final short FIGCAPTION = FIELDSET+1;
    public static final short FIGURE = FIGCAPTION+1;
    public static final short FONT = FIGURE+1;
    public static final short FOOTER = FONT+1;
    public static final short FORM = FOOTER+1;
    public static final short FRAME = FORM+1;
    public static final short FRAMESET = FRAME+1;
    public static final short H1 = FRAMESET+1;
    public static final short H2 = H1+1;
    public static final short H3 = H2+1;
    public static final short H4 = H3+1;
    public static final short H5 = H4+1;
    public static final short H6 = H5+1;
    public static final short HEAD = H6+1;
    public static final short HEADER = HEAD+1;
    public static final short HR = HEADER+1;
    public static final short HTML = HR+1;
    public static final short I = HTML+1;
    public static final short IFRAME = I+1;
    public static final short ILAYER = IFRAME+1;
    public static final short IMG = ILAYER+1;
    public static final short IMAGE = IMG+1;
    public static final short INPUT = IMAGE+1;
    public static final short INS = INPUT+1;
    public static final short ISINDEX = INS+1;
    public static final short KBD = ISINDEX+1;
    public static final short KEYGEN = KBD+1;
    public static final short LABEL = KEYGEN+1;
    public static final short LAYER = LABEL+1;
    public static final short LEGEND = LAYER+1;
    public static final short LI = LEGEND+1;
    public static final short LINK = LI+1;
    public static final short LISTING = LINK+1;
    public static final short MAIN = LISTING+1;
    public static final short MAP = MAIN+1;
    public static final short MARQUEE = MAP+1;
    public static final short MENU = MARQUEE+1;
    public static final short META = MENU+1;
    public static final short MULTICOL = META+1;
    public static final short NAV = MULTICOL+1;
    public static final short NEXTID = NAV+1;
    public static final short NOBR = NEXTID+1;
    public static final short NOEMBED = NOBR+1;
    public static final short NOFRAMES = NOEMBED+1;
    public static final short NOLAYER = NOFRAMES+1;
    public static final short NOSCRIPT = NOLAYER+1;
    public static final short OBJECT = NOSCRIPT+1;
    public static final short OL = OBJECT+1;
    public static final short OPTGROUP = OL+1;
    public static final short OPTION = OPTGROUP+1;
    public static final short P = OPTION+1;
    public static final short PARAM = P+1;
    public static final short PLAINTEXT = PARAM+1;
    public static final short PRE = PLAINTEXT+1;
    public static final short Q = PRE+1;
    public static final short RB = Q+1;
    public static final short RBC = RB+1;
    public static final short RP = RBC+1;
    public static final short RT = RP+1;
    public static final short RTC = RT+1;
    public static final short RUBY = RTC+1;
    public static final short S = RUBY+1;
    public static final short SAMP = S+1;
    public static final short SCRIPT = SAMP+1;
    public static final short SECTION = SCRIPT+1;
    public static final short SELECT = SECTION+1;
    public static final short SMALL = SELECT+1;
    public static final short SOUND = SMALL+1;
    public static final short SOURCE = SOUND+1;
    public static final short SPACER = SOURCE+1;
    public static final short SPAN = SPACER+1;
    public static final short STRIKE = SPAN+1;
    public static final short STRONG = STRIKE+1;
    public static final short STYLE = STRONG+1;
    public static final short SUB = STYLE+1;
    public static final short SUMMARY = SUB+1;
    public static final short SUP = SUMMARY+1;
    public static final short SVG = SUP+1;
    public static final short TABLE = SVG+1;
    public static final short TBODY = TABLE+1;
    public static final short TD = TBODY+1;
    public static final short TEMPLATE = TD+1;
    public static final short TEXTAREA = TEMPLATE+1;
    public static final short TFOOT = TEXTAREA+1;
    public static final short TH = TFOOT+1;
    public static final short THEAD = TH+1;
    public static final short TITLE = THEAD+1;
    public static final short TR = TITLE+1;
    public static final short TRACK = TR+1;
    public static final short TT = TRACK+1;
    public static final short U = TT+1;
    public static final short UL = U+1;
    public static final short VAR = UL+1;
    public static final short WBR = VAR+1;
    public static final short XML = WBR+1;
    public static final short XMP = XML+1;
    public static final short UNKNOWN = XMP+1;

    // information

    /** No such element. */
    public final Element NO_SUCH_ELEMENT = new Element(UNKNOWN, "",  Element.CONTAINER, new short[]{BODY,HEAD}/*HTML*/, null);

    public final Map elementsByCode = new HashMap<>(256);

    public final Map elementsByName = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);

    //
    // Static initializer
    //

    public HTMLElements() {
        final Element[][] elementsArray = new Element[26][];
        // 
        // 
        // 
        // 
        // 
        // 
        // 
        // 

        // initialize array of element information
        elementsArray['A'-'A'] = new Element[] {
            // A - - (%inline;)* -(A)
            new Element(A, "A", Element.CONTAINER, BODY, new short[] {A}),
            // ABBR - - (%inline;)*
            new Element(ABBR, "ABBR", Element.INLINE, BODY, null),
            // ACRONYM - - (%inline;)*
            new Element(ACRONYM, "ACRONYM", Element.INLINE, BODY, null),
            // ADDRESS - - (%inline;)*
            new Element(ADDRESS, "ADDRESS", Element.BLOCK, BODY, new short[] {P}),
            // APPLET
            new Element(APPLET, "APPLET", Element.CONTAINER, BODY, null),
            // AREA - O EMPTY
            new Element(AREA, "AREA", Element.EMPTY, BODY, null),

            new Element(ARTICLE, "ARTICLE", Element.BLOCK, BODY, new short[] {P}),

            new Element(ASIDE, "ASIDE", Element.BLOCK, BODY, new short[] {P}),
        };
        elementsArray['B'-'A'] = new Element[] {
            // B - - (%inline;)*
            new Element(B, "B", Element.INLINE, BODY, new short[] {SVG}),
            // BASE - O EMPTY
            new Element(BASE, "BASE", Element.EMPTY, HEAD, null),
            // BASEFONT
            new Element(BASEFONT, "BASEFONT", Element.EMPTY, HEAD, null),
            // BDO - - (%inline;)*
            new Element(BDO, "BDO", Element.INLINE, BODY, null),
            // BGSOUND
            new Element(BGSOUND, "BGSOUND", Element.EMPTY, HEAD, null),
            // BIG - - (%inline;)*
            new Element(BIG, "BIG", Element.INLINE, BODY, new short[]{SVG}),
            // BLINK
            new Element(BLINK, "BLINK", Element.INLINE, BODY, null),
            // BLOCKQUOTE - - (%block;|SCRIPT)+
            new Element(BLOCKQUOTE, "BLOCKQUOTE", Element.BLOCK, BODY, new short[]{P,SVG}),
            // BODY O O (%block;|SCRIPT)+ +(INS|DEL)
            new Element(BODY, "BODY", Element.CONTAINER, HTML, new short[]{HEAD,SVG}),
            // BR - O EMPTY
            new Element(BR, "BR", Element.EMPTY, BODY, new short[]{SVG}),
            // BUTTON - - (%flow;)* -(A|%formctrl;|FORM|FIELDSET)
            new Element(BUTTON, "BUTTON", Element.INLINE | Element.BLOCK, BODY, new short[]{BUTTON}),
        };
        elementsArray['C'-'A'] = new Element[] {
            // CAPTION - - (%inline;)*
            new Element(CAPTION, "CAPTION", Element.INLINE, TABLE, null),
            // CENTER,
            new Element(CENTER, "CENTER", Element.CONTAINER, BODY, new short[] {P,SVG}),
            // CITE - - (%inline;)*
            new Element(CITE, "CITE", Element.INLINE, BODY, null),
            // CODE - - (%inline;)*
            new Element(CODE, "CODE", Element.INLINE, BODY, new short[]{SVG}),
            // COL - O EMPTY
            new Element(COL, "COL", Element.EMPTY, COLGROUP, null),
            // COLGROUP - O (COL)*
            new Element(COLGROUP, "COLGROUP", Element.CONTAINER, TABLE, new short[]{COL,COLGROUP}),
            // COMMENT
            new Element(COMMENT, "COMMENT", Element.SPECIAL, HTML, null),
        };
        elementsArray['D'-'A'] = new Element[] {
            // DEL - - (%flow;)*
            new Element(DEL, "DEL", Element.INLINE, BODY, null),

            new Element(DETAILS, "DETAILS", Element.BLOCK, BODY, new short[] {P}),
            // DFN - - (%inline;)*
            new Element(DFN, "DFN", Element.INLINE, BODY, null),
            // DIR
            new Element(DIR, "DIR", Element.CONTAINER, BODY, new short[] {P}),
            // DIV - - (%flow;)*
            new Element(DIV, "DIV", Element.CONTAINER, BODY, new short[]{P,SVG}),
            // DD - O (%flow;)*
            new Element(DD, "DD", Element.BLOCK, BODY, new short[]{DT,DD,P,SVG}),
            // DL - - (DT|DD)+
            new Element(DL, "DL", Element.BLOCK|Element.CONTAINER, BODY, new short[] {P,SVG}),
            // DT - O (%inline;)*
            new Element(DT, "DT", Element.BLOCK, BODY, new short[]{DT,DD,P,SVG}),
        };
        elementsArray['E'-'A'] = new Element[] {
            // EM - - (%inline;)*
            new Element(EM, "EM", Element.INLINE, BODY, new short[]{SVG}),
            // EMBED
            new Element(EMBED, "EMBED", Element.EMPTY, BODY, new short[]{SVG}),
        };
        elementsArray['F'-'A'] = new Element[] {
            // FIELDSET - - (#PCDATA,LEGEND,(%flow;)*)
            new Element(FIELDSET, "FIELDSET", Element.CONTAINER, BODY, new short[] {P}),

            new Element(FIGCAPTION, "FIGCAPTION", Element.BLOCK, BODY, new short[] {P}),

            new Element(FIGURE, "FIGURE", Element.BLOCK, BODY, new short[] {P}),
            // FONT
            new Element(FONT, "FONT", Element.CONTAINER, BODY, null),

            new Element(FOOTER, "FOOTER", Element.BLOCK, BODY, new short[] {P}),

            // FORM - - (%block;|SCRIPT)+ -(FORM)
            new Element(FORM, "FORM", Element.CONTAINER, new short[]{BODY,TD,DIV}, new short[]{P}),
            // FRAME - O EMPTY
            new Element(FRAME, "FRAME", Element.EMPTY, FRAMESET, null),
            // FRAMESET - - ((FRAMESET|FRAME)+ & NOFRAMES?)
            new Element(FRAMESET, "FRAMESET", Element.CONTAINER, HTML, null),
        };
        elementsArray['H'-'A'] = new Element[] {
            // (H1|H2|H3|H4|H5|H6) - - (%inline;)*
            new Element(H1, "H1", Element.BLOCK, new short[]{BODY,A}, new short[]{H1,H2,H3,H4,H5,H6,P,SVG}),
            new Element(H2, "H2", Element.BLOCK, new short[]{BODY,A}, new short[]{H1,H2,H3,H4,H5,H6,P,SVG}),
            new Element(H3, "H3", Element.BLOCK, new short[]{BODY,A}, new short[]{H1,H2,H3,H4,H5,H6,P,SVG}),
            new Element(H4, "H4", Element.BLOCK, new short[]{BODY,A}, new short[]{H1,H2,H3,H4,H5,H6,P,SVG}),
            new Element(H5, "H5", Element.BLOCK, new short[]{BODY,A}, new short[]{H1,H2,H3,H4,H5,H6,P,SVG}),
            new Element(H6, "H6", Element.BLOCK, new short[]{BODY,A}, new short[]{H1,H2,H3,H4,H5,H6,P,SVG}),
            // HEAD O O (%head.content;) +(%head.misc;)
            new Element(HEAD, "HEAD", 0, HTML, null),

            new Element(HEADER, "HEADER", Element.BLOCK, BODY, new short[] {P}),

            // HR - O EMPTY
            new Element(HR, "HR", Element.EMPTY, BODY, new short[]{P,SVG}),
            // HTML O O (%html.content;)
            new Element(HTML, "HTML", 0, null, null),
        };
        elementsArray['I'-'A'] = new Element[] {
            // I - - (%inline;)*
            new Element(I, "I", Element.INLINE, BODY, new short[]{SVG}),
            // IFRAME
            new Element(IFRAME, "IFRAME", Element.BLOCK, BODY, null),
            // ILAYER
            new Element(ILAYER, "ILAYER", Element.BLOCK, BODY, null),
            // IMG - O EMPTY
            new Element(IMG, "IMG", Element.EMPTY, BODY, new short[]{SVG}),

            new Element(IMAGE, "IMAGE", Element.EMPTY, BODY, null),
            // INPUT - O EMPTY
            new Element(INPUT, "INPUT", Element.EMPTY, BODY, null),
            // INS - - (%flow;)*
            new Element(INS, "INS", Element.INLINE, BODY, null),
            // ISINDEX
            new Element(ISINDEX, "ISINDEX", Element.BLOCK, BODY, new short[] {ISINDEX, P}),
        };
        elementsArray['K'-'A'] = new Element[] {
            // KBD - - (%inline;)*
            new Element(KBD, "KBD", Element.INLINE, BODY, null),
            // KEYGEN
            new Element(KEYGEN, "KEYGEN", Element.EMPTY, BODY, null),
        };
        elementsArray['L'-'A'] = new Element[] {
            // LABEL - - (%inline;)* -(LABEL)
            new Element(LABEL, "LABEL", Element.INLINE, BODY, null),
            // LAYER
            new Element(LAYER, "LAYER", Element.BLOCK, BODY, null),
            // LEGEND - - (%inline;)*
            new Element(LEGEND, "LEGEND", Element.INLINE, BODY, null),
            // LI - O (%flow;)*
            new Element(LI, "LI", Element.CONTAINER, new short[]{BODY,UL,OL,MENU}, new short[]{LI,P,SVG}),
            // LINK - O EMPTY
            new Element(LINK, "LINK", Element.EMPTY, HEAD, null),
            // LISTING
            new Element(LISTING, "LISTING", Element.BLOCK, BODY, new short[] {P,SVG}),
        };
        elementsArray['M'-'A'] = new Element[] {
            new Element(MAIN, "MAIN", Element.BLOCK, BODY, new short[] {P}),
            // MAP - - ((%block;) | AREA)+
            new Element(MAP, "MAP", Element.INLINE, BODY, null),
            // MARQUEE
            new Element(MARQUEE, "MARQUEE", Element.CONTAINER, BODY, null),
            // MENU
            new Element(MENU, "MENU", Element.CONTAINER, BODY, new short[] {P,SVG}),
            // META - O EMPTY
            new Element(META, "META", Element.EMPTY, HEAD, new short[]{STYLE,TITLE,SVG}),
            // MULTICOL
            new Element(MULTICOL, "MULTICOL", Element.CONTAINER, BODY, null),
        };
        elementsArray['N'-'A'] = new Element[] {
            new Element(NAV, "NAV", Element.BLOCK, BODY, new short[] {P}),

            // NEXTID
            new Element(NEXTID, "NEXTID", Element.INLINE, BODY, null),
            // NOBR
            new Element(NOBR, "NOBR", Element.INLINE, BODY, new short[]{NOBR,SVG}),
            // NOEMBED
            new Element(NOEMBED, "NOEMBED", Element.CONTAINER, BODY, null),
            // NOFRAMES - - (BODY) -(NOFRAMES)
            new Element(NOFRAMES, "NOFRAMES", Element.CONTAINER, null, null),
            // NOLAYER
            new Element(NOLAYER, "NOLAYER", Element.CONTAINER, BODY, null),
            // NOSCRIPT - - (%block;)+
            new Element(NOSCRIPT, "NOSCRIPT", Element.CONTAINER, new short[]{BODY}, null),
        };
        elementsArray['O'-'A'] = new Element[] {
            // OBJECT - - (PARAM | %flow;)*
            new Element(OBJECT, "OBJECT", Element.CONTAINER, BODY, null),
            // OL - - (LI)+
            new Element(OL, "OL", Element.BLOCK, BODY, new short[] {P,SVG}),
            // OPTGROUP - - (OPTION)+
            new Element(OPTGROUP, "OPTGROUP", Element.INLINE, BODY, new short[]{OPTION}),
            // OPTION - O (#PCDATA)
            new Element(OPTION, "OPTION", Element.INLINE, BODY, new short[]{OPTION}),
        };
        elementsArray['P'-'A'] = new Element[] {
            // P - O (%inline;)*
            new Element(P, "P", Element.CONTAINER, BODY, new short[]{P,SVG}),
            // PARAM - O EMPTY
            new Element(PARAM, "PARAM", Element.EMPTY, HEAD, null),
            // PLAINTEXT
            new Element(PLAINTEXT, "PLAINTEXT", Element.SPECIAL, BODY, new short[]{P}),
            // PRE - - (%inline;)* -(%pre.exclusion;)
            new Element(PRE, "PRE", Element.BLOCK, BODY, new short[] {P,SVG}),
        };
        elementsArray['Q'-'A'] = new Element[] {
            // Q - - (%inline;)*
            new Element(Q, "Q", Element.INLINE, BODY, null),
        };
        elementsArray['R'-'A'] = new Element[] {
            // RB
            new Element(RB, "RB", Element.INLINE, RUBY, new short[]{RB}),
            // RBC
            new Element(RBC, "RBC", 0, RUBY, new short[]{SVG}),
            // RP
            new Element(RP, "RP", Element.INLINE, BODY, new short[]{RB}),
            // RT
            new Element(RT, "RT", Element.INLINE, BODY, new short[]{RB,RP}),
            // RTC
            new Element(RTC, "RTC", 0, RUBY, new short[]{RBC}),
            // RUBY
            new Element(RUBY, "RUBY", Element.CONTAINER, BODY, new short[]{SVG}),
        };
        elementsArray['S'-'A'] = new Element[] {
            // S
            new Element(S, "S", Element.INLINE, BODY, new short[]{SVG}),
            // SAMP - - (%inline;)*
            new Element(SAMP, "SAMP", Element.INLINE, BODY, null),
            // SCRIPT - - %Script;
            new Element(SCRIPT, "SCRIPT", Element.SPECIAL, new short[]{HEAD,BODY}, null),

            new Element(SECTION, "SECTION", Element.BLOCK, BODY, new short[]{SELECT, P}),
            // SELECT - - (OPTGROUP|OPTION)+
            new Element(SELECT, "SELECT", Element.CONTAINER, BODY, new short[]{SELECT}),
            // SMALL - - (%inline;)*
            new Element(SMALL, "SMALL", Element.INLINE, BODY, new short[]{SVG}),
            // SOUND
            new Element(SOUND, "SOUND", Element.EMPTY, HEAD, null),

            new Element(SOURCE, "SOURCE", Element.EMPTY, HEAD, null),
            // SPACER
            new Element(SPACER, "SPACER", Element.INLINE, BODY, null),
            // SPAN - - (%inline;)*
            new Element(SPAN, "SPAN", Element.CONTAINER, BODY, new short[]{SVG}),
            // STRIKE
            new Element(STRIKE, "STRIKE", Element.INLINE, BODY, null),
            // STRONG - - (%inline;)*
            new Element(STRONG, "STRONG", Element.INLINE, BODY, null),
            // STYLE - - %StyleSheet;
            new Element(STYLE, "STYLE", Element.SPECIAL, new short[]{HEAD,BODY}, new short[]{STYLE,TITLE,META}),
            // SUB - - (%inline;)*
            new Element(SUB, "SUB", Element.INLINE, BODY, null),

            new Element(SUMMARY, "SUMMARY", Element.BLOCK, BODY, new short[] {P}),
            // SUP - - (%inline;)*
            new Element(SUP, "SUP", Element.INLINE, BODY, null),

            // SVG - - (%SVG;)*
            new Element(SVG, "SVG", Element.CONTAINER, BODY, null),
        };
        elementsArray['T'-'A'] = new Element[] {
            // TABLE - - (CAPTION?, (COL*|COLGROUP*), THEAD?, TFOOT?, TBODY+)
            new Element(TABLE, "TABLE", Element.BLOCK|Element.CONTAINER, BODY, new short[]{SVG}),
            // TBODY O O (TR)+
            new Element(TBODY, "TBODY", 0, TABLE, new short[]{FORM,THEAD,TBODY,TFOOT,TD,TH,TR,COLGROUP}),
            // TD - O (%flow;)*
            new Element(TD, "TD", Element.CONTAINER, TR, TABLE, new short[]{TD,TH}),

            new Element(TEMPLATE, "TEMPLATE", Element.CONTAINER, BODY, null),
            // TEXTAREA - - (#PCDATA)
            new Element(TEXTAREA, "TEXTAREA", Element.SPECIAL, BODY, null),
            // TFOOT - O (TR)+
            new Element(TFOOT, "TFOOT", 0, TABLE, new short[]{THEAD,TBODY,TFOOT,TD,TH,TR}),
            // TH - O (%flow;)*
            new Element(TH, "TH", Element.CONTAINER, TR, TABLE, new short[]{TD,TH}),
            // THEAD - O (TR)+
            new Element(THEAD, "THEAD", 0, TABLE, new short[]{THEAD,TBODY,TFOOT,TD,TH,TR,COLGROUP}),
            // TITLE - - (#PCDATA) -(%head.misc;)
            new Element(TITLE, "TITLE", Element.SPECIAL, new short[]{HEAD,BODY}, null),
            // TR - O (TH|TD)+
            new Element(TR, "TR", Element.BLOCK, new short[]{TBODY, THEAD, TFOOT}, TABLE, new short[]{FORM,TD,TH,TR,COLGROUP,DIV}),

            new Element(TRACK, "TRACK", Element.EMPTY, HEAD, null),
            // TT - - (%inline;)*
            new Element(TT, "TT", Element.INLINE, BODY, new short[]{SVG}),
        };
        elementsArray['U'-'A'] = new Element[] {
            // U,
            new Element(U, "U", Element.INLINE, BODY, new short[]{SVG}),
            // UL - - (LI)+
            new Element(UL, "UL", Element.CONTAINER, BODY, new short[] {P,SVG}),
        };
        elementsArray['V'-'A'] = new Element[] {
            // VAR - - (%inline;)*
            new Element(VAR, "VAR", Element.INLINE, BODY, new short[]{SVG}),
        };
        elementsArray['W'-'A'] = new Element[] {
            // WBR
            new Element(WBR, "WBR", Element.EMPTY, BODY, null),
        };
        elementsArray['X'-'A'] = new Element[] {
            // XML
            new Element(XML, "XML", 0, BODY, null),
            // XMP
            new Element(XMP, "XMP", Element.SPECIAL, BODY, new short[] {P}),
        };

        // keep contiguous list of elements for lookups by code
        for (final Element[] elements : elementsArray) {
            if (elements != null) {
                for (final Element element : elements) {
                    elementsByCode.put(element.code, element);
                    elementsByName.put(element.name, element);
                }
            }
        }

        elementsByCode.put(NO_SUCH_ELEMENT.code, NO_SUCH_ELEMENT);

        // initialize cross references to parent elements
        for (final Element element : elementsByCode.values()) {
            defineParents(element);
        }
    }

    public void setElement(Element element) {
        elementsByCode.put(element.code, element);
        elementsByName.put(element.name, element);
        defineParents(element);
    }

    private void defineParents(final Element element) {
        if (element.parentCodes != null) {
            element.parent = new Element[element.parentCodes.length];
            for (int j = 0; j < element.parentCodes.length; j++) {
                element.parent[j] = elementsByCode.get(element.parentCodes[j]);
            }
            element.parentCodes = null;
        }
    }

    //
    // Public static methods
    //

    /**
     * @return the element information for the specified element code.
     *
     * @param code The element code.
     */
    public final Element getElement(final short code) {
        return elementsByCode.get(code);
    }

    /**
     * @return the element information for the specified element name.
     *
     * @param ename The element name.
     */
    public final Element getElement(final String ename) {
        Element element = getElement(ename, NO_SUCH_ELEMENT);
        if (element == NO_SUCH_ELEMENT) {
            element = new Element(UNKNOWN, ename.toUpperCase(Locale.ROOT),  Element.CONTAINER, new short[]{BODY,HEAD}/*HTML*/, null);
            element.parent = NO_SUCH_ELEMENT.parent;
            element.parentCodes = NO_SUCH_ELEMENT.parentCodes;
        }
        return element;
    }

    /**
     * @return the element information for the specified element name.
     *
     * @param ename The element name.
     * @param element The default element to return if not found.
     */
    public final Element getElement(final String ename, final Element element) {
        return elementsByName.getOrDefault(ename, element);
    }

    //
    // Classes
    //

    /**
     * Element information.
     *
     * @author Andy Clark
     */
    public static class Element {

        //
        // Constants
        //

        /** Inline element. */
        public static final int INLINE = 0x01;

        /** Block element. */
        public static final int BLOCK = 0x02;

        /** Empty element. */
        public static final int EMPTY = 0x04;

        /** Container element. */
        public static final int CONTAINER = 0x08;

        /** Special element. */
        public static final int SPECIAL = 0x10;

        //
        // Data
        //

        /** The element code. */
        public final short code;

        /** The element name. */
        public final String name;

        /** Informational flags. */
        public final int flags;

        /** Parent elements. */
        public short[] parentCodes;

        /** Parent elements. */
        public Element[] parent;

        /** The bounding element code. */
        public final short bounds;

        /** List of elements this element can close. */
        public final short[] closes;

        //
        // Constructors
        //

        /**
         * Constructs an element object.
         *
         * @param code The element code.
         * @param name The element name.
         * @param flags Informational flags
         * @param parent Natural closing parent name.
         * @param closes List of elements this element can close.
         */
        public Element(final short code, final String name, final int flags,
                final short parent, final short[] closes) {
            this(code, name, flags, new short[]{parent}, (short)-1, closes);
        }

        /**
         * Constructs an element object.
         *
         * @param code The element code.
         * @param name The element name.
         * @param flags Informational flags
         * @param parent Natural closing parent name.
         * @param bounds bounds
         * @param closes List of elements this element can close.
         */
        public Element(final short code, final String name, final int flags,
                final short parent, final short bounds, final short[] closes) {
            this(code, name, flags, new short[]{parent}, bounds, closes);
        }

        /**
         * Constructs an element object.
         *
         * @param code The element code.
         * @param name The element name.
         * @param flags Informational flags
         * @param parents Natural closing parent names.
         * @param closes List of elements this element can close.
         */
        public Element(final short code, final String name, final int flags,
                final short[] parents, final short[] closes) {
            this(code, name, flags, parents, (short)-1, closes);
        }

        /**
         * Constructs an element object.
         *
         * @param code The element code.
         * @param name The element name.
         * @param flags Informational flags
         * @param parents Natural closing parent names.
         * @param bounds bounds
         * @param closes List of elements this element can close.
         */
        public Element(final short code, final String name, final int flags,
                final short[] parents, final short bounds, final short[] closes) {
            this.code = code;
            this.name = name;
            this.flags = flags;
            this.parentCodes = parents;
            this.parent = null;
            this.bounds = bounds;
            this.closes = closes;
        }

        //
        // Public methods
        //

        /**
         * @return true if this element is an inline element.
         */
        public final boolean isInline() {
            return (flags & INLINE) != 0;
        }

        /**
         * @return true if this element is a block element.
         */
        public final boolean isBlock() {
            return (flags & BLOCK) != 0;
        }

        /**
         * @return true if this element is an empty element.
         */
        public final boolean isEmpty() {
            return (flags & EMPTY) != 0;
        }

        /**
         * @return true if this element is a container element.
         */
        public final boolean isContainer() {
            return (flags & CONTAINER) != 0;
        }

        /**
         * @return true if this element is special -- if its content
         * should be parsed ignoring markup.
         */
        public final boolean isSpecial() {
            return (flags & SPECIAL) != 0;
        }

        /**
         * @return true if this element can close the specified Element.
         *
         * @param tag The element.
         */
        public boolean closes(final short tag) {
            if (closes != null) {
                for (final short close : closes) {
                    if (close == tag) {
                        return true;
                    }
                }
            }
            return false;
        }

        //
        // Object methods
        //

        /**
         * @return a hash code for this object.
         */
        @Override
        public int hashCode() {
            return name.hashCode();
        }

        /**
         * @return true if the objects are equal.
         */
        @Override
        public boolean equals(final Object o) {
            if (o instanceof Element) {
                return name.equals(((Element)o).name);
            }
            return false;
        }

        /**
         * @return a simple representation to make debugging easier
         */
        @Override
        public String toString() {
            return super.toString() + "(name=" + name + ")";
        }

        /**
         * Indicates if the provided element is an accepted parent of current element
         * @param element the element to test for "paternity"
         * @return true if element belongs to the {@link #parent}
         */
        public boolean isParent(final Element element) {
            if (parent == null)
                return false;
            for (final Element element2 : parent) {
                if (element.code == element2.code)
                    return true;
            }
            return false;
        }
    }

    /** Unsynchronized list of elements. */
    public static class ElementList {

        //
        // Data
        //

        /** The size of the list. */
        public int size;

        /** The data in the list. */
        public Element[] data = new Element[120];

        //
        // Public methods
        //

        /**
         * Adds an element to list, resizing if necessary.
         * @param element element
         */
        public void addElement(final Element element) {
            if (size == data.length) {
                final Element[] newarray = new Element[size + 20];
                System.arraycopy(data, 0, newarray, 0, size);
                data = newarray;
            }
            data[size++] = element;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy