* xmlCompileIDCXPathPath: * @ctxt: the compilation context * * Compile the Path Pattern and generates a precompiled * form suitable for fast matching. * * [5] Path ::= ('.//')? ( Step '/' )* ( Step | '@' NameTest ) */
| 1312 | * [5] Path ::= ('.//')? ( Step '/' )* ( Step | '@' NameTest ) |
| 1313 | */ |
| 1314 | static void |
| 1315 | xmlCompileIDCXPathPath(xmlPatParserContextPtr ctxt) { |
| 1316 | SKIP_BLANKS; |
| 1317 | if (CUR == '/') { |
| 1318 | ERROR5(NULL, NULL, NULL, |
| 1319 | "Unexpected selection of the document root in '%s'.\n", |
| 1320 | ctxt->base); |
| 1321 | goto error; |
| 1322 | } |
| 1323 | ctxt->comp->flags |= PAT_FROM_CUR; |
| 1324 | |
| 1325 | if (CUR == '.') { |
| 1326 | /* "." - "self::node()" */ |
| 1327 | NEXT; |
| 1328 | SKIP_BLANKS; |
| 1329 | if (CUR == 0) { |
| 1330 | /* |
| 1331 | * Selection of the context node. |
| 1332 | */ |
| 1333 | PUSH(XML_OP_ELEM, NULL, NULL); |
| 1334 | return; |
| 1335 | } |
| 1336 | if (CUR != '/') { |
| 1337 | /* TODO: A more meaningful error message. */ |
| 1338 | ERROR5(NULL, NULL, NULL, |
| 1339 | "Unexpected token after '.' in '%s'.\n", ctxt->base); |
| 1340 | goto error; |
| 1341 | } |
| 1342 | /* "./" - "self::node()/" */ |
| 1343 | NEXT; |
| 1344 | SKIP_BLANKS; |
| 1345 | if (CUR == '/') { |
| 1346 | if (IS_BLANK_CH(PEEKPREV(1))) { |
| 1347 | /* |
| 1348 | * Disallow "./ /" |
| 1349 | */ |
| 1350 | ERROR5(NULL, NULL, NULL, |
| 1351 | "Unexpected '/' token in '%s'.\n", ctxt->base); |
| 1352 | goto error; |
| 1353 | } |
| 1354 | /* ".//" - "self:node()/descendant-or-self::node()/" */ |
| 1355 | PUSH(XML_OP_ANCESTOR, NULL, NULL); |
| 1356 | NEXT; |
| 1357 | SKIP_BLANKS; |
| 1358 | } |
| 1359 | if (CUR == 0) |
| 1360 | goto error_unfinished; |
| 1361 | } |
| 1362 | /* |
| 1363 | * Process steps. |
| 1364 | */ |
| 1365 | do { |
| 1366 | xmlCompileStepPattern(ctxt); |
| 1367 | if (ctxt->error != 0) |
| 1368 | goto error; |
| 1369 | SKIP_BLANKS; |
| 1370 | if (CUR != '/') |
| 1371 | break; |
no test coverage detected