1 21 package au.id.jericho.lib.html; 22 23 import java.util.*; 24 25 120 public abstract class Tag extends Segment implements HTMLElementName { 121 String name=null; Element element=Element.NOT_CACHED; int allTagsArrayIndex=-1; 124 private Object userData=null; 125 126 130 public static final String PROCESSING_INSTRUCTION=StartTagType.XML_PROCESSING_INSTRUCTION.getNamePrefixForTagConstant(); 131 132 136 public static final String XML_DECLARATION=StartTagType.XML_DECLARATION.getNamePrefixForTagConstant(); 137 138 142 public static final String DOCTYPE_DECLARATION=StartTagType.DOCTYPE_DECLARATION.getNamePrefixForTagConstant(); 143 144 148 public static final String SERVER_PHP=PHPTagTypes.PHP_STANDARD.getNamePrefixForTagConstant(); 149 150 154 public static final String SERVER_COMMON=StartTagType.SERVER_COMMON.getNamePrefixForTagConstant(); 155 156 160 public static final String SERVER_MASON_NAMED_BLOCK=MasonTagTypes.MASON_NAMED_BLOCK.getNamePrefixForTagConstant(); 162 166 public static final String SERVER_MASON_COMPONENT_CALL=MasonTagTypes.MASON_COMPONENT_CALL.getNamePrefixForTagConstant(); 167 168 172 public static final String SERVER_MASON_COMPONENT_CALLED_WITH_CONTENT=MasonTagTypes.MASON_COMPONENT_CALLED_WITH_CONTENT.getNamePrefixForTagConstant(); 173 174 private static final boolean INCLUDE_UNREGISTERED_IN_SEARCH=false; 176 Tag(final Source source, final int begin, final int end, final String name) { 177 super(source, begin, end); 178 this.name=HTMLElements.getConstantElementName(name.toLowerCase()); 179 } 180 181 190 public abstract Element getElement(); 191 192 213 public final String getName() { 214 return name; 215 } 216 217 227 public Segment getNameSegment() { 228 final int nameSegmentBegin=begin+getTagType().startDelimiterPrefix.length(); 229 return new Segment(source,nameSegmentBegin,nameSegmentBegin+name.length()); 230 } 231 232 236 public abstract TagType getTagType(); 237 238 245 public Object getUserData() { 246 return userData; 247 } 248 249 257 public void setUserData(final Object userData) { 258 this.userData=userData; 259 } 260 261 272 public Tag findNextTag() { 273 final Tag[] allTagsArray=source.allTagsArray; 274 if (allTagsArray!=null) { 275 final int nextAllTagsArrayIndex=allTagsArrayIndex+1; 276 if (allTagsArray.length==nextAllTagsArrayIndex) return null; 277 return allTagsArray[nextAllTagsArrayIndex]; 278 } else { 279 return source.findNextTag(begin+1); 280 } 281 } 282 283 294 public Tag findPreviousTag() { 295 final Tag[] allTagsArray=source.allTagsArray; 296 if (allTagsArray!=null) { 297 if (allTagsArrayIndex==0) return null; 298 return allTagsArray[allTagsArrayIndex-1]; 299 } else { 300 if (begin==0) return null; 301 return source.findPreviousTag(begin-1); 302 } 303 } 304 305 343 public abstract boolean isUnregistered(); 344 345 353 public abstract String tidy(); 354 355 370 public static final boolean isXMLName(final CharSequence text) { 371 if (text==null || text.length()==0 || !isXMLNameStartChar(text.charAt(0))) return false; 372 for (int i=1; i<text.length(); i++) 373 if (!isXMLNameChar(text.charAt(i))) return false; 374 return true; 375 } 376 377 396 public static final boolean isXMLNameStartChar(final char ch) { 397 return Character.isLetter(ch) || ch=='_' || ch==':'; 398 } 399 400 422 public static final boolean isXMLNameChar(final char ch) { 423 return Character.isLetterOrDigit(ch) || ch=='.' || ch=='-' || ch=='_' || ch==':'; 424 } 425 426 434 public abstract String regenerateHTML(); 435 436 final boolean includeInSearch() { 437 return INCLUDE_UNREGISTERED_IN_SEARCH || !isUnregistered(); 438 } 439 440 static final Tag findPreviousOrNextTag(final Source source, final int pos, final boolean previous) { 441 return source.useAllTypesCache 443 ? source.cache.findPreviousOrNextTag(pos,previous) 444 : findPreviousOrNextTagUncached(source,pos,previous,ParseText.NO_BREAK); 445 } 446 447 static final Tag findPreviousOrNextTagUncached(final Source source, final int pos, final boolean previous, final int breakAtPos) { 448 try { 450 final ParseText parseText=source.getParseText(); 451 int begin=pos; 452 do { 453 begin=previous?parseText.lastIndexOf('<',begin,breakAtPos):parseText.indexOf('<',begin,breakAtPos); if (begin==-1) return null; 456 final Tag tag=getTagAt(source,begin); 457 if (tag!=null && tag.includeInSearch()) return tag; 458 } while (previous ? (begin-=1)>=0 : (begin+=1)<source.end); 459 } catch (IndexOutOfBoundsException ex) { 460 } 463 return null; 464 } 465 466 static final Tag findPreviousOrNextTag(final Source source, final int pos, final TagType tagType, final boolean previous) { 467 if (source.useSpecialTypesCache) return source.cache.findPreviousOrNextTag(pos,tagType,previous); 469 return findPreviousOrNextTagUncached(source,pos,tagType,previous,ParseText.NO_BREAK); 470 } 471 472 static final Tag findPreviousOrNextTagUncached(final Source source, final int pos, final TagType tagType, final boolean previous, final int breakAtPos) { 473 if (tagType==null) return findPreviousOrNextTagUncached(source,pos,previous,breakAtPos); 475 final char[] startDelimiterCharArray=tagType.getStartDelimiterCharArray(); 476 try { 477 final ParseText parseText=source.getParseText(); 478 int begin=pos; 479 do { 480 begin=previous?parseText.lastIndexOf(startDelimiterCharArray,begin,breakAtPos):parseText.indexOf(startDelimiterCharArray,begin,breakAtPos); 481 if (begin==-1) return null; 483 final Tag tag=getTagAt(source,begin); 484 if (tag!=null && tag.getTagType()==tagType) return tag; 485 } while (previous ? (begin-=1)>=0 : (begin+=1)<source.end); 486 } catch (IndexOutOfBoundsException ex) { 487 } 490 return null; 491 } 492 493 static final Tag getTagAt(final Source source, final int pos) { 494 return source.useAllTypesCache 496 ? source.cache.getTagAt(pos) 497 : getTagAtUncached(source,pos); 498 } 499 500 static final Tag getTagAtUncached(final Source source, final int pos) { 501 return TagType.getTagAt(source,pos,false); 503 } 504 505 static final Tag[] parseAll(final Source source, final boolean assumeNoNestedTags) { 506 int registeredTagCount=0; 507 int registeredStartTagCount=0; 508 final ArrayList list=new ArrayList(); 509 if (source.end!=0) { 510 final ParseText parseText=source.getParseText(); 511 Tag tag=parseAllFindNextTag(source,parseText,0,assumeNoNestedTags); 512 while (tag!=null) { 513 list.add(tag); 514 if (!tag.isUnregistered()) { 515 registeredTagCount++; 516 if (tag instanceof StartTag) registeredStartTagCount++; 517 } 518 final int pos=(assumeNoNestedTags && !tag.isUnregistered()) ? tag.end : tag.begin+1; 520 if (pos==source.end) break; 521 tag=parseAllFindNextTag(source,parseText,pos,assumeNoNestedTags); 522 } 523 } 524 final Tag[] allRegisteredTags=new Tag[registeredTagCount]; 525 final StartTag[] allRegisteredStartTags=new StartTag[registeredStartTagCount]; 526 source.cache.loadAllTags(list,allRegisteredTags,allRegisteredStartTags); 527 source.allTagsArray=allRegisteredTags; 528 source.allTags=Arrays.asList(allRegisteredTags); 529 source.allStartTags=Arrays.asList(allRegisteredStartTags); 530 for (int i=0; i<allRegisteredTags.length; i++) allRegisteredTags[i].allTagsArrayIndex=i; 531 return allRegisteredTags; 532 } 533 534 private static final Tag parseAllFindNextTag(final Source source, final ParseText parseText, final int pos, final boolean assumeNoNestedTags) { 535 try { 536 int begin=pos; 537 do { 538 begin=parseText.indexOf('<',begin); if (begin==-1) return null; 540 final Tag tag=TagType.getTagAt(source,begin,assumeNoNestedTags); 541 if (tag!=null) { 542 if (!assumeNoNestedTags) { 543 final TagType tagType=tag.getTagType(); 544 if (tag.end>source.endOfLastTagIgnoringEnclosedMarkup 545 && !tagType.isServerTag() 546 && tagType!=StartTagType.DOCTYPE_DECLARATION 547 && tagType!=StartTagType.UNREGISTERED && tagType!=EndTagType.UNREGISTERED) 548 source.endOfLastTagIgnoringEnclosedMarkup=tag.end; 549 } 550 return tag; 551 } 552 } while ((begin+=1)<source.end); 553 } catch (IndexOutOfBoundsException ex) { 554 } 557 return null; 558 } 559 560 static Iterator getNextTagIterator(final Source source, final int pos) { 562 return new NextTagIterator(source,pos); 563 } 564 565 private static final class NextTagIterator implements Iterator { 566 private Tag nextTag=null; 567 568 public NextTagIterator(final Source source, final int pos) { 569 nextTag=findPreviousOrNextTag(source,pos,false); 570 } 571 572 public boolean hasNext() { 573 return nextTag!=null; 574 } 575 576 public Object next() { 577 final Tag result=nextTag; 578 try { 579 nextTag=findPreviousOrNextTag(result.source,result.begin+1,false); 580 } catch (NullPointerException ex) { 581 throw new NoSuchElementException(); 582 } 583 return result; 584 } 585 586 public void remove() { 587 throw new UnsupportedOperationException (); 588 } 589 } 590 } 591 | Popular Tags |