1:
37:
38: package ;
39:
40: import ;
41: import ;
42: import ;
43: import ;
44: import ;
45: import ;
46: import ;
47: import ;
48: import ;
49: import ;
50: import ;
51:
52:
57: public final class Selector
58: extends Path
59: {
60:
61: public static final int ANCESTOR = 0;
62: public static final int ANCESTOR_OR_SELF = 1;
63: public static final int ATTRIBUTE = 2;
64: public static final int CHILD = 3;
65: public static final int DESCENDANT = 4;
66: public static final int DESCENDANT_OR_SELF = 5;
67: public static final int FOLLOWING = 6;
68: public static final int FOLLOWING_SIBLING = 7;
69: public static final int NAMESPACE = 8;
70: public static final int PARENT = 9;
71: public static final int PRECEDING = 10;
72: public static final int PRECEDING_SIBLING = 11;
73: public static final int SELF = 12;
74:
75:
78: final int axis;
79:
80:
83: final Test[] tests;
84:
85: public Selector(int axis, List tests)
86: {
87: this.axis = axis;
88: this.tests = new Test[tests.size()];
89: tests.toArray(this.tests);
90: if (axis == NAMESPACE &&
91: this.tests.length > 0 &&
92: this.tests[0] instanceof NameTest)
93: {
94: NameTest nt = (NameTest) this.tests[0];
95: this.tests[0] = new NamespaceTest(nt.qName, nt.anyLocalName, nt.any);
96: }
97: }
98:
99:
102: public Test[] getTests()
103: {
104: return tests;
105: }
106:
107: public boolean matches(Node context)
108: {
109: short nodeType = context.getNodeType();
110: switch (axis)
111: {
112: case CHILD:
113: if (nodeType == Node.ATTRIBUTE_NODE)
114: {
115: return false;
116: }
117: break;
118: case ATTRIBUTE:
119: case NAMESPACE:
120: if (nodeType != Node.ATTRIBUTE_NODE)
121: {
122: return false;
123: }
124: break;
125: case DESCENDANT_OR_SELF:
126: return true;
127: default:
128: return false;
129: }
130: int tlen = tests.length;
131: if (tlen > 0)
132: {
133: int pos = getContextPosition(context);
134: int len = getContextSize(context);
135: for (int j = 0; j < tlen && len > 0; j++)
136: {
137: Test test = tests[j];
138: if (!test.matches(context, pos, len))
139: {
140: return false;
141: }
142: }
143: }
144: return true;
145: }
146:
147: private int getContextPosition(Node ctx)
148: {
149: int pos = 1;
150: for (ctx = ctx.getPreviousSibling(); ctx != null;
151: ctx = ctx.getPreviousSibling())
152: {
153: pos++;
154: }
155: return pos;
156: }
157:
158: private int getContextSize(Node ctx)
159: {
160: if (ctx.getNodeType() == Node.ATTRIBUTE_NODE)
161: {
162: Node parent = ((Attr) ctx).getOwnerElement();
163: return parent.getAttributes().getLength();
164: }
165: Node parent = ctx.getParentNode();
166: if (parent != null)
167: {
168: return parent.getChildNodes().getLength();
169: }
170: return 1;
171: }
172:
173: public Object evaluate(Node context, int pos, int len)
174: {
175: Set acc = new LinkedHashSet();
176: addCandidates(context, acc);
177: List candidates = new ArrayList(acc);
178:
179: List ret = filterCandidates(candidates, false);
180: return ret;
181: }
182:
183: Collection evaluate(Node context, Collection ns)
184: {
185: Set acc = new LinkedHashSet();
186: for (Iterator i = ns.iterator(); i.hasNext(); )
187: {
188: addCandidates((Node) i.next(), acc);
189: }
190: List candidates = new ArrayList(acc);
191:
192: List ret = filterCandidates(candidates, true);
193: return ret;
194: }
195:
196:
199: List filterCandidates(List candidates, boolean cascade)
200: {
201: int len = candidates.size();
202: int tlen = tests.length;
203: if (tlen > 0 && len > 0)
204: {
205:
206: for (int j = 0; j < tlen && len > 0; j++)
207: {
208: Test test = tests[j];
209: List successful = new ArrayList(len);
210: for (int i = 0; i < len; i++)
211: {
212: Node node = (Node) candidates.get(i);
213: if (cascade)
214: {
215:
216:
217:
218: short nodeType = node.getNodeType();
219: if ((nodeType == Node.DOCUMENT_NODE ||
220: nodeType == Node.DOCUMENT_FRAGMENT_NODE) &&
221: (axis == DESCENDANT_OR_SELF ||
222: axis == ANCESTOR_OR_SELF ||
223: axis == SELF) &&
224: (tests.length == 1 &&
225: tests[0] instanceof NodeTypeTest &&
226: ((NodeTypeTest) tests[0]).type == (short) 0))
227: {
228: successful.add(node);
229: continue;
230: }
231: }
232: if (test.matches(node, i + 1, len))
233: {
234: successful.add(node);
235: }
236:
244: }
245: candidates = successful;
246: len = candidates.size();
247: }
248: }
249: return candidates;
250: }
251:
252: void addCandidates(Node context, Collection candidates)
253: {
254:
255: switch (axis)
256: {
257: case CHILD:
258: addChildNodes(context, candidates, false);
259: break;
260: case DESCENDANT:
261: addChildNodes(context, candidates, true);
262: break;
263: case DESCENDANT_OR_SELF:
264: candidates.add (context);
265: addChildNodes(context, candidates, true);
266: break;
267: case PARENT:
268: addParentNode(context, candidates, false);
269: break;
270: case ANCESTOR:
271: addParentNode(context, candidates, true);
272: break;
273: case ANCESTOR_OR_SELF:
274: candidates.add(context);
275: addParentNode(context, candidates, true);
276: break;
277: case FOLLOWING_SIBLING:
278: addFollowingNodes(context, candidates, false);
279: break;
280: case PRECEDING_SIBLING:
281: addPrecedingNodes(context, candidates, false);
282: break;
283: case FOLLOWING:
284: addFollowingNodes(context, candidates, true);
285: break;
286: case PRECEDING:
287: addPrecedingNodes(context, candidates, true);
288: break;
289: case ATTRIBUTE:
290: addAttributes(context, candidates);
291: break;
292: case NAMESPACE:
293: addNamespaceAttributes(context, candidates);
294: break;
295: case SELF:
296: candidates.add(context);
297: break;
298: }
299: }
300:
301: void addChildNodes(Node context, Collection acc, boolean recurse)
302: {
303: Node child = context.getFirstChild();
304: while (child != null)
305: {
306: acc.add(child);
307: if (recurse)
308: {
309: addChildNodes(child, acc, recurse);
310: }
311: child = child.getNextSibling();
312: }
313: }
314:
315: void addParentNode(Node context, Collection acc, boolean recurse)
316: {
317: Node parent = (context.getNodeType() == Node.ATTRIBUTE_NODE) ?
318: ((Attr) context).getOwnerElement() : context.getParentNode();
319: if (parent != null)
320: {
321: acc.add(parent);
322: if (recurse)
323: {
324: addParentNode(parent, acc, recurse);
325: }
326: }
327: }
328:
329: void addFollowingNodes(Node context, Collection acc, boolean recurse)
330: {
331: Node cur = context.getNextSibling();
332: while (cur != null)
333: {
334: acc.add(cur);
335: if (recurse)
336: {
337: addChildNodes(cur, acc, true);
338: }
339: cur = cur.getNextSibling();
340: }
341: if (recurse)
342: {
343: context = (context.getNodeType() == Node.ATTRIBUTE_NODE) ?
344: ((Attr) context).getOwnerElement() : context.getParentNode();
345: if (context != null)
346: {
347: addFollowingNodes(context, acc, recurse);
348: }
349: }
350: }
351:
352: void addPrecedingNodes(Node context, Collection acc, boolean recurse)
353: {
354: Node cur = context.getPreviousSibling();
355: while (cur != null)
356: {
357: acc.add(cur);
358: if (recurse)
359: {
360: addChildNodes(cur, acc, true);
361: }
362: cur = cur.getPreviousSibling();
363: }
364: if (recurse)
365: {
366: context = (context.getNodeType() == Node.ATTRIBUTE_NODE) ?
367: ((Attr) context).getOwnerElement() : context.getParentNode();
368: if (context != null)
369: {
370: addPrecedingNodes(context, acc, recurse);
371: }
372: }
373: }
374:
375: void addAttributes(Node context, Collection acc)
376: {
377: NamedNodeMap attrs = context.getAttributes();
378: if (attrs != null)
379: {
380: int attrLen = attrs.getLength();
381: for (int i = 0; i < attrLen; i++)
382: {
383: Node attr = attrs.item(i);
384: if (!isNamespaceAttribute(attr))
385: {
386: acc.add(attr);
387: }
388: }
389: }
390: }
391:
392: void addNamespaceAttributes(Node context, Collection acc)
393: {
394: NamedNodeMap attrs = context.getAttributes();
395: if (attrs != null)
396: {
397: int attrLen = attrs.getLength();
398: for (int i = 0; i < attrLen; i++)
399: {
400: Node attr = attrs.item(i);
401: if (isNamespaceAttribute(attr))
402: {
403: acc.add(attr);
404: }
405: }
406: }
407: }
408:
409: final boolean isNamespaceAttribute(Node node)
410: {
411: String uri = node.getNamespaceURI();
412: return (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(uri) ||
413: XMLConstants.XMLNS_ATTRIBUTE.equals(node.getPrefix()) ||
414: XMLConstants.XMLNS_ATTRIBUTE.equals(node.getNodeName()));
415: }
416:
417: public Expr clone(Object context)
418: {
419: int len = tests.length;
420: List tests2 = new ArrayList(len);
421: for (int i = 0; i < len; i++)
422: {
423: tests2.add(tests[i].clone(context));
424: }
425: return new Selector(axis, tests2);
426: }
427:
428: public boolean references(QName var)
429: {
430: for (int i = 0; i < tests.length; i++)
431: {
432: if (tests[i].references(var))
433: {
434: return true;
435: }
436: }
437: return false;
438: }
439:
440: public String toString()
441: {
442: StringBuffer buf = new StringBuffer();
443: switch (axis)
444: {
445: case ANCESTOR:
446: buf.append("ancestor::");
447: break;
448: case ANCESTOR_OR_SELF:
449: buf.append("ancestor-or-self::");
450: break;
451: case ATTRIBUTE:
452: if (tests.length == 0 ||
453: (tests[0] instanceof NameTest))
454: {
455: buf.append('@');
456: }
457: else
458: {
459: buf.append("attribute::");
460: }
461: break;
462: case CHILD:
463:
464: break;
465: case DESCENDANT:
466: buf.append("descendant::");
467: break;
468: case DESCENDANT_OR_SELF:
469: buf.append("descendant-or-self::");
470: break;
471: case FOLLOWING:
472: buf.append("following::");
473: break;
474: case FOLLOWING_SIBLING:
475: buf.append("following-sibling::");
476: break;
477: case NAMESPACE:
478: buf.append("namespace::");
479: break;
480: case PARENT:
481: if (tests.length == 0 ||
482: (tests[0] instanceof NodeTypeTest &&
483: ((NodeTypeTest) tests[0]).type == 0))
484: {
485: return "..";
486: }
487: buf.append("parent::");
488: break;
489: case PRECEDING:
490: buf.append("preceding::");
491: break;
492: case PRECEDING_SIBLING:
493: buf.append("preceding-sibling::");
494: break;
495: case SELF:
496: if (tests.length == 0 ||
497: (tests[0] instanceof NodeTypeTest &&
498: ((NodeTypeTest) tests[0]).type == 0))
499: {
500: return ".";
501: }
502: buf.append("self::");
503: break;
504: }
505: if (tests.length == 0)
506: {
507: buf.append('*');
508: }
509: else
510: {
511: for (int i = 0; i < tests.length; i++)
512: {
513: buf.append(tests[i]);
514: }
515: }
516: return buf.toString();
517: }
518:
519: }