Skip to content

Commit faba5d1

Browse files
[MOD] XQuery, parsing: node tests
1 parent 4f9d976 commit faba5d1

File tree

3 files changed

+98
-76
lines changed

3 files changed

+98
-76
lines changed

basex-core/src/main/java/org/basex/query/QueryParser.java

+44-75
Original file line numberDiff line numberDiff line change
@@ -2073,23 +2073,18 @@ private Test nodeTest(final NodeType type, final boolean all) throws QueryExcept
20732073
int p = pos;
20742074
if(consume('*')) {
20752075
p = pos;
2076-
if(consume(':')) {
2077-
if(!consume('*')) {
2078-
// name test: *:name
2079-
return new NameTest(new QNm(ncName(QNAME_X)), NamePart.LOCAL, type, sc.elemNS);
2080-
}
2076+
if(consume(':') && !consume('*')) {
2077+
// name test: *:name
2078+
return new NameTest(new QNm(ncName(QNAME_X)), NamePart.LOCAL, type, sc.elemNS);
20812079
}
20822080
// name test: *
20832081
pos = p;
20842082
return KindTest.get(type);
20852083
}
2086-
20872084
if(consume(EQNAME)) {
2085+
// name test: Q{uri}*
20882086
final byte[] uri = bracedURILiteral();
2089-
if(consume('*')) {
2090-
// name test: Q{uri}*
2091-
return new NameTest(new QNm(COLON, uri), NamePart.URI, type, sc.elemNS);
2092-
}
2087+
if(consume('*')) return new NameTest(new QNm(COLON, uri), NamePart.URI, type, sc.elemNS);
20932088
}
20942089
pos = p;
20952090

@@ -2098,23 +2093,23 @@ private Test nodeTest(final NodeType type, final boolean all) throws QueryExcept
20982093
if(name != null) {
20992094
p = pos;
21002095
if(all && wsConsumeWs(PAREN1)) {
2101-
// kind test
21022096
final NodeType nt = NodeType.find(name);
21032097
if(nt != null) {
2098+
// kind test
21042099
final Test test = kindTest(nt);
21052100
return test == null ? KindTest.get(nt) : test;
21062101
}
21072102
} else {
21082103
pos = p;
2104+
NamePart part = NamePart.FULL;
21092105
if(!name.hasPrefix() && consume(COLWC)) {
21102106
// name test: prefix:*
21112107
name = new QNm(concat(name.string(), COLON));
2112-
qnames.add(name, type == NodeType.ELEMENT, ii);
2113-
return new NameTest(name, NamePart.URI, type, sc.elemNS);
2108+
part = NamePart.URI;
21142109
}
21152110
// name test: prefix:name, name, Q{uri}name
21162111
qnames.add(name, type == NodeType.ELEMENT, ii);
2117-
return new NameTest(name, NamePart.FULL, type, sc.elemNS);
2112+
return new NameTest(name, part, type, sc.elemNS);
21182113
}
21192114
}
21202115
pos = p;
@@ -2309,10 +2304,10 @@ private Expr functionItem() throws QueryException {
23092304
body = enclosedExpr();
23102305
} else if(curr('{')) {
23112306
final InputInfo ii = info();
2312-
final QNm qnm = new QNm("arg");
2313-
final Var var = new Var(qnm, SeqType.ITEM_O, true, qc, sc, ii);
2307+
final QNm name = new QNm("arg");
2308+
final Var var = new Var(name, SeqType.ITEM_O, true, qc, sc, ii);
23142309
params = new Var[] { localVars.add(var) };
2315-
body = new CachedMap(ii, localVars.resolve(qnm, ii), enclosedExpr());
2310+
body = new CachedMap(ii, localVars.resolve(name, ii), enclosedExpr());
23162311
}
23172312
final VarScope vs = localVars.popContext();
23182313
if(body != null) return new Closure(info(), type, params, body, anns, global, vs);
@@ -3090,57 +3085,48 @@ private SeqType sequenceType() throws QueryException {
30903085
* @throws QueryException query exception
30913086
*/
30923087
private SeqType itemType() throws QueryException {
3093-
skipWs();
3094-
30953088
// parenthesized item type
3096-
if(consume(PAREN1)) {
3097-
final SeqType type = itemType();
3089+
if(wsConsume(PAREN1)) {
3090+
final SeqType st = itemType();
30983091
wsCheck(PAREN2);
3099-
return type;
3092+
return st;
31003093
}
31013094

3102-
// parse optional annotation and type name
3095+
// parse annotations and type name
31033096
final AnnList anns = annotations(false).check(false, false);
31043097
final QNm name = eQName(null, TYPEINVALID);
3105-
skipWs();
3106-
// check if name is followed by parentheses
3107-
final boolean func = curr('(');
31083098

3109-
// item type
3099+
// parse type
3100+
SeqType st = null;
31103101
Type type = null;
3111-
if(func) {
3112-
consume(PAREN1);
3113-
// item type
3114-
if(name.eq(AtomType.ITEM.qname())) type = AtomType.ITEM;
3115-
// node types
3116-
if(type == null) type = NodeType.find(name);
3117-
// function types
3118-
if(type == null) {
3119-
type = FuncType.find(name);
3120-
if(type != null) return functionTest(anns, type).seqType();
3102+
if(wsConsume(PAREN1)) {
3103+
// function type
3104+
type = FuncType.find(name);
3105+
if(type != null) return functionTest(anns, type).seqType();
3106+
// node type
3107+
type = NodeType.find(name);
3108+
if(type != null) {
3109+
// extended node type
3110+
if(!wsConsume(PAREN2)) st = SeqType.get(type, Occ.EXACTLY_ONE, kindTest((NodeType) type));
3111+
} else if(name.eq(AtomType.ITEM.qname())) {
3112+
// item type
3113+
type = AtomType.ITEM;
3114+
wsCheck(PAREN2);
31213115
}
31223116
// no type found
31233117
if(type == null) throw error(WHICHTYPE_X, FuncType.similar(name));
31243118
} else {
31253119
// attach default element namespace
31263120
if(!name.hasURI()) name.uri(sc.elemNS);
3127-
// atomic types
3121+
// atomic type
31283122
type = AtomType.find(name, false);
31293123
// no type found
31303124
if(type == null) throw error(TYPEUNKNOWN_X, AtomType.similar(name));
31313125
}
3132-
31333126
// annotations are not allowed for remaining types
31343127
if(!anns.isEmpty()) throw error(NOANN);
31353128

3136-
// atomic value, or closing parenthesis
3137-
if(!func || wsConsume(PAREN2)) return type.seqType();
3138-
3139-
// raise error if type different to node is not finalized by a parenthesis
3140-
if(!(type instanceof NodeType)) wsCheck(PAREN2);
3141-
3142-
// return type with an optional kind test for node types
3143-
return SeqType.get(type, Occ.EXACTLY_ONE, kindTest((NodeType) type));
3129+
return st != null ? st : type.seqType();
31443130
}
31453131

31463132
/**
@@ -3152,7 +3138,7 @@ private SeqType itemType() throws QueryException {
31523138
*/
31533139
private Type functionTest(final AnnList anns, final Type type) throws QueryException {
31543140
// wildcard
3155-
if(wsConsume(ASTERISK)) {
3141+
if(wsConsume(WILDCARD)) {
31563142
wsCheck(PAREN2);
31573143
return type;
31583144
}
@@ -3194,12 +3180,12 @@ private Test kindTest(final NodeType type) throws QueryException {
31943180
final Test tp;
31953181
switch(type) {
31963182
case DOCUMENT_NODE: tp = documentTest(); break;
3197-
case ELEMENT: tp = elemAttrTest(type); break;
3183+
case ELEMENT:
31983184
case ATTRIBUTE: tp = elemAttrTest(type); break;
3199-
case PROCESSING_INSTRUCTION: tp = piTest(); break;
3185+
case PROCESSING_INSTRUCTION: tp = piTest(); break;
32003186
case SCHEMA_ELEMENT:
32013187
case SCHEMA_ATTRIBUTE: tp = schemaTest(); break;
3202-
default: tp = null; break;
3188+
default: tp = null; break;
32033189
}
32043190
wsCheck(PAREN2);
32053191
return tp;
@@ -3238,37 +3224,20 @@ private Test schemaTest() throws QueryException {
32383224
* @throws QueryException query exception
32393225
*/
32403226
private Test elemAttrTest(final NodeType type) throws QueryException {
3241-
final Test test = nodeTest(type, true);
3242-
if(test != null) {
3243-
typeName(type);
3244-
return test;
3245-
}
3246-
final QNm name = eQName(type == NodeType.ELEMENT ? sc.elemNS : null, null);
3247-
if(name != null) {
3248-
typeName(type);
3249-
return Test.get(type, name, sc.elemNS);
3250-
}
3251-
return null;
3252-
}
3253-
3254-
/**
3255-
* Parses the "TypeName" rule.
3256-
* @param type node type
3257-
* @throws QueryException query exception
3258-
*/
3259-
private void typeName(final NodeType type) throws QueryException {
3260-
if(wsConsumeWs(COMMA)) {
3261-
final QNm tn = eQName(sc.elemNS, QNAME_X);
3262-
Type ann = ListType.find(tn);
3263-
if(ann == null) ann = AtomType.find(tn, true);
3264-
if(ann == null) throw error(TYPEUNDEF_X, AtomType.similar(tn));
3227+
final Test test = nodeTest(type, false);
3228+
if(test != null && wsConsumeWs(COMMA)) {
3229+
final QNm name = eQName(sc.elemNS, QNAME_X);
3230+
Type ann = ListType.find(name);
3231+
if(ann == null) ann = AtomType.find(name, true);
3232+
if(ann == null) throw error(TYPEUNDEF_X, AtomType.similar(name));
32653233
// parse (and ignore) optional question mark
32663234
if(type == NodeType.ELEMENT) wsConsume(QUESTION);
32673235
if(!ann.oneOf(AtomType.ANY_TYPE, AtomType.UNTYPED) && (type == NodeType.ELEMENT ||
32683236
!ann.oneOf(AtomType.ANY_SIMPLE_TYPE, AtomType.ANY_ATOMIC_TYPE, AtomType.UNTYPED_ATOMIC))) {
32693237
throw error(STATIC_X, ann);
32703238
}
32713239
}
3240+
return test;
32723241
}
32733242

32743243
/**

basex-core/src/main/java/org/basex/query/QueryText.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ public interface QueryText {
234234
/** Parser token. */ String PRAGMA = "(#";
235235
/** Parser token. */ String PRAGMA2 = "#)";
236236
/** Parser Token. */ String QUESTION = "?";
237-
/** Parser Token. */ String ASTERISK = "*";
237+
/** Parser Token. */ String WILDCARD = "*";
238238
/** Parser token. */ String FATARROW = "=>";
239239
/** Parser token. */ String THINARROW = "->";
240240
/** Parser token. */ String TERNARY1 = "??";

basex-core/src/test/java/org/basex/query/expr/XQuery4Test.java

+53
Original file line numberDiff line numberDiff line change
@@ -171,4 +171,57 @@ public final class XQuery4Test extends QueryPlanTest {
171171
error("0 -> Q{}unknown(?)", WHICHFUNC_X);
172172
error("let $_ := 0 return 0 -> $_()", INVFUNCITEM_X_X);
173173
}
174+
175+
/** Generalized element/attribute tests. */
176+
@Test public void elemAttrTest() {
177+
String prefix = "<xml:a/> instance of ";
178+
query(prefix + "element()", true);
179+
query(prefix + "element(*)", true);
180+
query(prefix + "element(*:a)", true);
181+
query(prefix + "element(xml:*)", true);
182+
query(prefix + "element(xml:a)", true);
183+
query(prefix + "element(Q{http://www.w3.org/XML/1998/namespace}a)", true);
184+
query(prefix + "element(Q{http://www.w3.org/XML/1998/namespace}*)", true);
185+
186+
query(prefix + "xs:string", false);
187+
query(prefix + "text()", false);
188+
query(prefix + "element(*:b)", false);
189+
query(prefix + "element(xsi:*)", false);
190+
query(prefix + "element(xml:b)", false);
191+
query(prefix + "element(xsi:a)", false);
192+
query(prefix + "element(Q{X}a)", false);
193+
query(prefix + "element(Q{http://www.w3.org/XML/1998/namespace}b)", false);
194+
195+
query(prefix + "element(*, xs:untyped)", true);
196+
query(prefix + "element(*, xs:anyType)", true);
197+
error(prefix + "element(*, xs:string)", STATIC_X);
198+
error(prefix + "element(*, xs:untypedAtomic)", STATIC_X);
199+
error(prefix + "element(*, xs:xyz)", TYPEUNDEF_X);
200+
201+
prefix = "<_ xml:a=''/>/@* instance of ";
202+
query(prefix + "attribute()", true);
203+
query(prefix + "attribute(*)", true);
204+
query(prefix + "attribute(*:a)", true);
205+
query(prefix + "attribute(xml:*)", true);
206+
query(prefix + "attribute(xml:a)", true);
207+
query(prefix + "attribute(Q{http://www.w3.org/XML/1998/namespace}a)", true);
208+
query(prefix + "attribute(Q{http://www.w3.org/XML/1998/namespace}*)", true);
209+
210+
query(prefix + "xs:string", false);
211+
query(prefix + "text()", false);
212+
query(prefix + "attribute(*:b)", false);
213+
query(prefix + "attribute(xsi:*)", false);
214+
query(prefix + "attribute(xml:b)", false);
215+
query(prefix + "attribute(xsi:a)", false);
216+
query(prefix + "attribute(Q{X}a)", false);
217+
query(prefix + "attribute(Q{http://www.w3.org/XML/1998/namespace}b)", false);
218+
219+
query(prefix + "attribute(*, xs:untyped)", true);
220+
query(prefix + "attribute(*, xs:anyType)", true);
221+
query(prefix + "attribute(*, xs:anySimpleType)", true);
222+
query(prefix + "attribute(*, xs:anyAtomicType)", true);
223+
query(prefix + "attribute(*, xs:untypedAtomic)", true);
224+
error(prefix + "attribute(*, xs:string)", STATIC_X);
225+
error(prefix + "attribute(*, xs:xyz)", TYPEUNDEF_X);
226+
}
174227
}

0 commit comments

Comments
 (0)