1 15 package org.apache.tapestry.parse; 16 17 import java.util.ArrayList ; 18 import java.util.Collections ; 19 import java.util.HashMap ; 20 import java.util.Iterator ; 21 import java.util.List ; 22 import java.util.Map ; 23 24 import org.apache.hivemind.ApplicationRuntimeException; 25 import org.apache.hivemind.Location; 26 import org.apache.hivemind.Resource; 27 import org.apache.hivemind.impl.LocationImpl; 28 import org.apache.oro.text.regex.MalformedPatternException; 29 import org.apache.oro.text.regex.MatchResult; 30 import org.apache.oro.text.regex.Pattern; 31 import org.apache.oro.text.regex.PatternMatcher; 32 import org.apache.oro.text.regex.Perl5Compiler; 33 import org.apache.oro.text.regex.Perl5Matcher; 34 import org.apache.tapestry.util.IdAllocator; 35 36 90 91 public class TemplateParser implements ITemplateParser 92 { 93 97 98 private static final String REMOVE_ID = "$remove$"; 99 100 105 106 private static final String CONTENT_ID = "$content$"; 107 108 114 115 public static final String LOCALIZATION_KEY_ATTRIBUTE_NAME = "key"; 116 117 124 125 public static final String RAW_ATTRIBUTE_NAME = "raw"; 126 127 132 133 private String _componentAttributeName; 134 135 private static final String PROPERTY_NAME_PATTERN = "_?[a-zA-Z]\\w*"; 136 137 142 143 public static final String SIMPLE_ID_PATTERN = "^(" + PROPERTY_NAME_PATTERN + ")$"; 144 145 153 154 public static final String IMPLICIT_ID_PATTERN = "^(" + PROPERTY_NAME_PATTERN + ")?@(((" 155 + PROPERTY_NAME_PATTERN + "):)?(" + PROPERTY_NAME_PATTERN + "))$"; 156 157 private static final int IMPLICIT_ID_PATTERN_ID_GROUP = 1; 158 159 private static final int IMPLICIT_ID_PATTERN_TYPE_GROUP = 2; 160 161 private static final int IMPLICIT_ID_PATTERN_LIBRARY_ID_GROUP = 4; 162 163 private static final int IMPLICIT_ID_PATTERN_SIMPLE_TYPE_GROUP = 5; 164 165 private Pattern _simpleIdPattern; 166 167 private Pattern _implicitIdPattern; 168 169 private PatternMatcher _patternMatcher; 170 171 private IdAllocator _idAllocator = new IdAllocator(); 172 173 private ITemplateParserDelegate _delegate; 174 175 178 179 private Resource _resourceLocation; 180 181 184 185 private Location _templateLocation; 186 187 190 191 private Location _currentLocation; 192 193 196 197 private char[] _templateData; 198 199 202 203 private List _stack = new ArrayList (); 204 205 private static class Tag 206 { 207 String _tagName; 209 210 boolean _component; 212 213 boolean _ignoringBody; 216 217 boolean _removeTag; 219 220 boolean _mustBalance; 223 224 int _line; 226 227 boolean _content; 229 230 Tag(String tagName, int line) 231 { 232 _tagName = tagName; 233 _line = line; 234 } 235 236 boolean match(String matchTagName) 237 { 238 return _tagName.equalsIgnoreCase(matchTagName); 239 } 240 } 241 242 245 246 private List _tokens = new ArrayList (); 247 248 252 253 private int _cursor; 254 255 258 259 private int _blockStart; 260 261 264 265 private int _line; 266 267 272 273 private boolean _ignoring; 274 275 278 279 private Map _attributes = new HashMap (); 280 281 284 285 private TemplateTokenFactory _factory; 286 287 public TemplateParser() 288 { 289 Perl5Compiler compiler = new Perl5Compiler(); 290 291 try 292 { 293 _simpleIdPattern = compiler.compile(SIMPLE_ID_PATTERN); 294 _implicitIdPattern = compiler.compile(IMPLICIT_ID_PATTERN); 295 } 296 catch (MalformedPatternException ex) 297 { 298 throw new ApplicationRuntimeException(ex); 299 } 300 301 _patternMatcher = new Perl5Matcher(); 302 } 303 304 317 318 public TemplateToken[] parse(char[] templateData, ITemplateParserDelegate delegate, 319 Resource resourceLocation) throws TemplateParseException 320 { 321 try 322 { 323 beforeParse(templateData, delegate, resourceLocation); 324 325 parse(); 326 327 return (TemplateToken[]) _tokens.toArray(new TemplateToken[_tokens.size()]); 328 } 329 finally 330 { 331 afterParse(); 332 } 333 } 334 335 338 339 protected void beforeParse(char[] templateData, ITemplateParserDelegate delegate, 340 Resource resourceLocation) 341 { 342 _templateData = templateData; 343 _resourceLocation = resourceLocation; 344 _templateLocation = new LocationImpl(resourceLocation); 345 _delegate = delegate; 346 _ignoring = false; 347 _line = 1; 348 _componentAttributeName = delegate.getComponentAttributeName(); 349 } 350 351 354 355 protected void afterParse() 356 { 357 _delegate = null; 358 _templateData = null; 359 _resourceLocation = null; 360 _templateLocation = null; 361 _currentLocation = null; 362 _stack.clear(); 363 _tokens.clear(); 364 _attributes.clear(); 365 _idAllocator.clear(); 366 } 367 368 386 387 protected void templateParseProblem(String message, Location location, int line, int cursor) 388 throws TemplateParseException 389 { 390 throw new TemplateParseException(message, location); 391 } 392 393 409 410 protected void templateParseProblem(ApplicationRuntimeException exception, int line, int cursor) 411 throws ApplicationRuntimeException 412 { 413 throw exception; 414 } 415 416 419 protected List getTokens() 420 { 421 if (_tokens == null) 422 return Collections.EMPTY_LIST; 423 424 return _tokens; 425 } 426 427 430 431 private boolean lookahead(char[] match) 432 { 433 try 434 { 435 for (int i = 0; i < match.length; i++) 436 { 437 if (_templateData[_cursor + i] != match[i]) 438 return false; 439 } 440 441 443 return true; 444 } 445 catch (IndexOutOfBoundsException ex) 446 { 447 return false; 448 } 449 } 450 451 private static final char[] COMMENT_START = new char[] 452 { '<', '!', '-', '-' }; 453 454 private static final char[] COMMENT_END = new char[] 455 { '-', '-', '>' }; 456 457 private static final char[] CLOSE_TAG = new char[] 458 { '<', '/' }; 459 460 protected void parse() throws TemplateParseException 461 { 462 _cursor = 0; 463 _blockStart = -1; 464 int length = _templateData.length; 465 466 while (_cursor < length) 467 { 468 if (_templateData[_cursor] != '<') 469 { 470 if (_blockStart < 0 && !_ignoring) 471 _blockStart = _cursor; 472 473 advance(); 474 continue; 475 } 476 477 479 if (lookahead(CLOSE_TAG)) 480 { 481 closeTag(); 482 continue; 483 } 484 485 if (lookahead(COMMENT_START)) 486 { 487 skipComment(); 488 continue; 489 } 490 491 493 startTag(); 494 } 495 496 501 addTextToken(_templateData.length - 1); 502 } 503 504 508 509 private void skipComment() throws TemplateParseException 510 { 511 int length = _templateData.length; 512 int startLine = _line; 513 514 if (_blockStart < 0 && !_ignoring) 515 _blockStart = _cursor; 516 517 while (true) 518 { 519 if (_cursor >= length) 520 templateParseProblem(ParseMessages.commentNotEnded(startLine), new LocationImpl( 521 _resourceLocation, startLine), startLine, _cursor); 522 523 if (lookahead(COMMENT_END)) 524 break; 525 526 528 advance(); 529 } 530 531 _cursor += COMMENT_END.length; 532 advanceOverWhitespace(); 533 } 534 535 private void addTextToken(int end) 536 { 537 539 if (_blockStart < 0) 540 return; 541 542 if (_blockStart <= end) 543 { 544 547 TemplateToken token = _factory.createTextToken( 548 _templateData, 549 _blockStart, 550 end, 551 _templateLocation); 552 553 _tokens.add(token); 554 } 555 556 _blockStart = -1; 557 } 558 559 private static final int WAIT_FOR_ATTRIBUTE_NAME = 0; 560 561 private static final int COLLECT_ATTRIBUTE_NAME = 1; 562 563 private static final int ADVANCE_PAST_EQUALS = 2; 564 565 private static final int WAIT_FOR_ATTRIBUTE_VALUE = 3; 566 567 private static final int COLLECT_QUOTED_VALUE = 4; 568 569 private static final int COLLECT_UNQUOTED_VALUE = 5; 570 571 private void startTag() throws TemplateParseException 572 { 573 int cursorStart = _cursor; 574 int length = _templateData.length; 575 String tagName = null; 576 boolean endOfTag = false; 577 boolean emptyTag = false; 578 int startLine = _line; 579 Location startLocation = new LocationImpl(_resourceLocation, startLine); 580 581 tagBeginEvent(startLine, _cursor); 582 583 advance(); 584 585 587 while (_cursor < length) 588 { 589 char ch = _templateData[_cursor]; 590 591 if (ch == '/' || ch == '>' || Character.isWhitespace(ch)) 592 { 593 tagName = new String (_templateData, cursorStart + 1, _cursor - cursorStart - 1); 594 595 break; 596 } 597 598 advance(); 599 } 600 601 String attributeName = null; 602 int attributeNameStart = -1; 603 int attributeValueStart = -1; 604 int state = WAIT_FOR_ATTRIBUTE_NAME; 605 char quoteChar = 0; 606 607 _attributes.clear(); 608 609 611 while (!endOfTag) 612 { 613 if (_cursor >= length) 614 { 615 String message = (tagName == null) ? ParseMessages.unclosedUnknownTag(startLine) 616 : ParseMessages.unclosedTag(tagName, startLine); 617 618 templateParseProblem(message, startLocation, startLine, cursorStart); 619 } 620 621 char ch = _templateData[_cursor]; 622 623 switch (state) 624 { 625 case WAIT_FOR_ATTRIBUTE_NAME: 626 627 630 if (ch == '/') 631 { 632 emptyTag = true; 633 advance(); 634 break; 635 } 636 637 if (ch == '>') 638 { 639 endOfTag = true; 640 break; 641 } 642 643 if (Character.isWhitespace(ch)) 644 { 645 advance(); 646 break; 647 } 648 649 652 attributeNameStart = _cursor; 653 state = COLLECT_ATTRIBUTE_NAME; 654 advance(); 655 break; 656 657 case COLLECT_ATTRIBUTE_NAME: 658 659 661 if (ch == '=' || ch == '/' || ch == '>' || Character.isWhitespace(ch)) 662 { 663 attributeName = new String (_templateData, attributeNameStart, _cursor 664 - attributeNameStart); 665 666 state = ADVANCE_PAST_EQUALS; 667 break; 668 } 669 670 672 advance(); 673 break; 674 675 case ADVANCE_PAST_EQUALS: 676 677 681 if (ch == '/' || ch == '>') 682 { 683 686 state = WAIT_FOR_ATTRIBUTE_NAME; 687 break; 688 } 689 690 if (Character.isWhitespace(ch)) 691 { 692 advance(); 693 break; 694 } 695 696 if (ch == '=') 697 { 698 state = WAIT_FOR_ATTRIBUTE_VALUE; 699 quoteChar = 0; 700 attributeValueStart = -1; 701 advance(); 702 break; 703 } 704 705 709 state = WAIT_FOR_ATTRIBUTE_NAME; 710 break; 711 712 case WAIT_FOR_ATTRIBUTE_VALUE: 713 714 if (ch == '/' || ch == '>') 715 templateParseProblem(ParseMessages.missingAttributeValue( 716 tagName, 717 _line, 718 attributeName), getCurrentLocation(), _line, _cursor); 719 720 723 if (Character.isWhitespace(ch)) 724 { 725 advance(); 726 break; 727 } 728 729 if (ch == '\'' || ch == '"') 730 { 731 quoteChar = ch; 732 733 state = COLLECT_QUOTED_VALUE; 734 advance(); 735 attributeValueStart = _cursor; 736 attributeBeginEvent(attributeName, _line, attributeValueStart); 737 break; 738 } 739 740 742 state = COLLECT_UNQUOTED_VALUE; 743 attributeValueStart = _cursor; 744 attributeBeginEvent(attributeName, _line, attributeValueStart); 745 break; 746 747 case COLLECT_QUOTED_VALUE: 748 749 753 if (ch == quoteChar) 754 { 755 String attributeValue = new String (_templateData, attributeValueStart, 756 _cursor - attributeValueStart); 757 758 _attributes.put(attributeName, attributeValue); 759 attributeEndEvent(_cursor); 760 761 advance(); 763 state = WAIT_FOR_ATTRIBUTE_NAME; 764 break; 765 } 766 767 advance(); 768 break; 769 770 case COLLECT_UNQUOTED_VALUE: 771 772 775 if (ch == '/' || ch == '>' || Character.isWhitespace(ch)) 776 { 777 String attributeValue = new String (_templateData, attributeValueStart, 778 _cursor - attributeValueStart); 779 780 _attributes.put(attributeName, attributeValue); 781 attributeEndEvent(_cursor); 782 783 state = WAIT_FOR_ATTRIBUTE_NAME; 784 break; 785 } 786 787 advance(); 788 break; 789 } 790 } 791 792 tagEndEvent(_cursor); 793 794 796 String localizationKey = findValueCaselessly(LOCALIZATION_KEY_ATTRIBUTE_NAME, _attributes); 797 String jwcId = findValueCaselessly(_componentAttributeName, _attributes); 798 799 if (localizationKey != null && tagName.equalsIgnoreCase("span") && jwcId == null) 800 { 801 if (_ignoring) 802 templateParseProblem( 803 ParseMessages.componentMayNotBeIgnored(tagName, startLine), 804 startLocation, 805 startLine, 806 cursorStart); 807 808 811 if (!emptyTag) 812 { 813 Tag tag = new Tag(tagName, startLine); 814 815 tag._component = false; 816 tag._removeTag = true; 817 tag._ignoringBody = true; 818 tag._mustBalance = true; 819 820 _stack.add(tag); 821 822 824 _ignoring = true; 825 } 826 else 827 { 828 advance(); 830 advanceOverWhitespace(); 831 } 832 833 835 addTextToken(cursorStart - 1); 836 837 boolean raw = checkBoolean(RAW_ATTRIBUTE_NAME, _attributes); 838 839 Map attributes = filter(_attributes, new String [] 840 { LOCALIZATION_KEY_ATTRIBUTE_NAME, RAW_ATTRIBUTE_NAME }); 841 842 TemplateToken token = _factory.createLocalizationToken( 843 tagName, 844 localizationKey, 845 raw, 846 attributes, 847 startLocation); 848 849 _tokens.add(token); 850 851 return; 852 } 853 854 if (jwcId != null) 855 { 856 processComponentStart(tagName, jwcId, emptyTag, startLine, cursorStart, startLocation); 857 return; 858 } 859 860 863 if (!emptyTag) 864 { 865 Tag tag = new Tag(tagName, startLine); 866 _stack.add(tag); 867 } 868 869 871 if (_blockStart < 0 && !_ignoring) 872 _blockStart = cursorStart; 873 874 advance(); 875 } 876 877 881 882 887 protected void tagBeginEvent(int startLine, int cursorPosition) 888 { 889 } 890 891 896 protected void tagEndEvent(int cursorPosition) 897 { 898 } 899 900 905 protected void attributeBeginEvent(String attributeName, int startLine, int cursorPosition) 906 { 907 } 908 909 914 protected void attributeEndEvent(int cursorPosition) 915 { 916 } 917 918 private void processComponentStart(String tagName, String jwcId, boolean emptyTag, 919 int startLine, int cursorStart, Location startLocation) throws TemplateParseException 920 { 921 if (jwcId.equalsIgnoreCase(CONTENT_ID)) 922 { 923 processContentTag(tagName, startLine, cursorStart, emptyTag); 924 925 return; 926 } 927 928 boolean isRemoveId = jwcId.equalsIgnoreCase(REMOVE_ID); 929 930 if (_ignoring && !isRemoveId) 931 templateParseProblem( 932 ParseMessages.componentMayNotBeIgnored(tagName, startLine), 933 startLocation, 934 startLine, 935 cursorStart); 936 937 String type = null; 938 boolean allowBody = false; 939 940 if (_patternMatcher.matches(jwcId, _implicitIdPattern)) 941 { 942 MatchResult match = _patternMatcher.getMatch(); 943 944 jwcId = match.group(IMPLICIT_ID_PATTERN_ID_GROUP); 945 type = match.group(IMPLICIT_ID_PATTERN_TYPE_GROUP); 946 947 String libraryId = match.group(IMPLICIT_ID_PATTERN_LIBRARY_ID_GROUP); 948 String simpleType = match.group(IMPLICIT_ID_PATTERN_SIMPLE_TYPE_GROUP); 949 950 958 if (jwcId == null) 959 jwcId = _idAllocator.allocateId("$" + simpleType); 960 961 try 962 { 963 allowBody = _delegate.getAllowBody(libraryId, simpleType, startLocation); 964 } 965 catch (ApplicationRuntimeException e) 966 { 967 templateParseProblem(e, startLine, cursorStart); 969 } 970 971 } 972 else 973 { 974 if (!isRemoveId) 975 { 976 if (!_patternMatcher.matches(jwcId, _simpleIdPattern)) 977 templateParseProblem( 978 ParseMessages.componentIdInvalid(tagName, startLine, jwcId), 979 startLocation, 980 startLine, 981 cursorStart); 982 983 if (!_delegate.getKnownComponent(jwcId)) 984 templateParseProblem( 985 ParseMessages.unknownComponentId(tagName, startLine, jwcId), 986 startLocation, 987 startLine, 988 cursorStart); 989 990 try 991 { 992 allowBody = _delegate.getAllowBody(jwcId, startLocation); 993 } 994 catch (ApplicationRuntimeException e) 995 { 996 templateParseProblem(e, startLine, cursorStart); 998 } 999 } 1000 } 1001 1002 1006 boolean ignoreBody = !emptyTag && (isRemoveId || !allowBody); 1007 1008 if (_ignoring && ignoreBody) 1009 templateParseProblem(ParseMessages.nestedIgnore(tagName, startLine), new LocationImpl( 1010 _resourceLocation, startLine), startLine, cursorStart); 1011 1012 if (!emptyTag) 1013 pushNewTag(tagName, startLine, isRemoveId, ignoreBody); 1014 1015 1017 addTextToken(cursorStart - 1); 1018 1019 if (!isRemoveId) 1020 { 1021 addOpenToken(tagName, jwcId, type, startLocation); 1022 1023 if (emptyTag) 1024 _tokens.add(_factory.createCloseToken(tagName, getCurrentLocation())); 1025 } 1026 1027 advance(); 1028 } 1029 1030 private void pushNewTag(String tagName, int startLine, boolean isRemoveId, boolean ignoreBody) 1031 { 1032 Tag tag = new Tag(tagName, startLine); 1033 1034 tag._component = !isRemoveId; 1035 tag._removeTag = isRemoveId; 1036 1037 tag._ignoringBody = ignoreBody; 1038 1039 _ignoring = tag._ignoringBody; 1040 1041 tag._mustBalance = true; 1042 1043 _stack.add(tag); 1044 } 1045 1046 private void processContentTag(String tagName, int startLine, int cursorStart, boolean emptyTag) 1047 throws TemplateParseException 1048 { 1049 if (_ignoring) 1050 templateParseProblem( 1051 ParseMessages.contentBlockMayNotBeIgnored(tagName, startLine), 1052 new LocationImpl(_resourceLocation, startLine), 1053 startLine, 1054 cursorStart); 1055 1056 if (emptyTag) 1057 templateParseProblem( 1058 ParseMessages.contentBlockMayNotBeEmpty(tagName, startLine), 1059 new LocationImpl(_resourceLocation, startLine), 1060 startLine, 1061 cursorStart); 1062 1063 _tokens.clear(); 1064 _blockStart = -1; 1065 1066 Tag tag = new Tag(tagName, startLine); 1067 1068 tag._mustBalance = true; 1069 tag._content = true; 1070 1071 _stack.clear(); 1072 _stack.add(tag); 1073 1074 advance(); 1075 } 1076 1077 private void addOpenToken(String tagName, String jwcId, String type, Location location) 1078 { 1079 OpenToken token = _factory.createOpenToken(tagName, jwcId, type, location); 1080 _tokens.add(token); 1081 1082 if (_attributes.isEmpty()) 1083 return; 1084 1085 Iterator i = _attributes.entrySet().iterator(); 1086 while (i.hasNext()) 1087 { 1088 Map.Entry entry = (Map.Entry ) i.next(); 1089 1090 String key = (String ) entry.getKey(); 1091 1092 if (key.equalsIgnoreCase(_componentAttributeName)) 1093 continue; 1094 1095 String value = (String ) entry.getValue(); 1096 1097 addAttributeToToken(token, key, value); 1098 } 1099 } 1100 1101 1106 1107 private void addAttributeToToken(OpenToken token, String name, String attributeValue) 1108 { 1109 token.addAttribute(name, convertEntitiesToPlain(attributeValue)); 1110 } 1111 1112 1125 1126 private void closeTag() throws TemplateParseException 1127 { 1128 int cursorStart = _cursor; 1129 int length = _templateData.length; 1130 int startLine = _line; 1131 1132 Location startLocation = getCurrentLocation(); 1133 1134 _cursor += CLOSE_TAG.length; 1135 1136 int tagStart = _cursor; 1137 1138 while (true) 1139 { 1140 if (_cursor >= length) 1141 templateParseProblem( 1142 ParseMessages.incompleteCloseTag(startLine), 1143 startLocation, 1144 startLine, 1145 cursorStart); 1146 1147 char ch = _templateData[_cursor]; 1148 1149 if (ch == '>') 1150 break; 1151 1152 advance(); 1153 } 1154 1155 String tagName = new String (_templateData, tagStart, _cursor - tagStart); 1156 1157 int stackPos = _stack.size() - 1; 1158 Tag tag = null; 1159 1160 while (stackPos >= 0) 1161 { 1162 tag = (Tag) _stack.get(stackPos); 1163 1164 if (tag.match(tagName)) 1165 break; 1166 1167 if (tag._mustBalance) 1168 templateParseProblem(ParseMessages.improperlyNestedCloseTag( 1169 tagName, 1170 startLine, 1171 tag._tagName, 1172 tag._line), startLocation, startLine, cursorStart); 1173 1174 stackPos--; 1175 } 1176 1177 if (stackPos < 0) 1178 templateParseProblem( 1179 ParseMessages.unmatchedCloseTag(tagName, startLine), 1180 startLocation, 1181 startLine, 1182 cursorStart); 1183 1184 1186 if (tag._content) 1187 { 1188 addTextToken(cursorStart - 1); 1189 1190 1192 _cursor = length; 1193 _stack.clear(); 1194 return; 1195 } 1196 1197 if (tag._component) 1199 { 1200 addTextToken(cursorStart - 1); 1201 1202 _tokens.add(_factory.createCloseToken(tagName, getCurrentLocation())); 1203 } 1204 else 1205 { 1206 1209 if (_blockStart < 0 && !tag._removeTag && !_ignoring) 1210 _blockStart = cursorStart; 1211 } 1212 1213 1215 for (int i = _stack.size() - 1; i >= stackPos; i--) 1216 _stack.remove(i); 1217 1218 1220 advance(); 1221 1222 1226 if (tag._removeTag) 1227 advanceOverWhitespace(); 1228 1229 1232 if (tag._ignoringBody) 1233 _ignoring = false; 1234 } 1235 1236 1240 1241 private void advance() 1242 { 1243 int length = _templateData.length; 1244 1245 if (_cursor >= length) 1246 return; 1247 1248 char ch = _templateData[_cursor]; 1249 1250 _cursor++; 1251 1252 if (ch == '\n') 1253 { 1254 _line++; 1255 _currentLocation = null; 1256 return; 1257 } 1258 1259 1261 if (ch == '\r') 1262 { 1263 _line++; 1264 _currentLocation = null; 1265 1266 if (_cursor < length && _templateData[_cursor] == '\n') 1267 _cursor++; 1268 1269 return; 1270 } 1271 1272 1274 } 1275 1276 private void advanceOverWhitespace() 1277 { 1278 int length = _templateData.length; 1279 1280 while (_cursor < length) 1281 { 1282 char ch = _templateData[_cursor]; 1283 if (!Character.isWhitespace(ch)) 1284 return; 1285 1286 advance(); 1287 } 1288 } 1289 1290 1295 1296 private Map filter(Map input, String [] removeKeys) 1297 { 1298 if (input == null || input.isEmpty()) 1299 return null; 1300 1301 Map result = null; 1302 1303 Iterator i = input.entrySet().iterator(); 1304 1305 nextkey: while (i.hasNext()) 1306 { 1307 Map.Entry entry = (Map.Entry ) i.next(); 1308 1309 String key = (String ) entry.getKey(); 1310 1311 for (int j = 0; j < removeKeys.length; j++) 1312 { 1313 if (key.equalsIgnoreCase(removeKeys[j])) 1314 continue nextkey; 1315 } 1316 1317 if (result == null) 1318 result = new HashMap (input.size()); 1319 1320 result.put(key, entry.getValue()); 1321 } 1322 1323 return result; 1324 } 1325 1326 1331 1332 protected String findValueCaselessly(String key, Map map) 1333 { 1334 String result = (String ) map.get(key); 1335 1336 if (result != null) 1337 return result; 1338 1339 Iterator i = map.entrySet().iterator(); 1340 while (i.hasNext()) 1341 { 1342 Map.Entry entry = (Map.Entry ) i.next(); 1343 1344 String entryKey = (String ) entry.getKey(); 1345 1346 if (entryKey.equalsIgnoreCase(key)) 1347 return (String ) entry.getValue(); 1348 } 1349 1350 return null; 1351 } 1352 1353 1356 1357 private static final String [] CONVERSIONS = 1358 { "<", "<", ">", ">", """, "\"", "&", "&" }; 1359 1360 1366 1367 private String convertEntitiesToPlain(String input) 1368 { 1369 int inputLength = input.length(); 1370 1371 StringBuffer buffer = new StringBuffer (inputLength); 1372 1373 int cursor = 0; 1374 1375 outer: while (cursor < inputLength) 1376 { 1377 for (int i = 0; i < CONVERSIONS.length; i += 2) 1378 { 1379 String entity = CONVERSIONS[i]; 1380 int entityLength = entity.length(); 1381 String value = CONVERSIONS[i + 1]; 1382 1383 if (cursor + entityLength > inputLength) 1384 continue; 1385 1386 if (input.substring(cursor, cursor + entityLength).equals(entity)) 1387 { 1388 buffer.append(value); 1389 cursor += entityLength; 1390 continue outer; 1391 } 1392 } 1393 1394 buffer.append(input.charAt(cursor)); 1395 cursor++; 1396 } 1397 1398 return buffer.toString().trim(); 1399 } 1400 1401 1405 1406 private boolean checkBoolean(String key, Map map) 1407 { 1408 String value = findValueCaselessly(key, map); 1409 1410 if (value == null) 1411 return false; 1412 1413 return value.equalsIgnoreCase("true"); 1414 } 1415 1416 1422 1423 protected Location getCurrentLocation() 1424 { 1425 if (_currentLocation == null) 1426 _currentLocation = new LocationImpl(_resourceLocation, _line); 1427 1428 return _currentLocation; 1429 } 1430 1431 public void setFactory(TemplateTokenFactory factory) 1432 { 1433 _factory = factory; 1434 } 1435 1436} | Popular Tags |