| 1 21 22 package nu.xom; 23 24 import java.util.ArrayList ; 25 import java.util.HashSet ; 26 import java.util.Iterator ; 27 import java.util.NoSuchElementException ; 28 import java.util.Set ; 29 import java.util.SortedSet ; 30 import java.util.TreeSet ; 31 32 52 public class Element extends ParentNode { 53 54 private String localName; 55 private String prefix; 56 private String URI; 57 58 private ArrayList attributes = null; 59 private Namespaces namespaces = null; 60 61 71 public Element(String name) { 72 this(name, ""); 73 } 74 75 76 91 public Element(String name, String uri) { 92 93 String prefix = ""; 96 String localName = name; 97 int colon = name.indexOf(':'); 98 if (colon > 0) { 99 prefix = name.substring(0, colon); 100 localName = name.substring(colon + 1); 101 } 102 103 _setNamespacePrefix(prefix); 106 _setNamespaceURI(uri); 107 try { 108 _setLocalName(localName); 109 } 110 catch (IllegalNameException ex) { 111 ex.setData(name); 112 throw ex; 113 } 114 115 } 116 117 118 private Element() {} 119 120 121 static Element build(String name, String uri) { 122 123 Element result = new Element(); 124 String prefix = ""; 125 String localName = name; 126 int colon = name.indexOf(':'); 127 if (colon >= 0) { 128 prefix = name.substring(0, colon); 129 localName = name.substring(colon + 1); 130 } 131 result.prefix = prefix; 132 result.localName = localName; 133 if (! "".equals(uri)) Verifier.checkAbsoluteURIReference(uri); 139 result.URI = uri; 140 return result; 141 142 } 143 144 145 155 public Element(Element element) { 156 157 this.prefix = element.prefix; 158 this.localName = element.localName; 159 this.URI = element.URI; 160 161 if (element.namespaces != null) { 163 this.namespaces = element.namespaces.copy(); 164 } 165 166 if (element.attributes != null) { 168 this.attributes = element.copyAttributes(); 169 } 170 171 this.actualBaseURI = element.findActualBaseURI(); 172 173 copyChildren(element, this); 174 175 } 176 177 178 private ArrayList copyAttributes() { 179 180 int size = attributes.size(); 181 ArrayList copy = new ArrayList (size); 182 for (int i = 0; i < size; i++) { 183 copy.add(((Attribute) attributes.get(i)).copy()); 184 } 185 return copy; 186 187 } 188 189 190 private static Element copyTag(final Element source) { 191 192 Element result = source.shallowCopy(); 193 194 if (source.namespaces != null) { 196 result.namespaces = source.namespaces.copy(); 197 } 198 199 if (source.attributes != null) { 201 result.attributes = source.copyAttributes(); 202 } 203 204 result.actualBaseURI = source.findActualBaseURI(); 205 206 return result; 207 208 } 209 210 211 private static void copyChildren(final Element sourceElement, 212 Element resultElement) { 213 214 if (sourceElement.getChildCount() == 0) return; 215 ParentNode resultParent = resultElement; 216 Node sourceCurrent = sourceElement; 217 int index = 0; 218 int[] indexes = new int[10]; 219 int top = 0; 220 indexes[0] = 0; 221 222 boolean endTag = false; 225 226 while (true) { 227 if (!endTag && sourceCurrent.getChildCount() > 0) { 228 sourceCurrent = sourceCurrent.getChild(0); 229 index = 0; 230 top++; 231 indexes = grow(indexes, top); 232 indexes[top] = 0; 233 } 234 else { 235 endTag = false; 236 ParentNode sourceParent = sourceCurrent.getParent(); 237 if (sourceParent.getChildCount() - 1 == index) { 238 sourceCurrent = sourceParent; 239 top--; 240 if (sourceCurrent == sourceElement) break; 241 resultParent = (Element) resultParent.getParent(); 243 index = indexes[top]; 244 endTag = true; 245 continue; 246 } 247 else { 248 index++; 249 indexes[top] = index; 250 sourceCurrent = sourceParent.getChild(index); 251 } 252 } 253 254 if (sourceCurrent.isElement()) { 255 Element child = copyTag((Element) sourceCurrent); 256 resultParent.appendChild(child); 257 if (sourceCurrent.getChildCount() > 0) { 258 resultParent = child; 259 } 260 } 261 else { 262 Node child = sourceCurrent.copy(); 263 resultParent.appendChild(child); 264 } 265 266 } 267 268 } 269 270 271 private static int[] grow(int[] indexes, int top) { 272 273 if (top < indexes.length) return indexes; 274 int[] result = new int[indexes.length*2]; 275 System.arraycopy(indexes, 0, result, 0, indexes.length); 276 return result; 277 278 } 279 280 281 293 public final Elements getChildElements(String name) { 294 return getChildElements(name, ""); 295 } 296 297 298 317 public final Elements getChildElements(String localName, 318 String namespaceURI) { 319 320 if (namespaceURI == null) namespaceURI = ""; 321 if (localName == null) localName = ""; 322 323 Elements elements = new Elements(); 324 for (int i = 0; i < getChildCount(); i++) { 325 Node child = getChild(i); 326 if (child.isElement()) { 327 Element element = (Element) child; 328 if ((localName.equals(element.getLocalName()) 329 || localName.length() == 0) 330 && namespaceURI.equals(element.getNamespaceURI())) { 331 elements.add(element); 332 } 333 } 334 } 335 return elements; 336 337 } 338 339 340 349 public final Elements getChildElements() { 350 351 Elements elements = new Elements(); 352 for (int i = 0; i < getChildCount(); i++) { 353 Node child = getChild(i); 354 if (child.isElement()) { 355 Element element = (Element) child; 356 elements.add(element); 357 } 358 } 359 return elements; 360 361 } 362 363 364 376 public final Element getFirstChildElement(String name) { 377 return getFirstChildElement(name, ""); 378 } 379 380 381 394 public final Element getFirstChildElement(String localName, 395 String namespaceURI) { 396 397 for (int i = 0; i < getChildCount(); i++) { 398 Node child = getChild(i); 399 if (child.isElement()) { 400 Element element = (Element) child; 401 if (localName.equals(element.getLocalName()) 402 && namespaceURI.equals(element.getNamespaceURI())) { 403 return element; 404 } 405 } 406 } 407 return null; 408 409 } 410 411 412 428 public void addAttribute(Attribute attribute) { 429 430 if (attribute.getParent() != null) { 431 throw new MultipleParentException( 432 "Attribute already has a parent"); 433 } 434 435 String attPrefix = attribute.getNamespacePrefix(); 437 if (attPrefix.length() != 0 && !"xml".equals(attPrefix)) { 438 if (prefix.equals(attribute.getNamespacePrefix()) 439 && !(getNamespaceURI() 440 .equals(attribute.getNamespaceURI()))) { 441 throw new NamespaceConflictException("Prefix of " 442 + attribute.getQualifiedName() 443 + " conflicts with element prefix " + prefix); 444 } 445 if (namespaces != null) { 447 String existing 448 = namespaces.getURI(attribute.getNamespacePrefix()); 449 if (existing != null 450 && !existing.equals(attribute.getNamespaceURI())) { 451 throw new NamespaceConflictException("Attribute prefix " 452 + attPrefix 453 + " conflicts with namespace declaration."); 454 } 455 } 456 457 } 458 459 if (attributes == null) attributes = new ArrayList (1); 460 checkPrefixConflict(attribute); 461 462 Attribute oldAttribute = getAttribute(attribute.getLocalName(), 465 attribute.getNamespaceURI()); 466 if (oldAttribute != null) attributes.remove(oldAttribute); 467 468 attributes.add(attribute); 469 attribute.setParent(this); 470 471 } 472 473 474 void fastAddAttribute(Attribute attribute) { 475 if (attributes == null) attributes = new ArrayList (1); 476 attributes.add(attribute); 477 attribute.setParent(this); 478 } 479 480 481 494 public Attribute removeAttribute(Attribute attribute) { 495 496 if (attributes == null) { 497 throw new NoSuchAttributeException( 498 "Tried to remove attribute " 499 + attribute.getQualifiedName() 500 + " from non-parent element"); 501 } 502 if (attribute == null) { 503 throw new NullPointerException ( 504 "Tried to remove null attribute"); 505 } 506 if (attributes.remove(attribute)) { 507 attribute.setParent(null); 508 return attribute; 509 } 510 else { 511 throw new NoSuchAttributeException( 512 "Tried to remove attribute " 513 + attribute.getQualifiedName() 514 + " from non-parent element"); 515 } 516 517 } 518 519 520 531 public final Attribute getAttribute(String name) { 532 return getAttribute(name, ""); 533 } 534 535 536 549 public final Attribute getAttribute(String localName, 550 String namespaceURI) { 551 552 if (attributes == null) return null; 553 int size = attributes.size(); 554 for (int i = 0; i < size; i++) { 555 Attribute a = (Attribute) attributes.get(i); 556 if (a.getLocalName().equals(localName) 557 && a.getNamespaceURI().equals(namespaceURI)) { 558 return a; 559 } 560 } 561 562 return null; 563 564 } 565 566 567 580 public final String getAttributeValue(String name) { 581 return getAttributeValue(name, ""); 582 } 583 584 585 595 public final int getAttributeCount() { 596 if (attributes == null) return 0; 597 return attributes.size(); 598 } 599 600 601 631 public final Attribute getAttribute(int index) { 632 633 if (attributes == null) { 634 throw new IndexOutOfBoundsException ( 635 "Element does not have any attributes" 636 ); 637 } 638 return (Attribute) attributes.get(index); 639 640 } 641 642 643 656 public final String getAttributeValue(String localName, 657 String namespaceURI) { 658 659 Attribute attribute = getAttribute(localName, namespaceURI); 660 if (attribute == null) return null; 661 else return attribute.getValue(); 662 663 } 664 665 666 674 public final String getLocalName() { 675 return localName; 676 } 677 678 679 687 public final String getQualifiedName() { 688 if (prefix.length() == 0) return localName; 689 else return prefix + ":" + localName; 690 } 691 692 693 701 public final String getNamespacePrefix() { 702 return prefix; 703 } 704 705 706 715 public final String getNamespaceURI() { 716 return URI; 717 } 718 719 720 731 public final String getNamespaceURI(String prefix) { 732 733 Element current = this; 734 String result = getLocalNamespaceURI(prefix); 735 while (result == null) { 736 ParentNode parent = current.getParent(); 737 if (parent == null || parent.isDocument()) break; 738 current = (Element) parent; 739 result = current.getLocalNamespaceURI(prefix); 740 } 741 if (result == null && "".equals(prefix)) result = ""; 742 return result; 743 744 } 745 746 747 String getLocalNamespaceURI(String prefix) { 748 749 if (prefix.equals(this.prefix)) return this.URI; 750 751 if ("xml".equals(prefix)) { 752 return "http://www.w3.org/XML/1998/namespace"; 753 } 754 if ("xmlns".equals(prefix)) return ""; 758 if (namespaces != null) { 760 String result = namespaces.getURI(prefix); 761 if (result != null) return result; 762 } 763 if (prefix.length() != 0 && attributes != null) { 765 for (int i = 0; i < attributes.size(); i++) { 766 Attribute a = (Attribute) attributes.get(i); 767 if (a.getNamespacePrefix().equals(prefix)) { 768 return a.getNamespaceURI(); 769 } 770 } 771 } 772 773 return null; 774 775 } 776 777 778 788 public void setLocalName(String localName) { 789 _setLocalName(localName); 790 } 791 792 793 private void _setLocalName(String localName) { 794 Verifier.checkNCName(localName); 795 this.localName = localName; 796 } 797 798 799 813 public void setNamespaceURI(String uri) { 814 _setNamespaceURI(uri); 815 } 816 817 818 private void _setNamespaceURI(String uri) { 819 820 if (uri == null) uri = ""; 821 if (uri.equals(this.URI)) return; 824 if (uri.length() == 0) { if (prefix.length() != 0) { 826 throw new NamespaceConflictException( 827 "Prefixed elements must have namespace URIs." 828 ); 829 } 830 } 831 else Verifier.checkAbsoluteURIReference(uri); 832 if (namespaces != null) { 839 String result = namespaces.getURI(prefix); 840 if (result != null) { 841 throw new NamespaceConflictException( 842 "new URI conflicts with existing prefix" 843 ); 844 } 845 } 846 if (uri.length() > 0 && attributes != null) { 848 for (int i = 0; i < attributes.size(); i++) { 849 Attribute a = (Attribute) attributes.get(i); 850 String attPrefix = a.getNamespacePrefix(); 851 if (attPrefix.length() == 0) continue; 852 if (a.getNamespacePrefix().equals(prefix)) { 853 throw new NamespaceConflictException( 854 "new element URI " + uri 855 + " conflicts with attribute " 856 + a.getQualifiedName() 857 ); 858 } 859 } 860 } 861 862 if ("http://www.w3.org/XML/1998/namespace".equals(uri) 863 && ! "xml".equals(prefix)) { 864 throw new NamespaceConflictException( 865 "Wrong prefix " + prefix + 866 " for the http://www.w3.org/XML/1998/namespace namespace URI" 867 ); 868 } 869 else if ("xml".equals(prefix) && 870 !"http://www.w3.org/XML/1998/namespace".equals(uri)) { 871 throw new NamespaceConflictException( 872 "Wrong namespace URI " + uri + " for the xml prefix" 873 ); 874 } 875 876 this.URI = uri; 877 878 } 879 880 881 896 public void setNamespacePrefix(String prefix) { 897 _setNamespacePrefix(prefix); 898 } 899 900 901 private void _setNamespacePrefix(String prefix) { 902 903 if (prefix == null) prefix = ""; 904 if (prefix.length() != 0) Verifier.checkNCName(prefix); 905 906 String uri = getLocalNamespaceURI(prefix); 910 if (uri != null) { 911 if (!uri.equals(this.URI) && !"xml".equals(prefix)) { 912 throw new NamespaceConflictException(prefix 913 + " conflicts with existing prefix"); 914 } 915 } 916 else if ("".equals(this.URI) && !"".equals(prefix)) { 917 throw new NamespaceConflictException( 918 "Cannot assign prefix to element in no namespace"); 919 } 920 921 this.prefix = prefix; 922 &
|