net.sourceforge.htmlunit.cyberneko.HTMLElements Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of com.liferay.diff.impl
Show all versions of com.liferay.diff.impl
Liferay Diff Implementation
The 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;
}
}
}