Skip to content

Commit 9ca5fd7

Browse files
committed
redo attribute selector parsing to include wq-name and modifier.
See https://www.w3.org/TR/2018/WD-selectors-4-20181121/#attribute-selectors
1 parent c8043c1 commit 9ca5fd7

File tree

9 files changed

+243
-101
lines changed

9 files changed

+243
-101
lines changed

org/w3c/css/parser/analyzer/CssParser.jj

Lines changed: 103 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1441,20 +1441,20 @@ void page_selector_list(AtRulePage pageRule) :
14411441
}
14421442
{
14431443
(
1444-
( ( n=ident() { ns = convertIdent(n.image); } ) ( ":" p=ident() { if (ps == null) { ps = new ArrayList(); } ps.add(":"+convertIdent(p.image)); } )* ) {
1444+
( ( n=ident() { ns = convertIdent(n.image); } ) ( ":" p=ident() { if (ps == null) { ps = new ArrayList<String>(); } ps.add(":"+convertIdent(p.image)); } )* ) {
14451445
pageRule.addSelector(ns, ps, ac);
14461446
ns = null; ps = null;
14471447
}
1448-
| ( ":" p=ident() { if (ps == null) { ps = new ArrayList(); } ps.add(":"+convertIdent(p.image)); } )+ {
1448+
| ( ":" p=ident() { if (ps == null) { ps = new ArrayList<String>(); } ps.add(":"+convertIdent(p.image)); } )+ {
14491449
pageRule.addSelector(null, ps, ac);
14501450
ps = null;
14511451
} ) ( <S> ) *
14521452
( <COMMA> ( <S> )* (
1453-
( ( n=ident() { ns = convertIdent(n.image); } ) ( ":" p=ident() { if (ps == null) { ps = new ArrayList(); } ps.add(":"+convertIdent(p.image)); } )* ) {
1453+
( ( n=ident() { ns = convertIdent(n.image); } ) ( ":" p=ident() { if (ps == null) { ps = new ArrayList<String>(); } ps.add(":"+convertIdent(p.image)); } )* ) {
14541454
pageRule.addSelector(ns, ps, ac);
14551455
ns = null; ps = null;
14561456
}
1457-
| ( ":" p=ident() { if (ps == null) { ps = new ArrayList(); } ps.add(":"+convertIdent(p.image)); } )+ {
1457+
| ( ":" p=ident() { if (ps == null) { ps = new ArrayList<String>(); } ps.add(":"+convertIdent(p.image)); } )+ {
14581458
pageRule.addSelector(null, ps, ac);
14591459
ps = null;
14601460
} ) ( <S> )* )*
@@ -2374,7 +2374,7 @@ void element_name(CssSelectors s) :
23742374
.addError(new CssError(getSourceFile(), getBeginLine(),
23752375
getBeginColumn(), getEndLine(), getEndColumn(),
23762376
new InvalidParamException("notversion",
2377-
"namespace", ac.getCssVersionString(), ac)));
2377+
sb.toString(), ac.getCssVersionString(), ac)));
23782378
removeThisRule();
23792379
} else if (n!=null) {
23802380
prefix = convertIdent(n.image);
@@ -2416,10 +2416,12 @@ void attrib(CssSelectors s) :
24162416
{
24172417
Token att = null;
24182418
Token val = null;
2419+
Token mod = null;
2420+
Token pre = null;
24192421
int selectorType = CssSelectors.ATTRIBUTE_ANY;
24202422
}
24212423
{
2422-
<LBRACKET> ( <S> )* att=ident() ( <S> )*
2424+
<LBRACKET> ( <S> )* ( LOOKAHEAD(2) (pre=ident() | pre=<ANY>)? "|" )? att=ident() ( <S> )*
24232425
( (<EQ> { selectorType = CssSelectors.ATTRIBUTE_EXACT; }
24242426
| <INCLUDES> { selectorType = CssSelectors.ATTRIBUTE_ONE_OF; }
24252427
| <DASHMATCH> { selectorType = CssSelectors.ATTRIBUTE_BEGIN; }
@@ -2432,76 +2434,104 @@ void attrib(CssSelectors s) :
24322434
| val=<STRING>
24332435
{ val.image = convertStringIndex(val.image, 1, val.image.length() -1, false);}
24342436
)
2435-
( <S> )* )?
2436-
<RBRACKET>
2437+
( LOOKAHEAD(2) ( <S> )+ mod=ident() )? ( <S> )* )?
2438+
<RBRACKET>
24372439
{
2438-
if (ac.getCssVersion() == CssVersion.CSS1) {
2439-
StringBuilder reason;
2440-
CssParseException cp;
2441-
ParseException p;
2442-
reason = new StringBuilder(" [");
2443-
if (att != null) {
2444-
reason.append(convertIdent(att.image));
2445-
}
2446-
if (val != null ) {
2447-
reason.append('=').append(val.image);
2448-
}
2449-
reason.append(']');
2450-
p = new ParseException(ac.getMsg().getString("parser.attrcss1")+
2451-
reason.toString());
2452-
cp = new CssParseException(p);
2453-
ac.getFrame()
2454-
.addError(new CssError(getSourceFile(), getBeginLine(),
2455-
getBeginColumn(), getEndLine(), getEndColumn(), cp));
2456-
removeThisRule();
2457-
}
2458-
if (selectorType == CssSelectors.ATTRIBUTE_ANY) {
2459-
try {
2460-
s.addAttribute(new AttributeAny(att.image.toLowerCase()));
2461-
// s.addAttribute(att.image.toLowerCase(), null, selectorType);
2462-
} catch (InvalidParamException e) {
2463-
removeThisRule();
2464-
ac.getFrame()
2465-
.addError(new CssError(getSourceFile(), getBeginLine(),
2466-
getBeginColumn(), getEndLine(), getEndColumn(), e));
2467-
}
2468-
} else {
2469-
AttributeSelector attribute;
2470-
switch(selectorType) {
2471-
case CssSelectors.ATTRIBUTE_BEGIN:
2472-
attribute = new AttributeBegin(att.image.toLowerCase(), val.image);
2473-
break;
2474-
case CssSelectors.ATTRIBUTE_EXACT:
2475-
attribute = new AttributeExact(att.image.toLowerCase(), val.image);
2476-
break;
2477-
case CssSelectors.ATTRIBUTE_ONE_OF:
2478-
attribute = new AttributeOneOf(ac, att.image.toLowerCase(), val.image);
2479-
break;
2480-
case CssSelectors.ATTRIBUTE_START:
2481-
attribute = new AttributeStart(att.image.toLowerCase(), val.image);
2482-
break;
2483-
case CssSelectors.ATTRIBUTE_SUBSTR:
2484-
attribute = new AttributeSubstr(att.image.toLowerCase(), val.image);
2485-
break;
2486-
case CssSelectors.ATTRIBUTE_SUFFIX:
2487-
attribute = new AttributeSuffix(att.image.toLowerCase(), val.image);
2488-
break;
2489-
default:
2490-
attribute = new AttributeExact(att.image.toLowerCase(), val.image);
2491-
break;
2492-
}
2493-
try {
2494-
s.addAttribute(attribute);
2440+
if (ac.getCssVersion() == CssVersion.CSS1) {
2441+
StringBuilder reason;
2442+
CssParseException cp;
2443+
ParseException p;
2444+
reason = new StringBuilder(" [");
2445+
if (att != null) {
2446+
reason.append(convertIdent(att.image));
2447+
}
2448+
if (val != null ) {
2449+
reason.append('=').append(val.image);
2450+
}
2451+
reason.append(']');
2452+
p = new ParseException(ac.getMsg().getString("parser.attrcss1")+
2453+
reason.toString());
2454+
cp = new CssParseException(p);
2455+
ac.getFrame().addError(new CssError(getSourceFile(), getBeginLine(),
2456+
getBeginColumn(), getEndLine(), getEndColumn(), cp));
2457+
removeThisRule();
2458+
}
2459+
if ((mod != null) && ac.getCssVersion().compareTo(CssVersion.CSS3) < 0) {
2460+
String reason = mod.image;
2461+
ac.getFrame().addError(new CssError(getSourceFile(), getBeginLine(),
2462+
getBeginColumn(), getEndLine(), getEndColumn(),
2463+
new InvalidParamException("notversion",
2464+
reason, ac.getCssVersionString(), ac)));
2465+
2466+
removeThisRule();
2467+
}
2468+
if ((pre != null) && ac.getCssVersion().compareTo(CssVersion.CSS3) < 0) {
2469+
StringBuilder sb = new StringBuilder("namespace \"").append(pre.image).append('"');
2470+
ac.getFrame().addError(new CssError(getSourceFile(), getBeginLine(),
2471+
getBeginColumn(), getEndLine(), getEndColumn(),
2472+
new InvalidParamException("notversion",
2473+
sb.toString(), ac.getCssVersionString(), ac)));
2474+
removeThisRule();
2475+
}
2476+
if (selectorType == CssSelectors.ATTRIBUTE_ANY) {
2477+
try {
2478+
AttributeSelector as;
2479+
as = new AttributeAny(att.image.toLowerCase());
2480+
if (pre != null) {
2481+
as.setPrefix(pre.image);
2482+
}
2483+
if (mod != null) {
2484+
as.setModifier(mod.image, ac);
2485+
}
2486+
s.addAttribute(as);
2487+
// s.addAttribute(att.image.toLowerCase(), null, selectorType);
2488+
} catch (InvalidParamException e) {
2489+
removeThisRule();
2490+
ac.getFrame().addError(new CssError(getSourceFile(), getBeginLine(),
2491+
getBeginColumn(), getEndLine(), getEndColumn(), e));
2492+
}
2493+
} else {
2494+
AttributeSelector attribute;
2495+
switch(selectorType) {
2496+
case CssSelectors.ATTRIBUTE_BEGIN:
2497+
attribute = new AttributeBegin(att.image.toLowerCase(), val.image);
2498+
break;
2499+
case CssSelectors.ATTRIBUTE_EXACT:
2500+
attribute = new AttributeExact(att.image.toLowerCase(), val.image);
2501+
break;
2502+
case CssSelectors.ATTRIBUTE_ONE_OF:
2503+
attribute = new AttributeOneOf(ac, att.image.toLowerCase(), val.image);
2504+
break;
2505+
case CssSelectors.ATTRIBUTE_START:
2506+
attribute = new AttributeStart(att.image.toLowerCase(), val.image);
2507+
break;
2508+
case CssSelectors.ATTRIBUTE_SUBSTR:
2509+
attribute = new AttributeSubstr(att.image.toLowerCase(), val.image);
2510+
break;
2511+
case CssSelectors.ATTRIBUTE_SUFFIX:
2512+
attribute = new AttributeSuffix(att.image.toLowerCase(), val.image);
2513+
break;
2514+
default:
2515+
attribute = new AttributeExact(att.image.toLowerCase(), val.image);
2516+
break;
2517+
}
2518+
try {
2519+
if (pre != null) {
2520+
attribute.setPrefix(pre.image);
2521+
}
2522+
if (mod != null) {
2523+
attribute.setModifier(mod.image, ac);
2524+
}
2525+
s.addAttribute(attribute);
24952526
// s.addAttribute(att.image.toLowerCase(), val.image,
24962527
// selectorType);
2497-
} catch (InvalidParamException e) {
2498-
removeThisRule();
2499-
ac.getFrame()
2500-
.addError(new CssError(getSourceFile(), getBeginLine(),
2501-
getBeginColumn(), getEndLine(), getEndColumn(), e));
2502-
}
2503-
}
2504-
}
2528+
} catch (InvalidParamException e) {
2529+
removeThisRule();
2530+
ac.getFrame().addError(new CssError(getSourceFile(), getBeginLine(),
2531+
getBeginColumn(), getEndLine(), getEndColumn(), e));
2532+
}
2533+
}
2534+
}
25052535
}
25062536

