1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.commons.jxpath.ri.model;
17
18 import org.apache.commons.jxpath.AbstractFactory;
19 import org.apache.commons.jxpath.IdentityManager;
20 import org.apache.commons.jxpath.JXPathContext;
21 import org.apache.commons.jxpath.JXPathException;
22 import org.apache.commons.jxpath.JXPathTestCase;
23 import org.apache.commons.jxpath.Pointer;
24 import org.apache.commons.jxpath.Variables;
25 import org.apache.commons.jxpath.xml.DocumentContainer;
26
27 /***
28 * Abstract superclass for pure XPath 1.0. Subclasses
29 * apply the same XPaths to contexts using different models:
30 * DOM, JDOM etc.
31 *
32 * @author Dmitri Plotnikov
33 * @version $Revision: 1.23 $ $Date: 2004/06/30 00:29:13 $
34 */
35
36 public abstract class XMLModelTestCase extends JXPathTestCase {
37 protected JXPathContext context;
38
39 /***
40 * Construct a new instance of this test case.
41 *
42 * @param name Name of the test case
43 */
44 public XMLModelTestCase(String name) {
45 super(name);
46 }
47
48 public void setUp() {
49 if (context == null) {
50 DocumentContainer docCtr = createDocumentContainer();
51 context = createContext();
52 Variables vars = context.getVariables();
53 vars.declareVariable("document", docCtr.getValue());
54 vars.declareVariable("container", docCtr);
55 vars.declareVariable(
56 "element",
57 context.getPointer("vendor/location/address/street").getNode());
58 }
59 }
60
61 protected abstract String getModel();
62
63 protected DocumentContainer createDocumentContainer() {
64 return new DocumentContainer(
65 JXPathTestCase.class.getResource("Vendor.xml"),
66 getModel());
67 }
68
69 protected abstract AbstractFactory getAbstractFactory();
70
71 protected JXPathContext createContext() {
72 JXPathContext context =
73 JXPathContext.newContext(createDocumentContainer());
74 context.setFactory(getAbstractFactory());
75 context.registerNamespace("product", "productNS");
76 return context;
77 }
78
79 /***
80 * An XML signature is used to determine if we have the right result
81 * after a modification of XML by JXPath. It is basically a piece
82 * of simplified XML.
83 */
84 protected abstract String getXMLSignature(
85 Object node,
86 boolean elements,
87 boolean attributes,
88 boolean text,
89 boolean pi);
90
91 protected void assertXMLSignature(
92 JXPathContext context,
93 String path,
94 String signature,
95 boolean elements,
96 boolean attributes,
97 boolean text,
98 boolean pi)
99 {
100 Object node = context.getPointer(path).getNode();
101 String sig = getXMLSignature(node, elements, attributes, text, pi);
102 assertEquals("XML Signature mismatch: ", signature, sig);
103 }
104
105
106
107 public void testDocumentOrder() {
108 assertDocumentOrder(
109 context,
110 "vendor/location",
111 "vendor/location/address/street",
112 -1);
113
114 assertDocumentOrder(
115 context,
116 "vendor/location[@id = '100']",
117 "vendor/location[@id = '101']",
118 -1);
119
120 assertDocumentOrder(
121 context,
122 "vendor//price:amount",
123 "vendor/location",
124 1);
125 }
126
127
128 public void testSetValue() {
129 assertXPathSetValue(
130 context,
131 "vendor/location[@id = '100']",
132 "New Text");
133
134 assertXMLSignature(
135 context,
136 "vendor/location[@id = '100']",
137 "<E>New Text</E>",
138 false,
139 false,
140 true,
141 false);
142
143 assertXPathSetValue(
144 context,
145 "vendor/location[@id = '101']",
146 "Replacement Text");
147
148 assertXMLSignature(
149 context,
150 "vendor/location[@id = '101']",
151 "<E>Replacement Text</E>",
152 false,
153 false,
154 true,
155 false);
156 }
157
158 /***
159 * Test JXPathContext.createPath() with various arguments
160 */
161 public void testCreatePath() {
162
163 assertXPathCreatePath(
164 context,
165 "/vendor[1]/location[3]",
166 "",
167 "/vendor[1]/location[3]");
168
169
170 assertXPathCreatePath(
171 context,
172 "/vendor[1]/location[3]/address/street",
173 "",
174 "/vendor[1]/location[3]/address[1]/street[1]");
175
176
177 assertXPathCreatePath(
178 context,
179 "/vendor[1]/location[2]/@manager",
180 "",
181 "/vendor[1]/location[2]/@manager");
182
183 assertXPathCreatePath(
184 context,
185 "/vendor[1]/location[1]/@name",
186 "local",
187 "/vendor[1]/location[1]/@name");
188
189 assertXPathCreatePathAndSetValue(
190 context,
191 "/vendor[1]/location[4]/@manager",
192 "",
193 "/vendor[1]/location[4]/@manager");
194
195 context.registerNamespace("price", "priceNS");
196
197
198 assertXPathCreatePath(
199 context,
200 "/vendor[1]/price:foo/price:bar",
201 "",
202 "/vendor[1]/price:foo[1]/price:bar[1]");
203 }
204
205 /***
206 * Test JXPath.createPathAndSetValue() with various arguments
207 */
208 public void testCreatePathAndSetValue() {
209
210 assertXPathCreatePathAndSetValue(
211 context,
212 "vendor/location[3]",
213 "",
214 "/vendor[1]/location[3]");
215
216
217 assertXPathCreatePathAndSetValue(
218 context,
219 "vendor/location[3]/address/street",
220 "Lemon Circle",
221 "/vendor[1]/location[3]/address[1]/street[1]");
222
223
224 assertXPathCreatePathAndSetValue(
225 context,
226 "vendor/location[2]/@manager",
227 "John Doe",
228 "/vendor[1]/location[2]/@manager");
229
230 assertXPathCreatePathAndSetValue(
231 context,
232 "vendor/location[1]/@manager",
233 "John Doe",
234 "/vendor[1]/location[1]/@manager");
235
236 assertXPathCreatePathAndSetValue(
237 context,
238 "/vendor[1]/location[4]/@manager",
239 "James Dow",
240 "/vendor[1]/location[4]/@manager");
241
242 assertXPathCreatePathAndSetValue(
243 context,
244 "vendor/product/product:name/attribute::price:language",
245 "English",
246 "/vendor[1]/product[1]/product:name[1]/@price:language");
247
248 context.registerNamespace("price", "priceNS");
249
250
251 assertXPathCreatePathAndSetValue(
252 context,
253 "/vendor[1]/price:foo/price:bar",
254 "123.20",
255 "/vendor[1]/price:foo[1]/price:bar[1]");
256 }
257
258 /***
259 * Test JXPathContext.removePath() with various arguments
260 */
261 public void testRemovePath() {
262
263 context.removePath("vendor/location[@id = '101']//street/text()");
264 assertEquals(
265 "Remove DOM text",
266 "",
267 context.getValue("vendor/location[@id = '101']//street"));
268
269 context.removePath("vendor/location[@id = '101']//street");
270 assertEquals(
271 "Remove DOM element",
272 new Double(0),
273 context.getValue("count(vendor/location[@id = '101']//street)"));
274
275 context.removePath("vendor/location[@id = '100']/@name");
276 assertEquals(
277 "Remove DOM attribute",
278 new Double(0),
279 context.getValue("count(vendor/location[@id = '100']/@name)"));
280 }
281
282 public void testID() {
283 context.setIdentityManager(new IdentityManager() {
284 public Pointer getPointerByID(JXPathContext context, String id) {
285 NodePointer ptr = (NodePointer) context.getPointer("/");
286 ptr = ptr.getValuePointer();
287 return ptr.getPointerByID(context, id);
288 }
289 });
290
291 assertXPathValueAndPointer(
292 context,
293 "id(101)//street",
294 "Tangerine Drive",
295 "id('101')/address[1]/street[1]");
296
297 assertXPathPointerLenient(
298 context,
299 "id(105)/address/street",
300 "id(105)/address/street");
301 }
302
303 public void testAxisChild() {
304 assertXPathValue(
305 context,
306 "vendor/location/address/street",
307 "Orchard Road");
308
309
310 assertXPathValue(
311 context,
312 "vendor/location/address/city",
313 "Fruit Market");
314
315
316 assertXPathValue(
317 context,
318 "local-name(vendor/product/price:amount)",
319 "amount");
320
321
322 assertXPathValue(context, "local-name(vendor/location)", "location");
323
324
325 assertXPathValue(
326 context,
327 "name(vendor/product/price:amount)",
328 "value:amount");
329
330
331 assertXPathValue(
332 context,
333 "name(vendor/location)",
334 "location");
335
336
337 assertXPathValue(
338 context,
339 "namespace-uri(vendor/product/price:amount)",
340 "priceNS");
341
342
343 assertXPathValue(context, "vendor/product/prix", "934.99");
344
345 assertXPathValue(context, "/vendor/contact[@name='jim']", "Jim");
346
347 boolean nsv = false;
348 try {
349 context.setLenient(false);
350 context.getValue("/vendor/contact[@name='jane']");
351 }
352 catch (JXPathException ex) {
353 nsv = true;
354 }
355 assertTrue("No such value: /vendor/contact[@name='jim']", nsv);
356
357 nsv = false;
358 try {
359 context.setLenient(false);
360 context.getValue("/vendor/contact[@name='jane']/*");
361 }
362 catch (JXPathException ex) {
363 nsv = true;
364 }
365 assertTrue("No such value: /vendor/contact[@name='jane']/*", nsv);
366
367
368 assertXPathValue(
369 context,
370 "count(vendor/product/price:*)",
371 new Double(2));
372
373
374 assertXPathValue(context, "count(vendor/product/*)", new Double(4));
375
376
377 assertXPathValue(context, "vendor/product/price:amount", "45.95");
378 }
379
380 public void testAxisChildIndexPredicate() {
381 assertXPathValue(
382 context,
383 "vendor/location[2]/address/street",
384 "Tangerine Drive");
385 }
386
387 public void testAxisDescendant() {
388
389 assertXPathValue(context, "//street", "Orchard Road");
390
391
392 assertXPathValue(context, "count(//price:*)", new Double(2));
393
394 assertXPathValueIterator(context, "vendor//saleEnds", list("never"));
395
396 assertXPathValueIterator(context, "vendor//promotion", list(""));
397
398 assertXPathValueIterator(
399 context,
400 "vendor//saleEnds[../@stores = 'all']",
401 list("never"));
402
403 assertXPathValueIterator(
404 context,
405 "vendor//promotion[../@stores = 'all']",
406 list(""));
407 }
408
409
410
411
412
413
414
415
416 public void testAxisParent() {
417
418 assertXPathPointer(
419 context,
420 "//street/..",
421 "/vendor[1]/location[1]/address[1]");
422
423
424 assertXPathPointerIterator(
425 context,
426 "//street/..",
427 list(
428 "/vendor[1]/location[2]/address[1]",
429 "/vendor[1]/location[1]/address[1]"));
430
431
432 assertXPathValue(
433 context,
434 "vendor/product/price:sale/saleEnds/parent::price:*" + "/saleEnds",
435 "never");
436 }
437
438 public void testAxisFollowingSibling() {
439
440 assertXPathValue(
441 context,
442 "vendor/location[.//employeeCount = 10]/"
443 + "following-sibling::location//street",
444 "Tangerine Drive");
445
446
447 assertXPathPointer(
448 context,
449 "vendor/location[.//employeeCount = 10]/"
450 + "following-sibling::location//street",
451 "/vendor[1]/location[2]/address[1]/street[1]");
452 }
453
454 public void testAxisPrecedingSibling() {
455
456 assertXPathPointer(
457 context,
458 "//location[2]/preceding-sibling::location//street",
459 "/vendor[1]/location[1]/address[1]/street[1]");
460 }
461
462 public void testAxisAttribute() {
463
464 assertXPathValue(context, "vendor/location/@id", "100");
465
466
467 assertXPathPointer(
468 context,
469 "vendor/location/@id",
470 "/vendor[1]/location[1]/@id");
471
472
473 assertXPathValueIterator(
474 context,
475 "vendor/location/@id",
476 list("100", "101"));
477
478
479 assertXPathValue(
480 context,
481 "vendor/product/price:amount/@price:discount",
482 "10%");
483
484
485 assertXPathValue(
486 context,
487 "namespace-uri(vendor/product/price:amount/@price:discount)",
488 "priceNS");
489
490
491 assertXPathValue(
492 context,
493 "local-name(vendor/product/price:amount/@price:discount)",
494 "discount");
495
496
497 assertXPathValue(
498 context,
499 "name(vendor/product/price:amount/@price:discount)",
500 "price:discount");
501
502
503 assertXPathValue(
504 context,
505 "vendor/product/price:amount/@discount",
506 "20%");
507
508
509 assertXPathValue(
510 context,
511 "namespace-uri(vendor/product/price:amount/@discount)",
512 "");
513
514
515 assertXPathValue(
516 context,
517 "local-name(vendor/product/price:amount/@discount)",
518 "discount");
519
520
521 assertXPathValue(
522 context,
523 "name(vendor/product/price:amount/@discount)",
524 "discount");
525
526
527 assertXPathValueIterator(
528 context,
529 "vendor/product/price:amount/@price:*",
530 list("10%"));
531
532
533 assertXPathValueIterator(
534 context,
535 "vendor/location[1]/@*",
536 set("100", "", "local"));
537
538
539 assertXPathValueIterator(
540 context,
541 "vendor/product/price:amount/@*",
542 list("20%"));
543
544
545 assertXPathValue(context, "vendor/location/@manager", "");
546
547
548 assertXPathValueLenient(context, "vendor/location/@missing", null);
549
550
551 assertXPathValueLenient(context, "vendor/location/@miss:missing", null);
552
553
554 assertXPathValue(
555 context,
556 "vendor/location[@id='101']//street",
557 "Tangerine Drive");
558
559 assertXPathValueIterator(
560 context,
561 "/vendor/location[1]/@*[name()!= 'manager']", list("100",
562 "local"));
563 }
564
565 public void testAxisNamespace() {
566
567 assertXPathValueAndPointer(
568 context,
569 "vendor/product/prix/namespace::price",
570 "priceNS",
571 "/vendor[1]/product[1]/prix[1]/namespace::price");
572
573
574 assertXPathValue(
575 context,
576 "count(vendor/product/namespace::*)",
577 new Double(3));
578
579
580 assertXPathValue(
581 context,
582 "name(vendor/product/prix/namespace::price)",
583 "price");
584
585
586 assertXPathValue(
587 context,
588 "local-name(vendor/product/prix/namespace::price)",
589 "price");
590 }
591
592 public void testAxisAncestor() {
593
594 assertXPathValue(
595 context,
596 "vendor/product/price:sale/saleEnds/"
597 + "ancestor::price:sale/saleEnds",
598 "never");
599
600
601 assertXPathValue(
602 context,
603 "vendor/product/price:sale/saleEnds/ancestor::price:*"
604 + "/saleEnds",
605 "never");
606 }
607
608 public void testAxisAncestorOrSelf() {
609
610 assertXPathValue(
611 context,
612 "vendor/product/price:sale/"
613 + "ancestor-or-self::price:sale/saleEnds",
614 "never");
615 }
616
617 public void testAxisFollowing() {
618 assertXPathValueIterator(
619 context,
620 "vendor/contact/following::location//street",
621 list("Orchard Road", "Tangerine Drive"));
622
623
624 assertXPathValue(
625 context,
626 "//location/following::price:sale/saleEnds",
627 "never");
628 }
629
630 public void testAxisSelf() {
631
632 assertXPathValue(
633 context,
634 "//price:sale/self::price:sale/saleEnds",
635 "never");
636
637
638 assertXPathValueLenient(context, "//price:sale/self::x/saleEnds", null);
639 }
640
641 public void testNodeTypeComment() {
642
643 assertXPathValue(
644 context,
645 "//product/comment()",
646 "We are not buying this product, ever");
647 }
648
649 public void testNodeTypeText() {
650
651 assertXPathValue(
652 context,
653 "//product/text()[. != '']",
654 "We love this product.");
655
656
657 assertXPathPointer(
658 context,
659 "//product/text()",
660 "/vendor[1]/product[1]/text()[1]");
661
662 }
663
664 public void testNodeTypeProcessingInstruction() {
665
666 assertXPathValue(
667 context,
668 "//product/processing-instruction()",
669 "do not show anybody");
670
671
672 assertXPathValue(
673 context,
674 "//product/processing-instruction('report')",
675 "average only");
676
677
678 assertXPathPointer(
679 context,
680 "//product/processing-instruction('report')",
681 "/vendor[1]/product[1]/processing-instruction('report')[1]");
682
683
684 assertXPathValue(
685 context,
686 "name(//product/processing-instruction()[1])",
687 "security");
688 }
689
690 public void testLang() {
691
692 assertXPathValue(context, "//product/prix/@xml:lang", "fr");
693
694
695 assertXPathValue(context, "//product/prix[lang('fr')]", "934.99");
696
697
698 assertXPathValue(
699 context,
700 "//product/price:sale[lang('en')]/saleEnds",
701 "never");
702 }
703
704 public void testDocument() {
705 assertXPathValue(
706 context,
707 "$document/vendor/location[1]//street",
708 "Orchard Road");
709
710 assertXPathPointer(
711 context,
712 "$document/vendor/location[1]//street",
713 "$document/vendor[1]/location[1]/address[1]/street[1]");
714
715 assertXPathValue(context, "$document/vendor//street", "Orchard Road");
716 }
717
718 public void testContainer() {
719 assertXPathValue(context, "$container/vendor//street", "Orchard Road");
720
721 assertXPathValue(context, "$container//street", "Orchard Road");
722
723 assertXPathPointer(
724 context,
725 "$container//street",
726 "$container/vendor[1]/location[1]/address[1]/street[1]");
727
728
729 assertXPathValue(
730 context,
731 "number(vendor/location/employeeCount)",
732 new Double(10));
733 }
734
735 public void testElementInVariable() {
736 assertXPathValue(context, "$element", "Orchard Road");
737 }
738
739 public void testTypeConversions() {
740
741 assertXPathValue(
742 context,
743 "vendor/location/employeeCount + 1",
744 new Double(11));
745
746
747 assertXPathValue(
748 context,
749 "vendor/location/employeeCount and true()",
750 Boolean.TRUE);
751 }
752
753 public void testBooleanFunction() {
754 assertXPathValue(
755 context,
756 "boolean(vendor//saleEnds[../@stores = 'all'])",
757 Boolean.TRUE);
758
759 assertXPathValue(
760 context,
761 "boolean(vendor//promotion[../@stores = 'all'])",
762 Boolean.TRUE);
763
764 assertXPathValue(
765 context,
766 "boolean(vendor//promotion[../@stores = 'some'])",
767 Boolean.FALSE);
768 }
769
770 public void testFunctionsLastAndPosition() {
771 assertXPathPointer(
772 context,
773 "vendor//location[last()]",
774 "/vendor[1]/location[2]");
775 }
776
777 public void testNamespaceMapping() {
778 context.registerNamespace("rate", "priceNS");
779 context.registerNamespace("goods", "productNS");
780
781 assertEquals("Context node namespace resolution",
782 "priceNS",
783 context.getNamespaceURI("price"));
784
785 assertEquals("Registered namespace resolution",
786 "priceNS",
787 context.getNamespaceURI("rate"));
788
789
790 assertXPathValue(context,
791 "count(vendor/product/rate:*)",
792 new Double(2));
793
794
795 assertXPathValueAndPointer(context,
796 "//product:name",
797 "Box of oranges",
798 "/vendor[1]/product[1]/goods:name[1]");
799 }
800 }