1
2
3
4
5
6
7
8 package net.sf.saxon.option.jdom2;
9
10 import net.sf.saxon.lib.NamespaceConstant;
11 import net.sf.saxon.om.AxisInfo;
12 import net.sf.saxon.om.NamespaceBinding;
13 import net.sf.saxon.om.NamespaceMap;
14 import net.sf.saxon.om.NodeInfo;
15 import net.sf.saxon.pattern.AnyNodeTest;
16 import net.sf.saxon.pattern.NodeKindTest;
17 import net.sf.saxon.pattern.NodeTest;
18 import net.sf.saxon.tree.iter.*;
19 import net.sf.saxon.tree.util.FastStringBuffer;
20 import net.sf.saxon.tree.util.Navigator;
21 import net.sf.saxon.tree.wrapper.AbstractNodeWrapper;
22 import net.sf.saxon.tree.wrapper.SiblingCountingNode;
23 import net.sf.saxon.type.Type;
24 import net.sf.saxon.type.UType;
25 import org.jdom2.*;
26 import org.jdom2.filter.ElementFilter;
27 import org.jdom2.located.Located;
28
29 import java.util.ArrayList;
30 import java.util.Iterator;
31 import java.util.List;
32 import java.util.ListIterator;
33 import java.util.function.Predicate;
34
35
36
37
38
39
40
41
42 public class JDOM2NodeWrapper extends AbstractNodeWrapper implements SiblingCountingNode {
43
44 protected Object node;
45
46 protected short nodeKind;
47 private JDOM2NodeWrapper parent;
48 protected int index;
49 protected NamespaceMap inScopeNamespaces;
50
51
52
53
54
55
56
57
58
59 private JDOM2NodeWrapper./net/sf/saxon/option/jdom2/JDOM2NodeWrapper.html#JDOM2NodeWrapper">JDOM2NodeWrapper(Object node, JDOM2NodeWrapper parent, int index) {
60 this.node = node;
61 this.parent = parent;
62 this.index = index;
63 }
64
65
66
67
68
69
70
71
72
73 protected static JDOM2NodeWrapper makeWrapper(Object node, JDOM2DocumentWrapper docWrapper) {
74 return makeWrapper(node, docWrapper, null, -1);
75 }
76
77
78
79
80
81
82
83
84
85
86
87
88 protected static JDOM2NodeWrapper makeWrapper(Object node, JDOM2DocumentWrapper docWrapper,
89 JDOM2NodeWrapper parent, int index) {
90 JDOM2NodeWrapper wrapper;
91 if (node instanceof Document) {
92 wrapper = (JDOM2NodeWrapper)docWrapper.getRootNode();
93 if (wrapper == null) {
94 wrapper = new JDOM2NodeWrapper(node, parent, index);
95 wrapper.nodeKind = Type.DOCUMENT;
96 }
97 } else if (node instanceof Element) {
98 wrapper = new JDOM2NodeWrapper(node, parent, index);
99 wrapper.nodeKind = Type.ELEMENT;
100 } else if (node instanceof Attribute) {
101 wrapper = new JDOM2NodeWrapper(node, parent, index);
102 wrapper.nodeKind = Type.ATTRIBUTE;
103 } else if (node instanceof String || node instanceof Text) {
104 wrapper = new JDOM2NodeWrapper(node, parent, index);
105 wrapper.nodeKind = Type.TEXT;
106 } else if (node instanceof Comment) {
107 wrapper = new JDOM2NodeWrapper(node, parent, index);
108 wrapper.nodeKind = Type.COMMENT;
109 } else if (node instanceof ProcessingInstruction) {
110 wrapper = new JDOM2NodeWrapper(node, parent, index);
111 wrapper.nodeKind = Type.PROCESSING_INSTRUCTION;
112 } else if (node instanceof Namespace) {
113 throw new IllegalArgumentException("Cannot wrap JDOM namespace objects");
114 } else {
115 throw new IllegalArgumentException("Bad node type in JDOM! " + node.getClass() + " instance " + node.toString());
116 }
117 wrapper.treeInfo = docWrapper;
118 return wrapper;
119 }
120
121
122
123
124
125
126
127 @Override
128 public Object getUnderlyingNode() {
129 if (node instanceof List) {
130 return ((List) node).get(0);
131 } else {
132 return node;
133 }
134 }
135
136 @Override
137 public JDOM2DocumentWrapper getTreeInfo() {
138 return (JDOM2DocumentWrapper)treeInfo;
139 }
140
141
142
143
144
145
146
147 @Override
148 public int getNodeKind() {
149 return nodeKind;
150 }
151
152
153
154
155
156
157
158
159
160
161
162 @Override
163 public int compareOrder(NodeInfo other) {
164 if (other instanceof SiblingCountingNode) {
165 return Navigator.compareOrder(this, (SiblingCountingNode) other);
166 } else {
167
168 return -other.compareOrder(this);
169 }
170 }
171
172
173
174
175
176
177 @Override
178 public CharSequence getStringValueCS() {
179 if (node instanceof List) {
180
181 List nodes = (List) node;
182 FastStringBuffer fsb = new FastStringBuffer(FastStringBuffer.C64);
183 for (Object node1 : nodes) {
184 Text o = (Text) node1;
185 fsb.append(getStringValue(o));
186 }
187 return fsb;
188 } else {
189 return getStringValue(node);
190 }
191 }
192
193 @Override
194 public int getLineNumber() {
195 if (node instanceof Located) {
196 return ((Located) node).getLine();
197 } else {
198 return -1;
199 }
200 }
201
202 @Override
203 public int getColumnNumber() {
204 if (node instanceof Located) {
205 return ((Located) node).getColumn();
206 } else {
207 return -1;
208 }
209 }
210
211
212
213
214
215
216
217
218
219 private static String getStringValue(Object node) {
220 if (node instanceof Document) {
221 List<Content> children1 = ((Document) node).getContent();
222 FastStringBuffer sb1 = new FastStringBuffer(FastStringBuffer.C256);
223 expandStringValue(children1, sb1);
224 return sb1.toString();
225 } else if (node instanceof Element) {
226 return ((Element) node).getValue();
227 } else if (node instanceof Attribute) {
228 return ((Attribute) node).getValue();
229 } else if (node instanceof Text) {
230 return ((Text) node).getText();
231 } else if (node instanceof String) {
232 return (String) node;
233 } else if (node instanceof Comment) {
234 return ((Comment) node).getText();
235 } else if (node instanceof ProcessingInstruction) {
236 return ((ProcessingInstruction) node).getData();
237 } else if (node instanceof Namespace) {
238 return ((Namespace) node).getURI();
239 } else {
240 return "";
241 }
242 }
243
244
245
246
247
248
249
250
251 private static void expandStringValue(List<Content> list, FastStringBuffer sb) {
252 for (Content obj : list) {
253 if (obj instanceof Element) {
254 sb.append(obj.getValue());
255 } else if (obj instanceof Text) {
256 sb.append(((Text) obj).getText());
257 } else if (obj instanceof EntityRef) {
258 throw new IllegalStateException("Unexpanded entity in JDOM2 tree");
259 } else if (obj instanceof DocType) {
260
261 continue;
262 } else {
263 throw new AssertionError("Unknown JDOM2 node type");
264 }
265 }
266 }
267
268
269
270
271
272
273
274 @Override
275 public String getLocalPart() {
276 switch (nodeKind) {
277 case Type.ELEMENT:
278 return ((Element) node).getName();
279 case Type.ATTRIBUTE:
280 return ((Attribute) node).getName();
281 case Type.TEXT:
282 case Type.COMMENT:
283 case Type.DOCUMENT:
284 return "";
285 case Type.PROCESSING_INSTRUCTION:
286 return ((ProcessingInstruction) node).getTarget();
287 case Type.NAMESPACE:
288 return ((Namespace) node).getPrefix();
289 default:
290 return null;
291 }
292 }
293
294
295
296
297
298
299
300
301 @Override
302 public String getPrefix() {
303 switch (nodeKind) {
304 case Type.ELEMENT:
305 return ((Element) node).getNamespacePrefix();
306 case Type.ATTRIBUTE:
307 return ((Attribute) node).getNamespacePrefix();
308 default:
309 return "";
310 }
311 }
312
313
314
315
316
317
318
319
320
321
322 @Override
323 public String getURI() {
324 switch (nodeKind) {
325 case Type.ELEMENT:
326 return ((Element) node).getNamespaceURI();
327 case Type.ATTRIBUTE:
328 return ((Attribute) node).getNamespaceURI();
329 default:
330 return "";
331 }
332 }
333
334
335
336
337
338
339
340
341
342 @Override
343 public String getDisplayName() {
344 switch (nodeKind) {
345 case Type.ELEMENT:
346 return ((Element) node).getQualifiedName();
347 case Type.ATTRIBUTE:
348 return ((Attribute) node).getQualifiedName();
349 case Type.PROCESSING_INSTRUCTION:
350 case Type.NAMESPACE:
351 return getLocalPart();
352 default:
353 return "";
354
355 }
356 }
357
358
359
360
361
362 @Override
363 public NodeInfo getParent() {
364 if (parent == null) {
365 if (node instanceof Element) {
366 if (((Element) node).isRootElement()) {
367 parent = makeWrapper(((Element) node).getDocument(), getTreeInfo());
368 } else {
369 parent = makeWrapper(((Element) node).getParent(), getTreeInfo());
370 }
371 } else if (node instanceof Text) {
372 parent = makeWrapper(((Text) node).getParent(), getTreeInfo());
373 } else if (node instanceof Comment) {
374 parent = makeWrapper(((Comment) node).getParent(), getTreeInfo());
375 } else if (node instanceof ProcessingInstruction) {
376 parent = makeWrapper(((ProcessingInstruction) node).getParent(), getTreeInfo());
377 } else if (node instanceof Attribute) {
378 parent = makeWrapper(((Attribute) node).getParent(), getTreeInfo());
379 } else if (node instanceof Document) {
380 parent = null;
381 } else if (node instanceof Namespace) {
382 throw new UnsupportedOperationException("Cannot find parent of JDOM namespace node");
383 } else {
384 throw new IllegalStateException("Unknown JDOM node type " + node.getClass());
385 }
386 }
387 return parent;
388 }
389
390
391
392
393
394
395
396
397
398
399 @Override
400 public int getSiblingPosition() {
401 if (index == -1) {
402 int ix = 0;
403 getParent();
404 if (parent == null) {
405 return 0;
406 }
407 AxisIterator iter;
408 switch (nodeKind) {
409 case Type.ELEMENT:
410 case Type.TEXT:
411 case Type.COMMENT:
412 case Type.PROCESSING_INSTRUCTION:
413 iter = parent.iterateAxis(AxisInfo.CHILD);
414 break;
415 case Type.ATTRIBUTE:
416 iter = parent.iterateAxis(AxisInfo.ATTRIBUTE);
417 break;
418 case Type.NAMESPACE:
419 iter = parent.iterateAxis(AxisInfo.NAMESPACE);
420 break;
421 default:
422 index = 0;
423 return index;
424 }
425 while (true) {
426 NodeInfo n = iter.next();
427 if (n == null) {
428 break;
429 }
430 if (n.equals(this)) {
431 index = ix;
432 return index;
433 }
434 if (((JDOM2NodeWrapper) n).node instanceof List) {
435 ix += ((List) ((JDOM2NodeWrapper) n).node).size();
436 } else {
437 ix++;
438 }
439 }
440 throw new IllegalStateException("JDOM node not linked to parent node");
441 }
442 return index;
443 }
444
445 @Override
446 protected AxisIterator iterateAttributes(Predicate<? super NodeInfo> nodeTest) {
447 AxisIterator base = new AttributeEnumeration(this);
448 if (nodeTest == AnyNodeTest.getInstance()) {
449 return base;
450 } else {
451 return new Navigator.AxisFilter(base, nodeTest);
452 }
453 }
454
455 @Override
456 protected AxisIterator iterateChildren(Predicate<? super NodeInfo> nodeTest) {
457 if (hasChildNodes()) {
458 AxisIterator base = new ChildEnumeration(this, true, true);
459 if (nodeTest == AnyNodeTest.getInstance()) {
460 return base;
461 } else {
462 return new Navigator.AxisFilter(base, nodeTest);
463 }
464 } else {
465 return EmptyIterator.ofNodes();
466 }
467 }
468
469 @Override
470 protected AxisIterator iterateSiblings(Predicate<? super NodeInfo> nodeTest, boolean forwards) {
471 if (nodeTest == AnyNodeTest.getInstance()) {
472 return new ChildEnumeration(this, false, forwards);
473 } else {
474 return new Navigator.AxisFilter(
475 new ChildEnumeration(this, false, forwards),
476 nodeTest);
477 }
478 }
479
480 @Override
481 protected AxisIterator iterateDescendants(Predicate<? super NodeInfo> nodeTest, boolean includeSelf) {
482 Iterator<? extends Content> descendants;
483 if (nodeTest instanceof NodeTest && ((NodeTest)nodeTest).getUType() == UType.ELEMENT) {
484
485 descendants = ((Parent) node).getDescendants(new ElementFilter());
486 } else {
487 descendants = ((Parent) node).getDescendants();
488 }
489 NodeWrappingFunction<Content, NodeInfo> wrappingFunct = new NodeWrappingFunction<Content, NodeInfo>() {
490 @Override
491 public NodeInfo wrap(Content node) {
492 return makeWrapper(node, getTreeInfo());
493 }
494 };
495 AxisIterator wrappedDescendants = new DescendantWrappingIterator<Content>(descendants, wrappingFunct);
496
497 if (includeSelf && nodeTest.test(this)) {
498 wrappedDescendants = new PrependAxisIterator(this, wrappedDescendants);
499 }
500
501 if (nodeTest instanceof AnyNodeTest || (nodeTest instanceof NodeKindTest && ((NodeKindTest) nodeTest).getNodeKind() == Type.ELEMENT)) {
502 return wrappedDescendants;
503 } else {
504 return new Navigator.AxisFilter(wrappedDescendants, nodeTest);
505 }
506 }
507
508 private static class DescendantWrappingIterator<N> extends NodeWrappingAxisIterator<N> {
509
510 DescendantWrappingIterator(
511 Iterator<? extends N> descendantIterator,
512 NodeWrappingFunction<? super N, NodeInfo> wrappingFunction) {
513 super(descendantIterator, wrappingFunction);
514 }
515
516 @Override
517 public boolean isIgnorable(Object node) {
518 return node instanceof DocType;
519 }
520 }
521
522
523
524
525
526
527
528
529
530
531
532
533
534 @Override
535 public String getAttributeValue(String uri, String local) {
536 if (nodeKind == Type.ELEMENT) {
537 return ((Element) node).getAttributeValue(local,
538 (uri.equals(NamespaceConstant.XML) ?
539 Namespace.XML_NAMESPACE :
540 Namespace.getNamespace(uri)));
541
542 }
543 return null;
544 }
545
546
547
548
549
550
551
552 @Override
553 public NodeInfo getRoot() {
554 return treeInfo.getRootNode();
555 }
556
557
558
559
560
561
562
563 @Override
564 public boolean hasChildNodes() {
565 switch (nodeKind) {
566 case Type.DOCUMENT:
567 return true;
568 case Type.ELEMENT:
569 return !((Element) node).getContent().isEmpty();
570 default:
571 return false;
572 }
573 }
574
575
576
577
578
579
580
581
582
583 @Override
584 public void generateId(FastStringBuffer buffer) {
585 Navigator.appendSequentialKey(this, buffer, true);
586
587 }
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603 @Override
604 public NamespaceBinding[] getDeclaredNamespaces(NamespaceBinding[] buffer) {
605 if (node instanceof Element) {
606 Element elem = (Element) node;
607 List<Namespace> addl = elem.getAdditionalNamespaces();
608 List<NamespaceBinding> bindings = new ArrayList<>();
609 Namespace ns = elem.getNamespace();
610 String prefix = ns.getPrefix();
611 String uri = ns.getURI();
612 if (!(prefix.isEmpty() && uri.isEmpty())) {
613 bindings.add(new NamespaceBinding(prefix, uri));
614 }
615 if (!addl.isEmpty()) {
616 for (Namespace ns2 : addl) {
617 bindings.add(new NamespaceBinding(ns2.getPrefix(), ns2.getURI()));
618 }
619 }
620 return bindings.toArray(NamespaceBinding.EMPTY_ARRAY);
621 } else {
622 return null;
623 }
624 }
625
626
627
628
629
630
631
632
633
634
635
636 @Override
637 public NamespaceMap getAllNamespaces() {
638 if (getNodeKind() == Type.ELEMENT) {
639 if (inScopeNamespaces != null) {
640 return inScopeNamespaces;
641 } else {
642 NamespaceMap nsMap = getParent().getNodeKind() == Type.ELEMENT
643 ? getParent().getAllNamespaces()
644 : NamespaceMap.emptyMap();
645 Element elem = (Element) node;
646 List<Namespace> addl = elem.getAdditionalNamespaces();
647 Namespace ns = elem.getNamespace();
648 String prefix = ns.getPrefix();
649 String uri = ns.getURI();
650 nsMap = nsMap.bind(prefix, uri);
651 if (!addl.isEmpty()) {
652 for (Namespace ns2 : addl) {
653 nsMap = nsMap.bind(ns2.getPrefix(), ns2.getURI());
654 }
655 }
656 return inScopeNamespaces = nsMap;
657 }
658 } else {
659 return null;
660 }
661 }
662
663
664
665
666
667
668
669 @Override
670 public boolean isId() {
671 return node instanceof Attribute && ((Attribute) node).getAttributeType() == Attribute.ID_TYPE;
672 }
673
674
675
676
677
678
679
680 @Override
681 public boolean isIdref() {
682 if (node instanceof Attribute) {
683 AttributeType type = ((Attribute) node).getAttributeType();
684 return type == Attribute.IDREF_TYPE || type == Attribute.IDREFS_TYPE;
685 } else {
686 return false;
687 }
688 }
689
690
691
692
693
694
695
696 private final class AttributeEnumeration implements AxisIterator {
697
698 private Iterator<Attribute> atts;
699 private int ix = 0;
700 private JDOM2NodeWrapper start;
701
702 AttributeEnumeration(JDOM2NodeWrapper start) {
703 this.start = start;
704 atts = ((Element) start.node).getAttributes().iterator();
705 }
706
707 @Override
708 public JDOM2NodeWrapper next() {
709 if (atts.hasNext()) {
710 return makeWrapper(atts.next(), getTreeInfo(), start, ix++);
711 } else {
712 return null;
713 }
714 }
715
716 }
717
718
719
720
721
722
723
724
725
726 private final class ChildEnumeration implements AxisIterator {
727
728 private JDOM2NodeWrapper commonParent;
729 private ListIterator children;
730 private int ix = 0;
731 private boolean forwards;
732
733 public ChildEnumeration(JDOM2NodeWrapper start,
734 boolean downwards, boolean forwards) {
735 this.forwards = forwards;
736
737 if (downwards) {
738 commonParent = start;
739 } else {
740 commonParent = (JDOM2NodeWrapper) start.getParent();
741 }
742
743 if (commonParent.getNodeKind() == Type.DOCUMENT) {
744 children = ((Document) commonParent.node).getContent().listIterator();
745 } else {
746 children = ((Element) commonParent.node).getContent().listIterator();
747 }
748
749 if (downwards) {
750 if (!forwards) {
751
752 while (children.hasNext()) {
753 children.next();
754 ix++;
755 }
756 }
757 } else {
758 ix = start.getSiblingPosition();
759
760 Object n = null;
761 if (forwards) {
762 for (int i = 0; i <= ix; i++) {
763 n = children.next();
764 }
765 if (n instanceof Text) {
766
767 boolean atEnd = false;
768 while (n instanceof Text) {
769 if (children.hasNext()) {
770 n = children.next();
771 ix++;
772 } else {
773 atEnd = true;
774 break;
775 }
776 }
777 if (!atEnd) {
778 children.previous();
779 }
780 } else {
781 ix++;
782 }
783 } else {
784 for (int i = 0; i < ix; i++) {
785 children.next();
786 }
787 ix--;
788 }
789 }
790 }
791
792 @Override
793 public JDOM2NodeWrapper next() {
794 if (forwards) {
795 if (children.hasNext()) {
796 Object nextChild = children.next();
797 if (nextChild instanceof DocType) {
798 return next();
799 }
800 if (nextChild instanceof EntityRef) {
801 throw new IllegalStateException("Unexpanded entity in JDOM tree");
802 } else if (nextChild instanceof Text) {
803 JDOM2NodeWrapper current = makeWrapper(nextChild, getTreeInfo(), commonParent, ix++);
804 List<Object> list = null;
805 while (children.hasNext()) {
806 Object n = children.next();
807 if (n instanceof Text) {
808 if (list == null) {
809 list = new ArrayList<Object>(4);
810 list.add(current.node);
811 }
812 list.add(n);
813 ix++;
814 } else {
815
816 children.previous();
817 break;
818 }
819 }
820 if (list != null) {
821 current.node = list;
822 }
823 return current;
824 } else {
825 return makeWrapper(nextChild, getTreeInfo(), commonParent, ix++);
826 }
827 } else {
828 return null;
829 }
830 } else {
831 if (children.hasPrevious()) {
832 Object nextChild = children.previous();
833 if (nextChild instanceof DocType) {
834 return next();
835 }
836 if (nextChild instanceof EntityRef) {
837 throw new IllegalStateException("Unexpanded entity in JDOM tree");
838 } else if (nextChild instanceof Text) {
839 JDOM2NodeWrapper current = makeWrapper(nextChild, getTreeInfo(), commonParent, ix--);
840 List<Object> list = null;
841 while (children.hasPrevious()) {
842 Object n = children.previous();
843 if (n instanceof Text) {
844 if (list == null) {
845 list = new ArrayList<Object>(4);
846 list.add(current.node);
847 }
848 list.add(0, n);
849 ix--;
850 } else {
851
852 children.next();
853 break;
854 }
855 }
856 if (list != null) {
857 current.node = list;
858 }
859 return current;
860 } else {
861 return makeWrapper(nextChild, getTreeInfo(), commonParent, ix--);
862 }
863 } else {
864 return null;
865 }
866 }
867 }
868
869
870 }
871
872 }
873
874
875