25072537
void negation(CssSelectors s) :

org/w3c/css/selectors/AttributeSelector.java

Lines changed: 91 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,29 @@
55
package org.w3c.css.selectors;
66

77
import org.w3c.css.util.ApplContext;
8+
import org.w3c.css.util.InvalidParamException;
89

910
/**
1011
* Attribute<br />
1112
* Created: Sep 1, 2005 3:39:15 PM<br />
1213
*/
1314
public abstract class AttributeSelector implements Selector {
14-
15+
private String prefix;
1516
private String name;
17+
private String modifier;
18+
private String _prefixed_name = null;
19+
private String _ending_string = null;
20+
21+
static final String[] allowed_modifier = {"i", "s"};
22+
23+
static final boolean isValidModifier(String modifier) {
24+
for (String s : allowed_modifier) {
25+
if (s.equals(modifier)) {
26+
return true;
27+
}
28+
}
29+
return false;
30+
}
1631

1732
/**
1833
* Creates a new empty attribute selector
@@ -26,7 +41,22 @@ public AttributeSelector() {
2641
* @param name the name of this attribute
2742
*/
2843
public AttributeSelector(String name) {
44+
this(name, null, null);
45+
}
46+
47+
/**
48+
* Creates a new attribute selector given its name
49+
*
50+
* @param name the name of this attribute
51+
*/
52+
public AttributeSelector(String name, String prefix, String modifier) {
2953
this.name = name;
54+
this.prefix = prefix;
55+
this.modifier = modifier;
56+
}
57+
58+
public AttributeSelector(String name, String prefix) {
59+
this(name, prefix, null);
3060
}
3161

3262
/**
@@ -36,6 +66,7 @@ public AttributeSelector(String name) {
3666
*/
3767
public void setName(String name) {
3868
this.name = name;
69+
_prefixed_name = null;
3970
}
4071

4172
/**
@@ -45,14 +76,71 @@ public String getName() {
4576
return name;
4677
}
4778

79+
/**
80+
* Sets the namespace prefix of this attribute selector
81+
*
82+
* @param prefix the name of this attribute
83+
*/
84+
public void setPrefix(String prefix) {
85+
this.prefix = prefix;
86+
_prefixed_name = null;
87+
}
88+
89+
90+
public String getPrefix() {
91+
return prefix;
92+
}
93+
94+
/**
95+
* Sets the modifier of this attribute selector
96+
*
97+
* @param modifier the name of this attribute
98+
*/
99+
public void setModifier(String modifier, ApplContext ac)
100+
throws InvalidParamException {
101+
if (!isValidModifier(modifier)) {
102+
throw new InvalidParamException("value", modifier, getPrefixedName(), ac);
103+
}
104+
this.modifier = modifier;
105+
}
106+
107+
108+
public String getModifier() {
109+
return modifier;
110+
}
111+
48112
public abstract void applyAttribute(ApplContext ac, AttributeSelector attr);
49113

114+
public String getPrefixedName() {
115+
if (_prefixed_name == null) {
116+
if (prefix == null) {
117+
_prefixed_name = name;
118+
} else {
119+
StringBuilder sb = new StringBuilder();
120+
_prefixed_name = sb.append(prefix).append('|').append(name).toString();
121+
}
122+
}
123+
return _prefixed_name;
124+
}
125+
126+
public String getEndingString() {
127+
if (_ending_string == null) {
128+
if (modifier == null) {
129+
_ending_string = "]";
130+
} else {
131+
StringBuilder sb = new StringBuilder();
132+
_ending_string = sb.append(" ").append(modifier).append(']').toString();
133+
}
134+
}
135+
return _ending_string;
136+
}
137+
50138
/**
51139
* @see Selector#toString()
52140
*/
53141
public String toString() {
54142
StringBuilder sb = new StringBuilder();
55-
return sb.append('[').append(name).append(']').toString();
143+
sb.append('[').append(getPrefixedName()).append(getEndingString());
144+
return sb.toString();
56145
}
57-
58146
}

org/w3c/css/selectors/attributes/AttributeAny.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ public AttributeAny(String name) {
1818
super(name);
1919
}
2020

21+
public AttributeAny(String name, String prefix) {
22+
super(name, prefix);
23+
}
24+
2125
public boolean canApply(Selector other) {
2226
return true;
2327
}

org/w3c/css/selectors/attributes/AttributeBegin.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ public AttributeBegin(String name, String value) {
2121
this.value = value;
2222
}
2323

24+
public AttributeBegin(String name, String value, String prefix) {
25+
setName(name);
26+
this.value = value;
27+
setPrefix(prefix);
28+
29+
}
30+
2431
/**
2532
* @return Returns the value.
2633
*/
@@ -95,7 +102,9 @@ public void applyAttribute(ApplContext ac, AttributeSelector attr) {
95102

96103
public String toString() {
97104
StringBuilder sb = new StringBuilder();
98-
sb.append('[').append(getName()).append("|=\"").append(value).append("\"]");
105+
sb.append('[').append(getPrefixedName());
106+
sb.append("|=\"").append(value).append('"');
107+
sb.append(getEndingString());
99108
return sb.toString();
100109
}
101110

0 commit comments

Comments
 (0)