Package io.sf.carte.doc.style.css.nsac
NSAC Base Extension
The base extension is intended to be an easy upgrade path for current SAC users,
providing an API that is very similar to SAC but is able to process modern selectors,
and supports recent syntax and units. The original SAC interfaces are on a package
under the org.w3c
hierarchy and cannot be modified directly, so a set of
interfaces that inherit from SAC was created under a new package called
nsac
(for Non-Standard Api for Css) in the doc.style.css
hierarchy of this project.
The New Interfaces
The modifications that the new interfaces introduce are basically the following:
LexicalUnit
: add new identifiers (constants) and the methodgetCssText()
. (see below )Selector
: add numeric identifiers for combinatorsSAC_SUBSEQUENT_SIBLING_SELECTOR
andSAC_COLUMN_COMBINATOR_SELECTOR
. Also add theSAC_SCOPE_SELECTOR
pseudo-selector, intended to be a placeholder for scope in an selector argument (like innot()
orhas()
).Condition
: add numeric identifiers forSAC_BEGINS_ATTRIBUTE_CONDITION
and others, includingSAC_PSEUDO_ELEMENT_CONDITION
. Pseudo-elements are handled as conditional selectors with this extension. Also, a newCondition.SAC_SELECTOR_ARGUMENT_CONDITION
identifier is introduced to support the newArgumentCondition
.- New
ArgumentCondition
(see below). - New methods added to
AttributeCondition
andPositionalCondition
(see below).
New Methods and Constants
Interface LexicalUnit
Constants
- Add identifiers for level 3-4 units like
SAC_CAP
. - Add
SAC_ELEMENT_REFERENCE
for images by element reference. - For unicode range wildcards, add
SAC_UNICODE_WILDCARD
. - Also add the following identifiers for
grid support:
SAC_LEFT_BRACKET
,SAC_RIGHT_BRACKET
andSAC_FR
(fr
flexible length unit). - Finally, two values that are non-conformant and intended to be used for
compatibility with the Internet Explorer browser:
SAC_COMPAT_IDENT
andSAC_COMPAT_PRIO
values (seeLexicalUnit
Extensions).
Method
String getCssText()
- Get a parsable representation of the unit. The serialization must only include this lexical unit, ignoring the next units if they exist.
Interface AttributeCondition
boolean hasFlag(Flag)
- Check for the given flag. Currently supports
CASE_I
for thei
flag (case insensitivity) andCASE_S
fors
.
Interface PositionalCondition
boolean isForwardCondition()
- Is this a forward condition? return
true
if this is a forward condition like:nth-child
(alsotrue
for:only-child
),false
otherwise (like in:nth-last-child
). boolean isOfType()
- Is this an of-type selector? This method only returns
true
if the selector has been explicitly declared to apply to the same type, like in:first-of-type
or:nth-of-type
. It should returnfalse
otherwise, for example for selectors likediv:nth-child(1 of div)
despite being equivalent todiv:first-of-type
. This method is possibly the same as the oldPositionalCondition.getType()
, but with a potentially different specification. int getFactor()
- Get the
An+B
expression factor (i.e. 'A'). Zero if there is no factor (or no expression). int getOffset()
- Get the
An+B
expression offset (i.e. 'B'). If there is no expression, it must return the positive integer position value (e.g.1
for:first-child
or:last-child
). SelectorList getOfList()
- Get the list of selectors that the child list have to match, or
null
if not specified. boolean hasArgument()
- Was the selector specified with an argument ?. Serves to tell apart selectors
that have no functional notation from their functional equivalents (like
:first-child
and:nth-child(1)
. boolean hasKeyword()
- Get whether the AnB expression was specified as a keyword (like
even
).
New Interface ArgumentCondition
String getName()
- Get the name of the condition, like
not
orhas
. SelectorList getSelectors()
- Get the selector list to which the condition has to be applied.
Other Changes to Current SAC Usage
Although the changes to SAC described so far are required to handle modern selectors, the NSAC API behaves differently in other aspects:
- The names of pseudo-classes are retrieved with the
AttributeCondition
'sgetLocalName()
method instead ofgetValue()
. This leavesgetValue()
to retrieve the pseudo-class argument if there is any, like in:dir(ltr)
. - The identifier
SAC_ANY_NODE_SELECTOR
is used for the universal selector, albeit it is still implemented as anElementSelector
with the*
local name. - Margin rules are handled through
startPage
andendPage
, as nested page rules. Not very elegant, but allows the reuse of the oldDocumentHandler
interface. - Implementations of
LexicalUnit
must provide a serialization of the value, at least forSAC_IDENT
andSAC_RGBCOLOR
values, available throughLexicalUnit2
's newgetCssText()
method. That serialization should be close to how the value was specified (for example, preserving hex or functional notation in rgb colors) but must parse without errors (except for compatibility values likeSAC_COMPAT_IDENT
).
Selector Serialization
Implementations of the selector interfaces are not required to provide a
toString()
serialization, although the reference implementation (the
doc.style.css.parser
package) does. It is not recommended to use it for
serialization, however, as it may not reflect namespace changes made after the parsing
took place (i.e. changing the namespace prefix). The rule serialization in the
Object Model implementation of css4j does account for that, and it does not use the
selector's toString()
.
If you combine NSAC with your own Object Model code, you may want to follow the same approach and serialize the selectors yourself.
The Parser Extensions
The previously described base SAC extensions allowed to handle level 4 selectors and
values. However, for the API to be of more general usefulness in real-world usage a few
methods were added to the Parser
interface.
Parser Flags
To let the parser be configurable, two methods were added to the Parser
interface:
void setFlag(Flag)
void unsetFlag(Flag)
where Flag
is a flag from an enumeration:
STARHACK
. WhenSTARHACK
is set, the parser will handle asterisk-prefixed property names as accepted names. This hack (that targets old IE browsers) is ubiquitous in present-day websites, and in plain SAC parsers it was producing 'unexpected character' errors because the property names are not valid according to the specification. However, these declarations weren't real mistakes and the style authors wanted them to be there.IEVALUES
accepts values with some IE hacks like IE expressions (progid included), and also values ending with\9
and\0
. The non-standard values produceLexicalUnit2.SAC_COMPAT_IDENT
values as a result.IEPRIO
accepts values with the!ie
priority hack, and again producesLexicalUnit2.SAC_COMPAT_IDENT
values.IEPRIOCHAR
accepts values with the!important!
priority hack, and instead producesLexicalUnit2.SAC_COMPAT_PRIO
values.
Rule Parsing
The original SAC api includes this method:
void parseRule(InputSource)
The method can be used to parse individual rules, like those supplied to the CSSOM's
CSSStyleSheet.insertRule
method:
int insertRule(String, int)
However, when a rule that contains a namespace prefix is parsed, the style sheet may
contain the appropriate CSSNamespaceRule
for that prefix, but it is
unclear why/how the Parser
instance is going to know about it. To be able
to handle that case, NSAC adds the following method to the Parser
interface:
void parseRule(InputSource, NamespaceMap)
where NamespaceMap
is a simple sub-interface that just gives the namespace
URI associated to a prefix:
String getNamespaceURI(String)
LexicalUnit
Extensions
Some of the above Internet Explorer compatibility flags require the use of two pseudo-values that do not follow standard CSS syntax:
SAC_COMPAT_IDENT
values are produced only when theIEVALUES
andIEPRIO
flags are used, and contain ident-like values.SAC_COMPAT_PRIO
values are produced by theIEPRIOCHAR
flag, representing values that its compatible browser interprets as being of!important
priority.
Caution is advised when using these compatibility pseudo-values, as they may conflict with syntax-conformant values.
Bugs
While this API offers an useful improvement to SAC, that API is old and is showing its age; when it was written, CSS was simpler and smaller than it is today. As this API reuses from SAC as much as possible there are obvious limitations with this approach, like:
DocumentHandler.ignorableAtRule
is a big hammer and not appropriate for today's variety of rules. For example, for@supports
rules it would be better to have specializedstartSupports
andendSupports
methods than going throughignorableAtRule
.- Media queries are unparsed and passed as plain media declarations.
- Combinator selector interfaces were reused, avoiding the creation of a new
interface (like e.g. a plain
CombinatorSelector
interface). Again, this is not elegant but this API tries to depart minimally from SAC (and this kind of interface reuse was already being done by other SAC implementations).
W3C Copyright Notice
This software includes material derived from SAC (https://www.w3.org/TR/SAC/). Copyright © 1999,2000 W3C® (MIT, INRIA, Keio).
-
ClassDescriptionA condition is applied to a list of selectors that is supplied as an argument to the selector name.Refines SAC's
AttributeCondition
interface.Attribute selector flags.Updates SAC'sCondition
interface.Namespace-related parse exception.Updates SAC'sLexicalUnit
interface.Updates SAC'sParser
interface.NSAC parser flags: theParser2.Flag.STARHACK
,Parser2.Flag.IEVALUES
,Parser2.Flag.IEPRIO
andParser2.Flag.IEPRIOCHAR
flags are supported.Interface giving access to namespace URI from the prefix.Updates SAC'sPositionalCondition
interface.Updates SAC'sSelector
interface.