1 18 package org.apache.batik.dom; 19 20 import java.io.Serializable ; 21 22 import org.apache.batik.dom.util.DOMUtilities; 23 import org.w3c.dom.Attr ; 24 import org.w3c.dom.DOMException ; 25 import org.w3c.dom.Element ; 26 import org.w3c.dom.NamedNodeMap ; 27 import org.w3c.dom.Node ; 28 import org.w3c.dom.events.DocumentEvent ; 29 import org.w3c.dom.events.MutationEvent ; 30 31 37 public abstract class AbstractElement 38 extends AbstractParentChildNode 39 implements Element { 40 41 44 protected NamedNodeMap attributes; 45 46 49 protected AbstractElement() { 50 } 51 52 59 protected AbstractElement(String name, AbstractDocument owner) { 60 ownerDocument = owner; 61 if (!DOMUtilities.isValidName(name)) { 62 throw createDOMException(DOMException.INVALID_CHARACTER_ERR, 63 "xml.name", 64 new Object [] { name }); 65 } 66 } 67 68 72 public short getNodeType() { 73 return ELEMENT_NODE; 74 } 75 76 79 public boolean hasAttributes() { 80 return attributes != null && attributes.getLength() != 0; 81 } 82 83 86 public NamedNodeMap getAttributes() { 87 return (attributes == null) 88 ? attributes = createAttributes() 89 : attributes; 90 } 91 92 96 public String getTagName() { 97 return getNodeName(); 98 } 99 100 103 public boolean hasAttribute(String name) { 104 return attributes != null && attributes.getNamedItem(name) != null; 105 } 106 107 110 public String getAttribute(String name) { 111 if (attributes == null) { 112 return ""; 113 } 114 Attr attr = (Attr )attributes.getNamedItem(name); 115 return (attr == null) ? "" : attr.getValue(); 116 } 117 118 122 public void setAttribute(String name, String value) throws DOMException { 123 if (attributes == null) { 124 attributes = createAttributes(); 125 } 126 Attr attr = getAttributeNode(name); 127 if (attr == null) { 128 attr = getOwnerDocument().createAttribute(name); 129 attr.setValue(value); 130 attributes.setNamedItem(attr); 131 } else { 132 attr.setValue(value); 133 } 134 } 135 136 140 public void removeAttribute(String name) throws DOMException { 141 if (!hasAttribute(name)) { 142 return; 143 } 144 attributes.removeNamedItem(name); 145 } 146 147 151 public Attr getAttributeNode(String name) { 152 if (attributes == null) { 153 return null; 154 } 155 return (Attr )attributes.getNamedItem(name); 156 } 157 158 162 public Attr setAttributeNode(Attr newAttr) throws DOMException { 163 if (newAttr == null) { 164 return null; 165 } 166 if (attributes == null) { 167 attributes = createAttributes(); 168 } 169 return (Attr )attributes.setNamedItemNS(newAttr); 170 } 171 172 176 public Attr removeAttributeNode(Attr oldAttr) throws DOMException { 177 if (oldAttr == null) { 178 return null; 179 } 180 if (attributes == null) { 181 throw createDOMException(DOMException.NOT_FOUND_ERR, 182 "attribute.missing", 183 new Object [] { oldAttr.getName() }); 184 } 185 String nsURI = oldAttr.getNamespaceURI(); 186 return (Attr )attributes.removeNamedItemNS(nsURI, 187 (nsURI==null 188 ? oldAttr.getNodeName() 189 : oldAttr.getLocalName())); 190 } 191 192 195 public void normalize() { 196 super.normalize(); 197 if (attributes != null) { 198 NamedNodeMap map = getAttributes(); 199 for (int i = map.getLength() - 1; i >= 0; i--) { 200 map.item(i).normalize(); 201 } 202 } 203 } 204 205 209 public boolean hasAttributeNS(String namespaceURI, String localName) { 210 return attributes != null && 211 attributes.getNamedItemNS(namespaceURI, localName) != null; 212 } 213 214 218 public String getAttributeNS(String namespaceURI, String localName) { 219 if (attributes == null) { 220 return ""; 221 } 222 Attr attr = (Attr )attributes.getNamedItemNS(namespaceURI, localName); 223 return (attr == null) ? "" : attr.getValue(); 224 } 225 226 230 public void setAttributeNS(String namespaceURI, 231 String qualifiedName, 232 String value) throws DOMException { 233 if (attributes == null) { 234 attributes = createAttributes(); 235 } 236 Attr attr = getAttributeNodeNS(namespaceURI, qualifiedName); 237 if (attr == null) { 238 attr = getOwnerDocument().createAttributeNS(namespaceURI, 239 qualifiedName); 240 attr.setValue(value); 241 attributes.setNamedItemNS(attr); 242 } else { 243 attr.setValue(value); 244 } 245 } 246 247 251 public void removeAttributeNS(String namespaceURI, 252 String localName) throws DOMException { 253 if (!hasAttributeNS(namespaceURI, localName)) { 254 return; 255 } 256 attributes.removeNamedItemNS(namespaceURI, localName); 257 } 258 259 263 public Attr getAttributeNodeNS(String namespaceURI, 264 String localName) { 265 if (attributes == null) { 266 return null; 267 } 268 return (Attr )attributes.getNamedItemNS(namespaceURI, localName); 269 } 270 271 275 public Attr setAttributeNodeNS(Attr newAttr) throws DOMException { 276 if (newAttr == null) { 277 return null; 278 } 279 if (attributes == null) { 280 attributes = createAttributes(); 281 } 282 return (Attr )attributes.setNamedItemNS(newAttr); 283 } 284 285 288 protected void nodeAdded(Node node) { 289 invalidateElementsByTagName(node); 290 } 291 292 295 protected void nodeToBeRemoved(Node node) { 296 invalidateElementsByTagName(node); 297 } 298 299 302 private void invalidateElementsByTagName(Node node) { 303 if (node.getNodeType() != ELEMENT_NODE) { 304 return; 305 } 306 AbstractDocument ad = getCurrentDocument(); 307 String ns = node.getNamespaceURI(); 308 String nm = node.getNodeName(); 309 String ln = (ns == null) ? node.getNodeName() : node.getLocalName(); 310 for (Node n = this; n != null; n = n.getParentNode()) { 311 switch (n.getNodeType()) { 312 case ELEMENT_NODE: 313 case DOCUMENT_NODE: 314 ElementsByTagName l = ad.getElementsByTagName(n, nm); 315 if (l != null) { 316 l.invalidate(); 317 } 318 l = ad.getElementsByTagName(n, "*"); 319 if (l != null) { 320 l.invalidate(); 321 } 322 ElementsByTagNameNS lns = ad.getElementsByTagNameNS(n, ns, ln); 323 324 if (lns != null) { 325 lns.invalidate(); 326 } 327 lns = ad.getElementsByTagNameNS(n, "*", ln); 328 if (lns != null) { 329 lns.invalidate(); 330 } 331 lns = ad.getElementsByTagNameNS(n, ns, "*"); 332 if (lns != null) { 333 lns.invalidate(); 334 } 335 lns = ad.getElementsByTagNameNS(n, "*", "*"); 336 if (lns != null) { 337 lns.invalidate(); 338 } 339 } 340 } 341 342 Node c = node.getFirstChild(); 346 while (c != null) { 347 invalidateElementsByTagName(c); 348 c = c.getNextSibling(); 349 } 350 351 } 352 353 356 protected NamedNodeMap createAttributes() { 357 return new NamedNodeHashMap(); 358 } 359 360 365 protected Node export(Node n, AbstractDocument d) { 366 super.export(n, d); 367 AbstractElement ae = (AbstractElement)n; 368 if (attributes != null) { 369 NamedNodeMap map = attributes; 370 for (int i = map.getLength() - 1; i >= 0; i--) { 371 AbstractAttr aa = (AbstractAttr)map.item(i); 372 if (aa.getSpecified()) { 373 Attr attr = (Attr )aa.deepExport(aa.cloneNode(false), d); 374 if (aa instanceof AbstractAttrNS) { 375 ae.setAttributeNodeNS(attr); 376 } else { 377 ae.setAttributeNode(attr); 378 } 379 } 380 } 381 } 382 return n; 383 } 384 385 390 protected Node deepExport(Node n, AbstractDocument d) { 391 super.deepExport(n, d); 392 AbstractElement ae = (AbstractElement)n; 393 if (attributes != null) { 394 NamedNodeMap map = attributes; 395 for (int i = map.getLength() - 1; i >= 0; i--) { 396 AbstractAttr aa = (AbstractAttr)map.item(i); 397 if (aa.getSpecified()) { 398 Attr attr = (Attr )aa.deepExport(aa.cloneNode(false), d); 399 if (aa instanceof AbstractAttrNS) { 400 ae.setAttributeNodeNS(attr); 401 } else { 402 ae.setAttributeNode(attr); 403 } 404 } 405 } 406 } 407 return n; 408 } 409 410 414 protected Node copyInto(Node n) { 415 super.copyInto(n); 416 AbstractElement ae = (AbstractElement)n; 417 if (attributes != null) { 418 NamedNodeMap map = attributes; 419 for (int i = map.getLength() - 1; i >= 0; i--) { 420 AbstractAttr aa = (AbstractAttr)map.item(i).cloneNode(true); 421 if (aa instanceof AbstractAttrNS) { 422 ae.setAttributeNodeNS(aa); 423 } else { 424 ae.setAttributeNode(aa); 425 } 426 } 427 } 428 return n; 429 } 430 431 435 protected Node deepCopyInto(Node n) { 436 super.deepCopyInto(n); 437 AbstractElement ae = (AbstractElement)n; 438 if (attributes != null) { 439 NamedNodeMap map = attributes; 440 for (int i = map.getLength() - 1; i >= 0; i--) { 441 AbstractAttr aa = (AbstractAttr)map.item(i).cloneNode(true); 442 if (aa instanceof AbstractAttrNS) { 443 ae.setAttributeNodeNS(aa); 444 } else { 445 ae.setAttributeNode(aa); 446 } 447 } 448 } 449 return n; 450 } 451 452 456 protected void checkChildType(Node n, boolean replace) { 457 switch (n.getNodeType()) { 458 case ELEMENT_NODE: 459 case PROCESSING_INSTRUCTION_NODE: 460 case COMMENT_NODE: 461 case TEXT_NODE: 462 case CDATA_SECTION_NODE: 463 case ENTITY_REFERENCE_NODE: 464 case DOCUMENT_FRAGMENT_NODE: 465 break; 466 default: 467 throw createDOMException 468 (DOMException.HIERARCHY_REQUEST_ERR, 469 "child.type", 470 new Object [] { new Integer (getNodeType()), 471 getNodeName(), 472 new Integer (n.getNodeType()), 473 n.getNodeName() }); 474 } 475 } 476 477 488 public void fireDOMAttrModifiedEvent(String name, Attr node, String oldv, 489 String newv, short change) { 490 switch (change) { 491 case MutationEvent.ADDITION: 492 if (((AbstractAttr)node).isId()) 493 ownerDocument.addIdEntry(this, newv); 494 attrAdded(node, newv); 495 break; 496 497 case MutationEvent.MODIFICATION: 498 if (((AbstractAttr)node).isId()) 499 ownerDocument.updateIdEntry(this, oldv, newv); 500 attrModified(node, oldv, newv); 501 break; 502 503 default: if (((AbstractAttr)node).isId()) 505 ownerDocument.removeIdEntry(this, oldv); 506 attrRemoved(node, oldv); 507 } 508 AbstractDocument doc = getCurrentDocument(); 509 if (doc.getEventsEnabled() && !oldv.equals(newv)) { 510 DocumentEvent de = (DocumentEvent )doc; 511 MutationEvent ev = (MutationEvent )de.createEvent("MutationEvents"); 512 ev.initMutationEvent("DOMAttrModified", 513 true, false, node, oldv, newv, name, change); dispatchEvent(ev); 521 } 522 } 523 524 527 protected void attrAdded(Attr node, String newv) { 528 } 529 530 533 protected void attrModified(Attr node, String oldv, String newv) { 534 } 535 536 539 protected void attrRemoved(Attr node, String oldv) { 540 } 541 542 545 public class NamedNodeHashMap implements NamedNodeMap , Serializable { 546 547 550 protected final static int INITIAL_CAPACITY = 3; 551 552 555 protected Entry[] table; 556 557 560 protected int count; 561 562 565 public NamedNodeHashMap() { 566 table = new Entry[INITIAL_CAPACITY]; 567 } 568 569 573 public Node getNamedItem(String name) { 574 if (name == null) { 575 return null; 576 } 577 return get(null, name); 578 } 579 580 584 public Node setNamedItem(Node arg) throws DOMException { 585 if (arg == null) { 586 return null; 587 } 588 checkNode(arg); 589 590 return setNamedItem(null, arg.getNodeName(), arg); 591 } 592 593 597 public Node removeNamedItem(String name) throws DOMException { 598 return removeNamedItemNS(null, name); 599 } 600 601 604 public Node item(int index) { 605 if (index < 0 || index >= count) { 606 return null; 607 } 608 int j = 0; 609 for (int i = 0; i < table.length; i++) { 610 Entry e = table[i]; 611 if (e == null) { 612 continue; 613 } 614 do { 615 if (j++ == index) { 616 return e.value; 617 } 618 e = e.next; 619 } while (e != null); 620 } 621 return null; 622 } 623 624 627 public int getLength() { 628 return count; 629 } 630 631 635 public Node getNamedItemNS(String namespaceURI, String localName) { 636 return get(namespaceURI, localName); 637 } 638 639 643 public Node setNamedItemNS(Node arg) throws DOMException { 644 if (arg == null) { 645 return null; 646 } 647 String nsURI = arg.getNamespaceURI(); 648 return setNamedItem(nsURI, 649 (nsURI == null) 650 ? arg.getNodeName() 651 : arg.getLocalName(), arg); 652 } 653 654 658 public Node removeNamedItemNS(String namespaceURI, String localName) 659 throws DOMException { 660 if (isReadonly()) { 661 throw createDOMException 662 (DOMException.NO_MODIFICATION_ALLOWED_ERR, 663 "readonly.node.map", 664 new Object [] {}); 665 } 666 if (localName == null) { 667 throw createDOMException(DOMException.NOT_FOUND_ERR, 668 "attribute.missing", 669 new Object [] { "" }); 670 } 671 AbstractAttr n = (AbstractAttr)remove(namespaceURI, localName); 672 if (n == null) { 673 throw createDOMException(DOMException.NOT_FOUND_ERR, 674 "attribute.missing", 675 new Object [] { localName }); 676 } 677 n.setOwnerElement(null); 678 679 fireDOMAttrModifiedEvent(n.getNodeName(), n, n.getNodeValue(), "", 681 MutationEvent.REMOVAL); 682 return n; 683 } 684 685 688 public Node setNamedItem(String ns, String name, Node arg) 689 throws DOMException { 690 ((AbstractAttr)arg).setOwnerElement(AbstractElement.this); 691 AbstractAttr result = (AbstractAttr)put(ns, name, arg); 692 693 if (result != null) { 694 result.setOwnerElement(null); 695 fireDOMAttrModifiedEvent(name, 696 result, 697 result.getNodeValue(), 698 "", 699 MutationEvent.REMOVAL); 700 } 701 fireDOMAttrModifiedEvent(name, 702 (Attr )arg, 703 "", 704 arg.getNodeValue(), 705 MutationEvent.ADDITION); 706 return result; 707 } 708 709 712 protected void checkNode(Node arg) { 713 if (isReadonly()) { 714 throw createDOMException 715 (DOMException.NO_MODIFICATION_ALLOWED_ERR, 716 "readonly.node.map", 717 new Object [] {}); 718 } 719 if (getOwnerDocument() != arg.getOwnerDocument()) { 720 throw createDOMException(DOMException.WRONG_DOCUMENT_ERR, 721 "node.from.wrong.document", 722 new Object [] { new Integer 723 (arg.getNodeType()), 724 arg.getNodeName() }); 725 } 726 if (arg.getNodeType() == ATTRIBUTE_NODE && 727 ((Attr )arg).getOwnerElement() != null) { 728 throw createDOMException(DOMException.WRONG_DOCUMENT_ERR, 729 "inuse.attribute", 730 new Object [] { arg.getNodeName() }); 731 } 732 } 733 734 738 protected Node get(String ns, String nm) { 739 int hash = hashCode(ns, nm) & 0x7FFFFFFF; 740 int index = hash % table.length; 741 742 for (Entry e = table[index]; e != null; e = e.next) { 743 if ((e.hash == hash) && e.match(ns, nm)) { 744 return e.value; 745 } 746 } 747 return null; 748 } 749 750 754 protected Node put(String ns, String nm, Node value) { 755 int hash = hashCode(ns, nm) & 0x7FFFFFFF; 756 int index = hash % table.length; 757 758 for (Entry e = table[index]; e != null; e = e.next) { 759 if ((e.hash == hash) && e.match(ns, nm)) { 760 Node old = e.value; 761 e.value = value; 762 return old; 763 } 764 } 765 766 int len = table.length; 768 if (count++ >= (len * 3) >>> 2) { 769 rehash(); 770 index = hash % table.length; 771 } 772 773 Entry e = new Entry(hash, ns, nm, value, table[index]); 774 table[index] = e; 775 return null; 776 } 777 778 782 protected Node remove(String ns, String nm) { 783 int hash = hashCode(ns, nm) & 0x7FFFFFFF; 784 int index = hash % table.length; 785 786 Entry p = null; 787 for (Entry e = table[index]; e != null; e = e.next) { 788 if ((e.hash == hash) && e.match(ns, nm)) { 789 Node result = e.value; 790 if (p == null) { 791 table[index] = e.next; 792 } else { 793 p.next = e.next; 794 } 795 count--; 796 return result; 797 } 798 p = e; 799 } 800 return null; 801 } 802 803 806 protected void rehash () { 807 Entry[] oldTable = table; 808 809 table = new Entry[oldTable.length * 2 + 1]; 810 811 for (int i = oldTable.length-1; i >= 0; i--) { 812 for (Entry old = oldTable[i]; old != null;) { 813 Entry e = old; 814 old = old.next; 815 816 int index = e.hash % table.length; 817 e.next = table[index]; 818 table[index] = e; 819 } 820 } 821 } 822 823 826 protected int hashCode(String ns, String nm) { 827 int result = (ns == null) ? 0 : ns.hashCode(); 828 return result ^ nm.hashCode(); 829 } 830 } 831 832 835 protected static class Entry implements Serializable { 836 837 840 public int hash; 841 842 845 public String namespaceURI; 846 847 850 public String name; 851 852 855 public Node value; 856 857 860 public Entry next; 861 862 865 public Entry(int hash, String ns, String nm, Node value, Entry next) { 866 this.hash = hash; 867 this.namespaceURI = ns; 868 this.name = nm; 869 this.value = value; 870 this.next = next; 871 } 872 873 876 public boolean match(String ns, String nm) { 877 if (namespaceURI != null) { 878 if (!namespaceURI.equals(ns)) { 879 return false; 880 } 881 } else if (ns != null) { 882 return false; 883 } 884 return name.equals(nm); 885 } 886 } 887 888 } 889 | Popular Tags |