1 16 package org.apache.commons.jxpath.ri.model.jdom; 17 18 import java.util.List ; 19 import java.util.Locale ; 20 import java.util.Map ; 21 22 import org.apache.commons.jxpath.AbstractFactory; 23 import org.apache.commons.jxpath.JXPathContext; 24 import org.apache.commons.jxpath.JXPathException; 25 import org.apache.commons.jxpath.ri.Compiler; 26 import org.apache.commons.jxpath.ri.QName; 27 import org.apache.commons.jxpath.ri.compiler.NodeNameTest; 28 import org.apache.commons.jxpath.ri.compiler.NodeTest; 29 import org.apache.commons.jxpath.ri.compiler.NodeTypeTest; 30 import org.apache.commons.jxpath.ri.compiler.ProcessingInstructionTest; 31 import org.apache.commons.jxpath.ri.model.NodeIterator; 32 import org.apache.commons.jxpath.ri.model.NodePointer; 33 import org.apache.commons.jxpath.util.TypeUtils; 34 import org.jdom.Attribute; 35 import org.jdom.CDATA; 36 import org.jdom.Comment; 37 import org.jdom.Document; 38 import org.jdom.Element; 39 import org.jdom.Namespace; 40 import org.jdom.ProcessingInstruction; 41 import org.jdom.Text; 42 43 49 public class JDOMNodePointer extends NodePointer { 50 private Object node; 51 private Map namespaces; 52 private String defaultNamespace; 53 private String id; 54 55 public static final String XML_NAMESPACE_URI = 56 "http://www.w3.org/XML/1998/namespace"; 57 public static final String XMLNS_NAMESPACE_URI = 58 "http://www.w3.org/2000/xmlns/"; 59 60 public JDOMNodePointer(Object node, Locale locale) { 61 super(null, locale); 62 this.node = node; 63 } 64 65 public JDOMNodePointer(Object node, Locale locale, String id) { 66 super(null, locale); 67 this.node = node; 68 this.id = id; 69 } 70 71 public JDOMNodePointer(NodePointer parent, Object node) { 72 super(parent); 73 this.node = node; 74 } 75 76 public NodeIterator childIterator( 77 NodeTest test, 78 boolean reverse, 79 NodePointer startWith) 80 { 81 return new JDOMNodeIterator(this, test, reverse, startWith); 82 } 83 84 public NodeIterator attributeIterator(QName name) { 85 return new JDOMAttributeIterator(this, name); 86 } 87 88 public NodeIterator namespaceIterator() { 89 return new JDOMNamespaceIterator(this); 90 } 91 92 public NodePointer namespacePointer(String prefix) { 93 return new JDOMNamespacePointer(this, prefix); 94 } 95 96 public String getNamespaceURI() { 97 return getNamespaceURI(node); 98 } 99 100 private static String getNamespaceURI(Object node) { 101 if (node instanceof Element) { 102 Element element = (Element) node; 103 String ns = element.getNamespaceURI(); 104 if (ns != null && ns.equals("")) { 105 ns = null; 106 } 107 return ns; 108 } 109 return null; 110 } 111 112 public String getNamespaceURI(String prefix) { 113 if (node instanceof Document) { 114 Element element = ((Document)node).getRootElement(); 115 Namespace ns = element.getNamespace(prefix); 116 if (ns != null) { 117 return ns.getURI(); 118 } 119 } 120 else if (node instanceof Element) { 121 Element element = (Element) node; 122 Namespace ns = element.getNamespace(prefix); 123 if (ns != null) { 124 return ns.getURI(); 125 } 126 } 127 return null; 128 } 129 130 public int compareChildNodePointers( 131 NodePointer pointer1, 132 NodePointer pointer2) 133 { 134 Object node1 = pointer1.getBaseValue(); 135 Object node2 = pointer2.getBaseValue(); 136 if (node1 == node2) { 137 return 0; 138 } 139 140 if ((node1 instanceof Attribute) && !(node2 instanceof Attribute)) { 141 return -1; 142 } 143 else if ( 144 !(node1 instanceof Attribute) && (node2 instanceof Attribute)) { 145 return 1; 146 } 147 else if ( 148 (node1 instanceof Attribute) && (node2 instanceof Attribute)) { 149 List list = ((Element) getNode()).getAttributes(); 150 int length = list.size(); 151 for (int i = 0; i < length; i++) { 152 Object n = list.get(i); 153 if (n == node1) { 154 return -1; 155 } 156 else if (n == node2) { 157 return 1; 158 } 159 } 160 return 0; } 162 163 if (!(node instanceof Element)) { 164 throw new RuntimeException ( 165 "JXPath internal error: " 166 + "compareChildNodes called for " 167 + node); 168 } 169 170 List children = ((Element) node).getContent(); 171 int length = children.size(); 172 for (int i = 0; i < length; i++) { 173 Object n = children.get(i); 174 if (n == node1) { 175 return -1; 176 } 177 else if (n == node2) { 178 return 1; 179 } 180 } 181 182 return 0; 183 } 184 185 186 189 public Object getBaseValue() { 190 return node; 191 } 192 193 public boolean isCollection() { 194 return false; 195 } 196 197 public int getLength() { 198 return 1; 199 } 200 201 public boolean isLeaf() { 202 if (node instanceof Element) { 203 return ((Element) node).getContent().size() == 0; 204 } 205 else if (node instanceof Document) { 206 return ((Document) node).getContent().size() == 0; 207 } 208 return true; 209 } 210 211 214 public QName getName() { 215 String ns = null; 216 String ln = null; 217 if (node instanceof Element) { 218 ns = ((Element) node).getNamespacePrefix(); 219 if (ns != null && ns.equals("")) { 220 ns = null; 221 } 222 ln = ((Element) node).getName(); 223 } 224 else if (node instanceof ProcessingInstruction) { 225 ln = ((ProcessingInstruction) node).getTarget(); 226 } 227 return new QName(ns, ln); 228 } 229 230 233 public Object getImmediateNode() { 234 return node; 235 } 236 237 public Object getValue() { 238 if (node instanceof Element) { 239 return ((Element) node).getTextTrim(); 240 } 241 else if (node instanceof Comment) { 242 String text = ((Comment) node).getText(); 243 if (text != null) { 244 text = text.trim(); 245 } 246 return text; 247 } 248 else if (node instanceof Text) { 249 return ((Text) node).getTextTrim(); 250 } 251 else if (node instanceof CDATA) { 252 return ((CDATA) node).getTextTrim(); 253 } 254 else if (node instanceof ProcessingInstruction) { 255 String text = ((ProcessingInstruction) node).getData(); 256 if (text != null) { 257 text = text.trim(); 258 } 259 return text; 260 } 261 return null; 262 } 263 264 public void setValue(Object value) { 265 if (node instanceof Text) { 266 String string = (String ) TypeUtils.convert(value, String .class); 267 if (string != null && !string.equals("")) { 268 ((Text) node).setText(string); 269 } 270 else { 271 nodeParent(node).removeContent((Text) node); 272 } 273 } 274 else { 275 Element element = (Element) node; 276 element.getContent().clear(); 277 278 if (value instanceof Element) { 279 Element valueElement = (Element) value; 280 addContent(valueElement.getContent()); 281 } 282 else if (value instanceof Document) { 283 Document valueDocument = (Document) value; 284 addContent(valueDocument.getContent()); 285 } 286 else if (value instanceof Text || value instanceof CDATA) { 287 String string = ((Text) value).getText(); 288 element.addContent(new Text(string)); 289 } 290 else if (value instanceof ProcessingInstruction) { 291 ProcessingInstruction pi = 292 (ProcessingInstruction) ((ProcessingInstruction) value) 293 .clone(); 294 element.addContent(pi); 295 } 296 else if (value instanceof Comment) { 297 Comment comment = (Comment) ((Comment) value).clone(); 298 element.addContent(comment); 299 } 300 else { 301 String string = (String ) TypeUtils.convert(value, String .class); 302 if (string != null && !string.equals("")) { 303 element.addContent(new Text(string)); 304 } 305 } 306 } 307 } 308 309 private void addContent(List content) { 310 Element element = (Element) node; 311 int count = content.size(); 312 313 for (int i = 0; i < count; i++) { 314 Object child = content.get(i); 315 if (child instanceof Element) { 316 child = ((Element) child).clone(); 317 element.addContent((Element) child); 318 } 319 else if (child instanceof Text) { 320 child = ((Text) child).clone(); 321 element.addContent((Text) child); 322 } 323 else if (node instanceof CDATA) { 324 child = ((CDATA) child).clone(); 325 element.addContent((CDATA) child); 326 } 327 else if (node instanceof ProcessingInstruction) { 328 child = ((ProcessingInstruction) child).clone(); 329 element.addContent((ProcessingInstruction) child); 330 } 331 else if (node instanceof Comment) { 332 child = ((Comment) child).clone(); 333 element.addContent((Comment) child); 334 } 335 } 336 } 337 338 public boolean testNode(NodeTest test) { 339 return testNode(this, node, test); 340 } 341 342 public static boolean testNode( 343 NodePointer pointer, 344 Object node, 345 NodeTest test) 346 { 347 if (test == null) { 348 return true; 349 } 350 else if (test instanceof NodeNameTest) { 351 if (!(node instanceof Element)) { 352 return false; 353 } 354 355 NodeNameTest nodeNameTest = (NodeNameTest) test; 356 QName testName = nodeNameTest.getNodeName(); 357 String namespaceURI = nodeNameTest.getNamespaceURI(); 358 boolean wildcard = nodeNameTest.isWildcard(); 359 String testPrefix = testName.getPrefix(); 360 if (wildcard && testPrefix == null) { 361 return true; 362 } 363 364 if (wildcard 365 || testName.getName() 366 .equals(JDOMNodePointer.getLocalName(node))) { 367 String nodeNS = JDOMNodePointer.getNamespaceURI(node); 368 return equalStrings(namespaceURI, nodeNS); 369 } 370 371 } 372 else if (test instanceof NodeTypeTest) { 373 switch (((NodeTypeTest) test).getNodeType()) { 374 case Compiler.NODE_TYPE_NODE : 375 return node instanceof Element; 376 case Compiler.NODE_TYPE_TEXT : 377 return (node instanceof Text) || (node instanceof CDATA); 378 case Compiler.NODE_TYPE_COMMENT : 379 return node instanceof Comment; 380 case Compiler.NODE_TYPE_PI : 381 return node instanceof ProcessingInstruction; 382 } 383 return false; 384 } 385 else if (test instanceof ProcessingInstructionTest) { 386 if (node instanceof ProcessingInstruction) { 387 String testPI = ((ProcessingInstructionTest) test).getTarget(); 388 String nodePI = ((ProcessingInstruction) node).getTarget(); 389 return testPI.equals(nodePI); 390 } 391 } 392 393 return false; 394 } 395 396 private static boolean equalStrings(String s1, String s2) { 397 if (s1 == null && s2 != null) { 398 return false; 399 } 400 if (s1 != null && s2 == null) { 401 return false; 402 } 403 404 if (s1 != null && !s1.trim().equals(s2.trim())) { 405 return false; 406 } 407 408 return true; 409 } 410 411 public static String getPrefix(Object node) { 412 if (node instanceof Element) { 413 String prefix = ((Element) node).getNamespacePrefix(); 414 return (prefix == null || prefix.equals("")) ? null : prefix; 415 } 416 else if (node instanceof Attribute) { 417 String prefix = ((Attribute) node).getNamespacePrefix(); 418 return (prefix == null || prefix.equals("")) ? null : prefix; 419 } 420 return null; 421 } 422 423 public static String getLocalName(Object node) { 424 if (node instanceof Element) { 425 return ((Element) node).getName(); 426 } 427 else if (node instanceof Attribute) { 428 return ((Attribute) node).getName(); 429 } 430 return null; 431 } 432 433 438 public boolean isLanguage(String lang) { 439 String current = getLanguage(); 440 if (current == null) { 441 return super.isLanguage(lang); 442 } 443 return current.toUpperCase().startsWith(lang.toUpperCase()); 444 } 445 446 protected String getLanguage() { 447 Object n = node; 448 while (n != null) { 449 if (n instanceof Element) { 450 Element e = (Element) n; 451 String attr = 452 e.getAttributeValue("lang", Namespace.XML_NAMESPACE); 453 if (attr != null && !attr.equals("")) { 454 return attr; 455 } 456 } 457 n = nodeParent(n); 458 } 459 return null; 460 } 461 462 private Element nodeParent(Object node) { 463 if (node instanceof Element) { 464 Object parent = ((Element) node).getParent(); 465 if (parent instanceof Element) { 466 return (Element) parent; 467 } 468 } 469 else if (node instanceof Text) { 470 return (Element) ((Text) node).getParent(); 471 } 472 else if (node instanceof CDATA) { 473 return (Element) ((CDATA) node).getParent(); 474 } 475 else if (node instanceof ProcessingInstruction) { 476 return (Element) ((ProcessingInstruction) node).getParent(); 477 } 478 else if (node instanceof Comment) { 479 return (Element) ((Comment) node).getParent(); 480 } 481 return null; 482 } 483 484 public NodePointer createChild( 485 JXPathContext context, 486 QName name, 487 int index) 488 { 489 if (index == WHOLE_COLLECTION) { 490 index = 0; 491 } 492 boolean success = 493 getAbstractFactory(context).createObject( 494 context, 495 this, 496 node, 497 name.toString(), 498 index); 499 if (success) { 500 NodeTest nodeTest; 501 String prefix = name.getPrefix(); 502 if (prefix != null) { 503 String namespaceURI = context.getNamespaceURI(prefix); 504 nodeTest = new NodeNameTest(name, namespaceURI); 505 } 506 else { 507 nodeTest = new NodeNameTest(name); 508 } 509 510 NodeIterator it = 511 childIterator(nodeTest, false, null); 512 if (it != null && it.setPosition(index + 1)) { 513 return it.getNodePointer(); 514 } 515 } 516 throw new JXPathException( 517 "Factory could not create " 518 + "a child node for path: " 519 + asPath() 520 + "/" 521 + name 522 + "[" 523 + (index + 1) 524 + "]"); 525 } 526 527 public NodePointer createChild( 528 JXPathContext context, QName name, int index, Object value) 529 { 530 NodePointer ptr = createChild(context, name, index); 531 ptr.setValue(value); 532 return ptr; 533 } 534 535 public NodePointer createAttribute(JXPathContext context, QName name) { 536 if (!(node instanceof Element)) { 537 return super.createAttribute(context, name); 538 } 539 540 Element element = (Element) node; 541 String prefix = name.getPrefix(); 542 if (prefix != null) { 543 Namespace ns = element.getNamespace(prefix); 544 if (ns == null) { 545 throw new JXPathException( 546 "Unknown namespace prefix: " + prefix); 547 } 548 Attribute attr = element.getAttribute(name.getName(), ns); 549 if (attr == null) { 550 element.setAttribute(name.getName(), "", ns); 551 } 552 } 553 else { 554 Attribute attr = element.getAttribute(name.getName()); 555 if (attr == null) { 556 element.setAttribute(name.getName(), ""); 557 } 558 } 559 NodeIterator it = attributeIterator(name); 560 it.setPosition(1); 561 return it.getNodePointer(); 562 } 563 564 public void remove() { 565 Element parent = nodeParent(node); 566 if (parent == null) { 567 throw new JXPathException("Cannot remove root JDOM node"); 568 } 569 parent.getContent().remove(node); 570 } 571 572 public String asPath() { 573 if (id != null) { 574 return "id('" + escape(id) + "')"; 575 } 576 577 StringBuffer buffer = new StringBuffer (); 578 if (parent != null) { 579 buffer.append(parent.asPath()); 580 } 581 if (node instanceof Element) { 582 if (parent instanceof JDOMNodePointer) { 586 if (buffer.length() == 0 587 || buffer.charAt(buffer.length() - 1) != '/') { 588 buffer.append('/'); 589 } 590 String nsURI = getNamespaceURI(); 591 String ln = JDOMNodePointer.getLocalName(node); 592 593 if (nsURI == null) { 594 buffer.append(ln); 595 buffer.append('['); 596 buffer.append(getRelativePositionByName()).append(']'); 597 } 598 else { 599 String prefix = getNamespaceResolver().getPrefix(nsURI); 600 if (prefix != null) { 601 buffer.append(prefix); 602 buffer.append(':'); 603 buffer.append(ln); 604 buffer.append('['); 605 buffer.append(getRelativePositionByName()); 606 buffer.append(']'); 607 } 608 else { 609 buffer.append("node()"); 610 buffer.append('['); 611 buffer.append(getRelativePositionOfElement()); 612 buffer.append(']'); 613 } 614 } 615 616 } 617 } 618 else if (node instanceof Text || node instanceof CDATA) { 619 buffer.append("/text()"); 620 buffer.append('[').append(getRelativePositionOfTextNode()).append( 621 ']'); 622 } 623 else if (node instanceof ProcessingInstruction) { 624 String target = ((ProcessingInstruction) node).getTarget(); 625 buffer.append("/processing-instruction(\'").append(target).append( 626 "')"); 627 buffer.append('[').append(getRelativePositionOfPI(target)).append( 628 ']'); 629 } 630 return buffer.toString(); 631 } 632 633 private String escape(String string) { 634 int index = string.indexOf('\''); 635 while (index != -1) { 636 string = 637 string.substring(0, index) 638 + "'" 639 + string.substring(index + 1); 640 index = string.indexOf('\''); 641 } 642 index = string.indexOf('\"'); 643 while (index != -1) { 644 string = 645 string.substring(0, index) 646 + """ 647 + string.substring(index + 1); 648 index = string.indexOf('\"'); 649 } 650 return string; 651 } 652 653 private int getRelativePositionByName() { 654 if (node instanceof Element) { 655 Object parent = ((Element) node).getParent(); 656 if (!(parent instanceof Element)) { 657 return 1; 658 } 659 660 List children = ((Element)parent).getContent(); 661 int count = 0; 662 String name = ((Element) node).getQualifiedName(); 663 for (int i = 0; i < children.size(); i++) { 664 Object child = children.get(i); 665 if ((child instanceof Element) 666 && ((Element) child).getQualifiedName().equals(name)) { 667 count++; 668 } 669 if (child == node) { 670 break; 671 } 672 } 673 return count; 674 } 675 return 1; 676 } 677 678 private int getRelativePositionOfElement() { 679 Element parent = (Element) ((Element) node).getParent(); 680 if (parent == null) { 681 return 1; 682 } 683 List children = parent.getContent(); 684 int count = 0; 685 for (int i = 0; i < children.size(); i++) { 686 Object child = children.get(i); 687 if (child instanceof Element) { 688 count++; 689 } 690 if (child == node) { 691 break; 692 } 693 } 694 return count; 695 } 696 697 private int getRelativePositionOfTextNode() { 698 Element parent; 699 if (node instanceof Text) { 700 parent = (Element) ((Text) node).getParent(); 701 } 702 else { 703 parent = (Element) ((CDATA) node).getParent(); 704 } 705 if (parent == null) { 706 return 1; 707 } 708 List children = parent.getContent(); 709 int count = 0; 710 for (int i = 0; i < children.size(); i++) { 711 Object child = children.get(i); 712 if (child instanceof Text || child instanceof CDATA) { 713 count++; 714 } 715 if (child == node) { 716 break; 717 } 718 } 719 return count; 720 } 721 722 private int getRelativePositionOfPI(String target) { 723 Element parent = (Element) ((ProcessingInstruction) node).getParent(); 724 if (parent == null) { 725 return 1; 726 } 727 List children = parent.getContent(); 728 int count = 0; 729 for (int i = 0; i < children.size(); i++) { 730 Object child = children.get(i); 731 if (child instanceof ProcessingInstruction 732 && (target == null 733 || target.equals( 734 ((ProcessingInstruction) child).getTarget()))) { 735 count++; 736 } 737 if (child == node) { 738 break; 739 } 740 } 741 return count; 742 } 743 744 public int hashCode() { 745 return System.identityHashCode(node); 746 } 747 748 public boolean equals(Object object) { 749 if (object == this) { 750 return true; 751 } 752 753 if (!(object instanceof JDOMNodePointer)) { 754 return false; 755 } 756 757 JDOMNodePointer other = (JDOMNodePointer) object; 758 return node == other.node; 759 } 760 private AbstractFactory getAbstractFactory(JXPathContext context) { 761 AbstractFactory factory = context.getFactory(); 762 if (factory == null) { 763 throw new JXPathException( 764 "Factory is not set on the JXPathContext - cannot create path: " 765 + asPath()); 766 } 767 return factory; 768 } 769 } | Popular Tags |