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