Changeset 1496 for trunk/autoquest-plugin-html/src/main
- Timestamp:
- 04/11/14 12:12:52 (11 years ago)
- Location:
- trunk/autoquest-plugin-html/src/main
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/HTMLLogParser.java
r1435 r1496 19 19 import java.io.FileNotFoundException; 20 20 import java.io.IOException; 21 import java.util.Arrays;22 21 import java.util.HashMap; 22 import java.util.LinkedList; 23 23 import java.util.List; 24 24 import java.util.Map; … … 35 35 import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement; 36 36 import de.ugoe.cs.autoquest.plugin.html.eventcore.HTMLEventTypeFactory; 37 import de.ugoe.cs.autoquest.plugin.html.guimodel.HTMLDocument; 37 38 import de.ugoe.cs.autoquest.plugin.html.guimodel.HTMLDocumentSpec; 38 39 import de.ugoe.cs.autoquest.plugin.html.guimodel.HTMLGUIElement; … … 48 49 * </p> 49 50 * <p> 50 * The parser can be configured with parsing parameters to ignore, e.g., ids orindexes of51 * The parser can be configured with parsing parameters to adapt, e.g., ids or or ignore indexes of 51 52 * parsed GUI elements. Details can be found in the manual pages of the respective parsing commands. 52 53 * </p> … … 68 69 /** 69 70 * <p> 70 * the pattern used for parsing parsing parameters 71 * </p> 72 */ 73 private Pattern htmlElementSpecPattern = 74 Pattern.compile("(\\w+)(\\[(\\d+)\\]|\\(htmlId=([\\w-#]+)\\))?"); 75 76 /** 77 * <p> 78 * parameters to influence parsing 79 * </p> 80 */ 81 private Map<String, List<String>> parseParams; 71 * file containing parameters to influence parsing 72 * </p> 73 */ 74 private String parseParamFile; 82 75 83 76 /** … … 86 79 * </p> 87 80 */ 88 private Map<String, String> idReplacements;89 90 /** 91 * <p> 92 * initializes the parser with the parsing parameters to be considered81 private Map<String, List<ReplacementSpecification>> replacementSpecifications; 82 83 /** 84 * <p> 85 * initializes the parser with the file containing parsing parameters to be considered 93 86 * </p> 94 87 * 95 * @param parseParams the parsing parameters to be considered 96 */ 97 public HTMLLogParser(Map<String, List<String>> parseParams) { 98 this.parseParams = parseParams; 99 100 for (String paramKey : parseParams.keySet()) { 101 if (!"clearId".equals(paramKey) && !"clearIndex".equals(paramKey) && 102 !"idReplacements".equals(paramKey)) 103 { 104 throw new IllegalArgumentException("unknown parse parameter key " + paramKey); 105 } 106 } 88 * @param parseParamFile the parsing parameters to be considered 89 */ 90 public HTMLLogParser(String parseParamFile) { 91 this.parseParamFile = parseParamFile; 107 92 } 108 93 … … 114 99 throws SAXException 115 100 { 101 ensureParsingParameters(); 102 116 103 HTMLGUIElementSpec specification = null; 117 104 … … 182 169 String htmlId = parameters.get("htmlid"); 183 170 184 if (clearIndex(tagName, index, htmlId, parent)) { 185 index = -1; 186 } 187 188 String idReplacement = replaceHTMLId(tagName, index, htmlId, parent); 189 if (idReplacement != null) { 190 htmlId = idReplacement; 191 } 192 else if (clearHTMLId(tagName, index, htmlId, parent)) { 193 htmlId = null; 171 String replacement = getReplacementMapping(tagName, index, htmlId, parent); 172 173 if (replacement != null) { 174 if (replacement.startsWith("CLEAR_INDEX,")) { 175 index = -1; 176 replacement = replacement.substring("CLEAR_INDEX,".length()); 177 } 178 else if ("CLEAR_INDEX".equals(replacement)) { 179 index = -1; 180 replacement = htmlId; 181 } 182 183 if ("".equals(replacement)) { 184 htmlId = null; 185 } 186 else { 187 htmlId = replacement; 188 } 194 189 } 195 190 … … 226 221 } 227 222 } 228 229 /** 230 * <p> 231 * checks if for a specific GUI element the index shall be ignored or not by considering the 232 * parsing parameters. 223 224 /** 225 * <p> 226 * returns the replacement mapping for the tag specified by the parameters, if a mapping exists. 233 227 * </p> 234 228 * 235 * @param tagName the tag of the considered GUI element236 * @param index the index of the GUI element237 * @param id the id of the GUI element238 * @param parent the parent GUI element of the considered GUI element229 * @param tagName the tag of the considered GUI element 230 * @param index the index of the GUI element 231 * @param id the id of the GUI element 232 * @param parent the parent GUI element of the considered GUI element 239 233 * 240 * @return true if the index shall be ignored, false else. 241 */ 242 private boolean clearIndex(String tagName, int index, String id, HTMLGUIElement parent) { 243 return clearSomething("clearIndex", tagName, index, id, parent); 244 } 245 246 /** 247 * <p> 248 * checks if the parsing parameters define a replacement for the id of the given GUI element 249 * and if so returns this replacement 250 * </p> 251 * 252 * @param tagName the tag of the considered GUI element 253 * @param index the index of the GUI element 254 * @param id the id of the GUI element 255 * @param parent the parent GUI element of the considered GUI element 256 * 257 * @return the identified replacement 258 */ 259 private String replaceHTMLId(String tagName, int index, String htmlId, HTMLGUIElement parent) 260 throws SAXException 234 * @return the replacement mapping, if any is configured; null else 235 */ 236 private String getReplacementMapping(String tagName, 237 int index, 238 String htmlId, 239 HTMLGUIElement parent) 261 240 { 262 if ((idReplacements == null) && (parseParams.containsKey("idReplacements"))) { 263 idReplacements = new HashMap<String, String>(); 264 for (String fileName : parseParams.get("idReplacements")) { 241 List<ReplacementSpecification> mappingCandidates = replacementSpecifications.get(tagName); 242 243 if (mappingCandidates != null) { 244 for (ReplacementSpecification replacementSpec : mappingCandidates) { 245 if (replacementSpec.matches(tagName, index, htmlId, parent)) { 246 return replacementSpec.getReplacement(); 247 } 248 } 249 } 250 251 return null; 252 } 253 254 /* (non-Javadoc) 255 * @see de.ugoe.cs.autoquest.plugin.html.AbstractDefaultLogParser#handleEvent(String, Map) 256 */ 257 @Override 258 protected boolean handleEvent(String type, Map<String, String> parameters) throws SAXException { 259 String targetId = parameters.get("target"); 260 261 if (targetId == null) { 262 if (replacementSpecifications.size() != 0) { 263 throw new SAXException 264 ("old log file versions can not be parsed with parse parameters"); 265 } 266 267 String targetDocument = parameters.get("targetDocument"); 268 String targetDOMPath = parameters.get("targetDOMPath"); 269 270 if ((targetDocument == null) || (targetDOMPath == null)) { 271 throw new SAXException("event has no target defined"); 272 } 273 274 targetId = determineTargetId(targetDocument, targetDOMPath); 275 276 if (targetId == null) { 277 // the target id can not be determined yet 278 return false; 279 } 280 } 281 282 IGUIElement target = super.getGUIElementTree().find(targetId); 283 284 if (target == null) { 285 // event not processible yet 286 return false; 287 } 288 289 IEventType eventType = 290 HTMLEventTypeFactory.getInstance().getEventType(type, parameters, target); 291 292 if (eventType != null) { 293 Event event = new Event(eventType, target); 294 295 String timestampStr = parameters.get("timestamp"); 296 297 if (timestampStr != null) { 298 event.setTimestamp(Long.parseLong(timestampStr)); 299 } 300 301 ((HTMLGUIElement) event.getTarget()).markUsed(); 302 303 super.addToSequence(event); 304 } 305 // else ignore unknown event type 306 307 return true; 308 } 309 310 /** 311 * <p> 312 * reads parsing parameters from the config file and makes them available for the parsing 313 * process 314 * </p> 315 */ 316 private void ensureParsingParameters() throws SAXException { 317 if (replacementSpecifications == null) { 318 replacementSpecifications = new HashMap<String, List<ReplacementSpecification>>(); 319 320 if (parseParamFile != null) { 265 321 Properties props = new Properties(); 266 322 FileInputStream stream = null; 267 323 try { 268 stream = new FileInputStream(new File( fileName));324 stream = new FileInputStream(new File(parseParamFile)); 269 325 props.load(stream); 270 326 } 271 327 catch (FileNotFoundException e) { 272 throw new SAXException("could not find file " + fileName, e);328 throw new SAXException("could not find file " + parseParamFile, e); 273 329 } 274 330 catch (IOException e) { 275 throw new SAXException("error reading file " + fileName, e);331 throw new SAXException("error reading file " + parseParamFile, e); 276 332 } 277 333 finally { … … 285 341 } 286 342 } 287 343 288 344 for (Map.Entry<Object, Object> entry : props.entrySet()) { 289 idReplacements.put((String) entry.getKey(), (String) entry.getValue()); 290 } 291 } 292 } 293 294 if (idReplacements != null) { 295 for (Map.Entry<String, String> replacementSpec : idReplacements.entrySet()) { 296 String tagSpec = replacementSpec.getKey(); 297 298 if (tagSpec.startsWith("/")) { 299 throw new IllegalArgumentException("can not handle absolute specifications"); 300 } 301 else if (tagSpec.endsWith("/")) { 302 throw new IllegalArgumentException("specifications may not end with a /"); 303 } 304 305 String[] tagSpecs = tagSpec.split("/"); 306 307 if (tagMatchesTagSpec(tagName, index, htmlId, parent, tagSpecs)) { 308 return replacementSpec.getValue(); 309 } 310 } 311 } 312 313 return null; 314 } 315 316 /** 317 * <p> 318 * checks if for a specific GUI element the id shall be ignored or not by considering the 319 * parsing parameters. 320 * </p> 321 * 322 * @param tagName the tag of the considered GUI element 323 * @param index the index of the GUI element 324 * @param id the id of the GUI element 325 * @param parent the parent GUI element of the considered GUI element 326 * 327 * @return true if the id shall be ignored, false else. 328 */ 329 private boolean clearHTMLId(String tagName, int index, String id, HTMLGUIElement parent) { 330 return clearSomething("clearId", tagName, index, id, parent); 345 ReplacementSpecification replSpec = new ReplacementSpecification 346 ((String) entry.getKey(), (String) entry.getValue()); 347 348 List<ReplacementSpecification> similarReplSpecs = 349 replacementSpecifications.get(replSpec.getLastTagName()); 350 351 if (similarReplSpecs == null) { 352 similarReplSpecs = new LinkedList<ReplacementSpecification>(); 353 replacementSpecifications.put(replSpec.getLastTagName(), similarReplSpecs); 354 } 355 356 similarReplSpecs.add(replSpec); 357 } 358 } 359 } 331 360 } 332 361 333 /**334 * <p>335 * convenience method to check for the existence for specific parsing parameters for clearing336 * ids or indexes of GUI elements.337 * </p>338 *339 * @param parseParamId the id of the parsing parameter to be checked for the GUI element340 * @param tagName the tag of the considered GUI element341 * @param index the index of the GUI element342 * @param id the id of the GUI element343 * @param parent the parent GUI element of the considered GUI element344 *345 * @return true if the denoted parse parameter is set to ignore, false else.346 */347 private boolean clearSomething(String parseParamId,348 String tagName,349 int index,350 String id,351 HTMLGUIElement parent)352 {353 if (parseParams.containsKey(parseParamId)) {354 for (String spec : parseParams.get(parseParamId)) {355 // determine the specification parts356 if (spec.startsWith("/")) {357 throw new IllegalArgumentException("can not handle absolute specifications");358 }359 else if (spec.endsWith("/")) {360 throw new IllegalArgumentException("specifications may not end with a /");361 }362 363 String[] tagSpecs = spec.split("/");364 365 if (tagMatchesTagSpec(tagName, index, id, parent, tagSpecs)) {366 return true;367 }368 }369 }370 371 return false;372 }373 374 /**375 * <p>376 * convenience method to check if a given GUI element matches a specification tags provided377 * through the parsing parameters.378 * </p>379 *380 * @param tagName the tag of the considered GUI element381 * @param index the index of the GUI element382 * @param id the id of the GUI element383 * @param parent the parent GUI element of the considered GUI element384 * @param tagSpecs the specification of a GUI element to match against the given GUI element385 *386 * @return true if the denoted parse parameter is set to ignore, false else.387 */388 private boolean tagMatchesTagSpec(String tagName,389 int index,390 String id,391 HTMLGUIElement parent,392 String[] tagSpecs)393 {394 395 if (tagSpecs.length > 0) {396 Matcher matcher = htmlElementSpecPattern.matcher(tagSpecs[tagSpecs.length - 1]);397 398 if (!matcher.matches()) {399 throw new IllegalArgumentException400 ("illegal tag specification " + tagSpecs[tagSpecs.length - 1]);401 }402 403 if (!tagName.equals(matcher.group(1))) {404 return false;405 }406 407 String idCondition = matcher.group(4);408 409 if (idCondition != null) {410 if (!idCondition.equals(id)) {411 // check if the id condition would match with ignoring specific characters412 if ((id != null) && (idCondition.indexOf('#') > -1)) {413 // first of all, the length must match414 if (idCondition.length() != id.length()) {415 return false;416 }417 418 for (int i = 0; i < idCondition.length(); i++) {419 if ((idCondition.charAt(i) != '#') &&420 (idCondition.charAt(i) != id.charAt(i)))421 {422 // if there is a character that is neither ignored not matches423 // the condition at a specific position, return "no match"424 return false;425 }426 }427 428 }429 else {430 // no condition ignoring specific characters431 return false;432 }433 }434 }435 436 String indexCondition = matcher.group(3);437 438 if (indexCondition != null) {439 try {440 if (index != Integer.parseInt(indexCondition)) {441 return false;442 }443 }444 catch (NumberFormatException e) {445 throw new IllegalArgumentException446 ("illegal tag index specification " + indexCondition, e);447 }448 }449 450 if (tagSpecs.length > 1) {451 if (parent instanceof HTMLPageElement) {452 return tagMatchesTagSpec(((HTMLPageElement) parent).getTagName(),453 ((HTMLPageElement) parent).getIndex(),454 ((HTMLPageElement) parent).getHtmlId(),455 (HTMLGUIElement) parent.getParent(),456 Arrays.copyOfRange(tagSpecs, 0, tagSpecs.length - 1));457 }458 else {459 throw new IllegalArgumentException460 ("specification matches documents or servers. This is not supported yet.");461 }462 }463 else {464 return true;465 }466 }467 else {468 return true;469 }470 }471 472 /* (non-Javadoc)473 * @see de.ugoe.cs.autoquest.plugin.html.AbstractDefaultLogParser#handleEvent(String, Map)474 */475 @Override476 protected boolean handleEvent(String type, Map<String, String> parameters) throws SAXException {477 String targetId = parameters.get("target");478 479 if (targetId == null) {480 if (parseParams.size() != 0) {481 throw new SAXException482 ("old log file versions can not be parsed with parse parameters");483 }484 485 String targetDocument = parameters.get("targetDocument");486 String targetDOMPath = parameters.get("targetDOMPath");487 488 if ((targetDocument == null) || (targetDOMPath == null)) {489 throw new SAXException("event has no target defined");490 }491 492 targetId = determineTargetId(targetDocument, targetDOMPath);493 494 if (targetId == null) {495 // the target id can not be determined yet496 return false;497 }498 }499 500 IGUIElement target = super.getGUIElementTree().find(targetId);501 502 if (target == null) {503 // event not processible yet504 return false;505 }506 507 IEventType eventType =508 HTMLEventTypeFactory.getInstance().getEventType(type, parameters, target);509 510 if (eventType != null) {511 Event event = new Event(eventType, target);512 513 String timestampStr = parameters.get("timestamp");514 515 if (timestampStr != null) {516 event.setTimestamp(Long.parseLong(timestampStr));517 }518 519 ((HTMLGUIElement) event.getTarget()).markUsed();520 521 super.addToSequence(event);522 }523 // else ignore unknown event type524 525 return true;526 }527 528 362 /** 529 363 * <p> … … 647 481 } 648 482 483 /** 484 * <p>specification for a replacement consisting of path of tag or document specifications 485 * and the appropriate replacement.</p> 486 */ 487 private static class ReplacementSpecification { 488 489 /** 490 * <p> 491 * the pattern used for parsing parsing parameters 492 * </p> 493 */ 494 private Pattern htmlElementSpecPattern = Pattern.compile 495 ("(document\\(path=([\\w/-]+)\\))|((\\w+)(\\[(\\d+)\\]|\\(htmlId=([\\w-_#]+)\\))?)"); 496 497 /** 498 * <p> 499 * the path of specifications (tags and document) specifying the tag for which this 500 * replacement is specified 501 * </p> 502 */ 503 private List<Spec> specs = new LinkedList<Spec>(); 504 505 /** 506 * <p> 507 * the name of the last tag in the specification path (used for indexing purposes) 508 * </p> 509 */ 510 private String lastTagName; 511 512 /** 513 * <p> 514 * the configured replacement 515 * </p> 516 */ 517 private String replacement; 518 519 /** 520 * <p> 521 * initializes the specification with the key/value strings from the config file. Parses 522 * the key to get the specification path consisting of, optionally, a document 523 * specification and one or more tag specification. 524 * </p> 525 */ 526 public ReplacementSpecification(String tagSpec, String replacement) { 527 List<String> tagSpecs = split(tagSpec); 528 529 for (int i = 0; i < tagSpecs.size(); i++) { 530 Matcher matcher = htmlElementSpecPattern.matcher(tagSpecs.get(i)); 531 532 if (!matcher.matches()) { 533 throw new IllegalArgumentException 534 ("illegal tag specification " + tagSpecs.get(i)); 535 } 536 537 if (matcher.group(1) != null) { 538 this.specs.add(new DocumentSpec(matcher.group(2))); 539 } 540 else if (matcher.group(4) != null) { 541 String indexConditionStr = matcher.group(6); 542 Integer indexCondition = null; 543 544 if (indexConditionStr != null) { 545 try { 546 indexCondition = Integer.parseInt(indexConditionStr); 547 } 548 catch (NumberFormatException e) { 549 throw new IllegalArgumentException 550 ("illegal tag index specification " + indexConditionStr, e); 551 } 552 } 553 554 this.specs.add 555 (new TagSpec(matcher.group(4), indexCondition, matcher.group(7))); 556 } 557 } 558 559 this.lastTagName = ((TagSpec) this.specs.get(this.specs.size() - 1)).getTagName(); 560 561 this.replacement = replacement; 562 } 563 564 /** 565 * <p> 566 * convenience method to split the key of a key/value pair from the config file into its 567 * parts 568 * </p> 569 */ 570 private List<String> split(String tagSpec) { 571 List<String> specs = new LinkedList<String>(); 572 573 StringBuffer currentSpec = new StringBuffer(); 574 int openBraces = 0; 575 576 for (int i = 0; i < tagSpec.length(); i++) { 577 char curChar = tagSpec.charAt(i); 578 if ((openBraces == 0) && ('/' == curChar) && (currentSpec.length() > 0)) { 579 specs.add(currentSpec.toString()); 580 currentSpec.setLength(0); 581 } 582 else { 583 if ('(' == curChar) { 584 openBraces++; 585 } 586 else if (')' == curChar) { 587 openBraces--; 588 } 589 currentSpec.append(curChar); 590 } 591 } 592 593 if (currentSpec.length() > 0) { 594 specs.add(currentSpec.toString()); 595 } 596 597 return specs; 598 } 599 600 /** 601 * <p> 602 * checks, if the tag identified by the parameters matches this specificaiton. 603 * </p> 604 */ 605 private boolean matches(String tagName, int index, String htmlId, HTMLGUIElement parent) { 606 String currentTagName = tagName; 607 int currentIndex = index; 608 String currentHtmlId = htmlId; 609 String currentPath = null; 610 HTMLGUIElement currentParent = parent; 611 612 int i = specs.size() - 1; 613 614 while (i >= 0) { 615 if ((specs.get(i) instanceof TagSpec) && 616 (!((TagSpec) specs.get(i)).matches(currentTagName, currentIndex, currentHtmlId))) 617 { 618 return false; 619 } 620 else if ((specs.get(i) instanceof DocumentSpec) && 621 (!((DocumentSpec) specs.get(i)).matches(currentPath))) 622 { 623 return false; 624 } 625 626 i--; 627 628 if (i >= 0) { 629 if (currentParent instanceof HTMLPageElement) { 630 currentTagName = ((HTMLPageElement) currentParent).getTagName(); 631 currentIndex = ((HTMLPageElement) currentParent).getIndex(); 632 currentHtmlId = ((HTMLPageElement) currentParent).getHtmlId(); 633 currentPath = null; 634 currentParent = (HTMLGUIElement) currentParent.getParent(); 635 } 636 else if (currentParent instanceof HTMLDocument) { 637 currentTagName = null; 638 currentIndex = Integer.MIN_VALUE; 639 currentHtmlId = null; 640 currentPath = ((HTMLDocument) currentParent).getPath(); 641 currentParent = (HTMLGUIElement) currentParent.getParent(); 642 } 643 else { 644 throw new IllegalArgumentException 645 ("specification matches documents or servers. This is not supported yet."); 646 } 647 } 648 } 649 650 return true; 651 } 652 653 /** 654 * <p> 655 * returns the specified replacement 656 * </p> 657 */ 658 private String getReplacement() { 659 return replacement; 660 } 661 662 /** 663 * <p> 664 * returns the name of the last tag specified in the specification path 665 * </p> 666 */ 667 private String getLastTagName() { 668 return lastTagName; 669 } 670 671 /* (non-Javadoc) 672 * @see java.lang.Object#toString() 673 */ 674 @Override 675 public String toString() { 676 StringBuffer result = new StringBuffer(); 677 for (Spec spec : specs) { 678 if (result.length() > 0) { 679 result.append("/"); 680 } 681 result.append(spec); 682 } 683 684 result.append('='); 685 result.append(replacement); 686 687 return result.toString(); 688 } 689 690 } 691 692 /** 693 * <p> 694 * parent type for document and tag specifications 695 * </p> 696 */ 697 private static interface Spec { } 698 699 /** 700 * <p> 701 * specification of a document 702 * </p> 703 */ 704 private static class DocumentSpec implements Spec { 705 706 /** 707 * <p> 708 * the part of the path the document path must have to match this specification 709 * </p> 710 */ 711 private String pathPart; 712 713 /** 714 * <p> 715 * initializes the document specification with the path part 716 * </p> 717 */ 718 private DocumentSpec(String pathPart) { 719 this.pathPart = pathPart; 720 } 721 722 /** 723 * <p> 724 * returns true if the provided path contains the path part provided to the parameter 725 * </p> 726 */ 727 private boolean matches(String path) { 728 return path.contains(pathPart); 729 } 730 731 /* (non-Javadoc) 732 * @see java.lang.Object#toString() 733 */ 734 @Override 735 public String toString() { 736 return "document(path=" + pathPart + ")"; 737 } 738 } 739 740 /** 741 * <p> 742 * specification for a tag containing a tag name and either an index or id condition. 743 * </p> 744 */ 745 private static class TagSpec implements Spec { 746 747 /** 748 * <p> 749 * the name of the tag to match 750 * </p> 751 */ 752 private String tagName; 753 754 /** 755 * <p> 756 * the index of the tag to match 757 * </p> 758 */ 759 private Integer indexCondition; 760 761 /** 762 * <p> 763 * the id of the tag to match 764 * </p> 765 */ 766 private String idCondition; 767 768 /** 769 * <p> 770 * initializes the specification with all required parameters 771 * </p> 772 */ 773 private TagSpec(String tagName, Integer indexCondition, String idCondition) { 774 this.tagName = tagName; 775 this.indexCondition = indexCondition; 776 this.idCondition = idCondition; 777 } 778 779 /** 780 * <p> 781 * returns true if the provided tag information matches this specification. The id is 782 * checked first. If the id condition has a # at some position, the respective element 783 * of the provided id is ignored. 784 * </p> 785 */ 786 private boolean matches(String tagName, int index, String htmlId) { 787 if (!this.tagName.equals(tagName)) { 788 return false; 789 } 790 791 if (idCondition != null) { 792 if (!idCondition.equals(htmlId)) { 793 // check if the id condition would match with ignoring specific characters 794 if ((htmlId != null) && (idCondition.indexOf('#') > -1)) { 795 // first of all, the length must match 796 if (idCondition.length() != htmlId.length()) { 797 return false; 798 } 799 800 for (int i = 0; i < idCondition.length(); i++) { 801 if ((idCondition.charAt(i) != '#') && 802 (idCondition.charAt(i) != htmlId.charAt(i))) 803 { 804 // if there is a character that is neither ignored nor matches 805 // the condition at a specific position, return "no match" 806 return false; 807 } 808 } 809 810 } 811 else { 812 // no condition ignoring specific characters 813 return false; 814 } 815 } 816 } 817 818 if ((indexCondition != null) && (index != indexCondition)) { 819 return false; 820 } 821 822 return true; 823 } 824 825 /** 826 * <p> 827 * returns the name of the tags matched by this specification 828 * </p> 829 */ 830 private String getTagName() { 831 return tagName; 832 } 833 834 /* (non-Javadoc) 835 * @see java.lang.Object#toString() 836 */ 837 @Override 838 public String toString() { 839 StringBuffer result = new StringBuffer(tagName); 840 841 if (idCondition != null) { 842 result.append("(htmlId="); 843 result.append(idCondition); 844 result.append(')'); 845 } 846 else if (indexCondition != null) { 847 result.append('['); 848 result.append(indexCondition); 849 result.append(']'); 850 } 851 852 return result.toString(); 853 } 854 855 } 649 856 } -
trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/commands/CMDcorrectHTMLLogDirs.java
r1339 r1496 17 17 import java.io.File; 18 18 import java.util.Arrays; 19 import java.util.HashMap;20 19 import java.util.List; 21 20 import java.util.logging.Level; … … 91 90 String serverName = null; 92 91 93 HTMLLogParser parser = new HTMLLogParser(n ew HashMap<String, List<String>>());92 HTMLLogParser parser = new HTMLLogParser(null); 94 93 try { 95 94 parser.parseFile(file); -
trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/commands/CMDparseDirHTML.java
r1435 r1496 18 18 import java.util.Arrays; 19 19 import java.util.Collection; 20 import java.util.HashMap;21 import java.util.LinkedList;22 20 import java.util.List; 23 import java.util.Map;24 21 import java.util.logging.Level; 25 22 import java.util.regex.Matcher; … … 55 52 String path = null; 56 53 String sequencesName = null; 57 Map<String, List<String>> parseParams = new HashMap<String, List<String>>();54 String parseParamFile = null; 58 55 59 56 try { … … 69 66 } 70 67 else { 71 Pattern parseParamPattern = Pattern.compile("-(\\w*)=([\\w =\\[\\]\\(\\)/\\.-]*)");68 Pattern parseParamPattern = Pattern.compile("-(\\w*)=([\\w/\\.-]*)"); 72 69 Matcher matcher = parseParamPattern.matcher(param); 73 70 74 71 if (matcher.matches()) { 75 72 String key = matcher.group(1); 76 List<String> values = parseParams.get(key); 77 78 if (values == null) { 79 values = new LinkedList<String>(); 80 parseParams.put(key, values); 73 if (!"parseParamFile".equals(key)) { 74 String message = "unknown parameter: " + key; 75 Console.printerrln(message); 76 throw new IllegalArgumentException(message); 81 77 } 82 78 83 values.add(matcher.group(2));79 parseParamFile = matcher.group(2); 84 80 } 85 81 else { 86 String message = "par se parameter does not follow format: -<key>=<value>";82 String message = "parameter does not follow format: -<key>=<value>"; 87 83 Console.printerrln(message); 88 84 throw new IllegalArgumentException(message); … … 105 101 } 106 102 107 HTMLLogParser parser = new HTMLLogParser(parseParam s);103 HTMLLogParser parser = new HTMLLogParser(parseParamFile); 108 104 109 105 parseFile(folder, parser); … … 161 157 @Override 162 158 public String help() { 163 return "parseDirHTML <directory> [<sequencesName>] " + 164 "{-idReplacements=path/to/replacementfile} {-clearId=path/to[0]/gui(htmlId=element)} " + 165 "{-clearIndex=path/to[0]/gui(htmlId=element)}"; 159 return "parseDirHTML <directory> [<sequencesName>] {-parseParams=path/to/parseParamsFile}"; 166 160 } 167 161 -
trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/commands/CMDparseHTML.java
r1435 r1496 16 16 17 17 import java.util.Collection; 18 import java.util.HashMap;19 import java.util.LinkedList;20 18 import java.util.List; 21 import java.util.Map;22 19 import java.util.regex.Matcher; 23 20 import java.util.regex.Pattern; … … 50 47 String filename = null; 51 48 String sequencesName = null; 52 Map<String, List<String>> parseParams = new HashMap<String, List<String>>();49 String parseParamFile = null; 53 50 54 51 try { … … 64 61 } 65 62 else { 66 Pattern parseParamPattern = Pattern.compile("-(\\w*)=([\\w =\\[\\]\\(\\)/\\.-]*)");63 Pattern parseParamPattern = Pattern.compile("-(\\w*)=([\\w/\\.-]*)"); 67 64 Matcher matcher = parseParamPattern.matcher(param); 68 65 69 66 if (matcher.matches()) { 70 67 String key = matcher.group(1); 71 List<String> values = parseParams.get(key); 72 73 if (values == null) { 74 values = new LinkedList<String>(); 75 parseParams.put(key, values); 68 if (!"parseParamFile".equals(key)) { 69 String message = "unknown parameter: " + key; 70 Console.printerrln(message); 71 throw new IllegalArgumentException(message); 76 72 } 77 73 78 values.add(matcher.group(2));74 parseParamFile = matcher.group(2); 79 75 } 80 76 else { 81 String message = "par se parameter does not follow format: -<key>=<value>";77 String message = "parameter does not follow format: -<key>=<value>"; 82 78 Console.printerrln(message); 83 79 throw new IllegalArgumentException(message); … … 94 90 } 95 91 96 HTMLLogParser parser = new HTMLLogParser(parseParam s);92 HTMLLogParser parser = new HTMLLogParser(parseParamFile); 97 93 98 94 try { … … 124 120 @Override 125 121 public String help() { 126 return "parseHTML <filename> [<sequencesName>] " + 127 "{-idReplacements=path/to/replacementfile} {-clearId=path/to[0]/gui(htmlId=element)} " + 128 "{-clearIndex=path/to[0]/gui(htmlId=element)}"; 122 return "parseHTML <filename> [<sequencesName>] {-parseParams=path/to/parseParamsFile}"; 129 123 } 130 124 -
trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/guimodel/HTMLPageElement.java
r1490 r1496 90 90 } 91 91 else if (otherElement instanceof HTMLPageElement) { 92 if ( this == otherElement) {92 if (equals(otherElement)) { 93 93 return DISTANCE_NONE; 94 94 } -
trunk/autoquest-plugin-html/src/main/resources/manuals/parseDirHTML
r1354 r1496 1 1 Treats all files in a directory structure as HTML log files and parses them into event sequences and a GUI model. Also sub directories are parsed. 2 2 3 The parsing process can be parameterized. This allows to replace or ignore ids or indexes of GUI elements in the log files. If they are replaced or ignored, the GUI model is more harmonized and GUI elements are considered equal although they are not. This may be helpful, e.g., if you have a table where each row is semantically the same. Without replacing or ignoring indexes or ids of the rows, each row is treated separately. But with replaced or ignored indexes or ids, all rows are considered the same.3 The parsing process can be parameterized. This allows to replace ids or ignore indexes of GUI elements in the log files. If they are replaced or ignored, the GUI model is more harmonized and GUI elements are considered equal although they are not. This may be helpful, e.g., if you have a table where each row is semantically the same. Without ignoring indexes or ids of the rows, each row is treated separately. But with ignored or replaced indexes or ids, all rows are considered the same. 4 4 5 T o ignore the indexes, add -clearIndex=<path to GUI element> as parameter to the command call. To ignore ids, add -clearId=<path to GUI element> to the command call. The path to the GUI element is written using the HTML tag names and either their index or their id as identification. E.g., to denote all rows in a table where the table has the id "table_1" you can specify "table(htmlId=table_1)/tbody/tr". To denote e.g. all divs being the child of a div with an index 1, you specify "div[1]/div".5 The parameterization is done in a separate properties file. The keys in the file specify the tags for which either the id shall be replaced or the index shall be ignored. A specification for a simple tag either simply by its name, by its name and index or by its name and id looks as follows: 6 6 7 To replace ids, a separate files with mappings must be created. The path to this file must be provided using the idReplacements parameter. The file follows a typical properties format. The key is the path denoting the GUI element of which the id shall be set. The value is the actual id. The key may contain the # character to denote a wildcard in html ids. This allows matching several GUI elements with similar ids at once and to give them the same id. An example entry of this file is: 7 tagName 8 tagName[index] 9 tagName(htmlId\=id) 8 10 9 div(htmlId\=id_number_#)=div_number_X 11 Furthermore, tags can be specified as paths through the DOM in that several tags specifications are given and concatenated using /. An example with three specified tag (tag1 with index 5, tag 2, and tag 3 with id "id") is the following: 10 12 11 This line would give all divs with an id "id_number_#" where # denotes any character the new id "div_number_X". Please note that for specifying the keys, it is required to escape any = sign in the key specification. This is usually required if the path to the denoted GUI elements denotes elements by their id as shown in the example. 13 tag1[5]/tag2/tag3(htmlId\=id) 12 14 15 The specification of a tag id may contain the # character to denote a wildcard. This allows matching several GUI elements with similar ids at once and to give them the same id. An example entry of this is: 16 17 div(htmlId\=id_number_#) 18 19 This line would match all divs with an id starting with "id_number_" where # denotes any character. 20 21 It is also possible to specify the document in which the tag path should match. A document is specified by giving a part of the documents path in the URL. After the document specification, the full path to the specified tag must be given. An example is the following: 22 23 document(path\=accounts)/html/body/div[0]/ul/li(htmlId\=breadcrumb1)/a 24 25 Please note that for specifying the keys, it is required to escape any = sign in the key specification. This is usually required if the path to the denoted GUI elements denotes elements by their id as shown in the example. 26 27 To remove the id of a specified tag, the value must be empty. To set the id, the value must the id the tag shall have. To clear the index of the specified tag, that value must be CLEAR_INDEX. Here are some further example entries: 28 29 body/div/div/div/form= 30 body/p/small/a=imprint-link 31 document(path\=accounts/login)/html/body/div[0]/div[1]/div[0]/form/p/a=password-reset-link 32 document(path\=accounts/login)/html/body/div[0]/div[1]/div[0]/form/div/button=CLEAR_INDEX 33 body/div[5]=date-chooser 34 div(htmlId\=date-chooser)/div[0]=date-chooser_day 13 35 14 36 … … 19 41 [<sequenceNames>] 20 42 array of sequences into which the parsed events shall be stored 21 {- idReplacements=path/to/replacementfile}43 {-parseParams=path/to/replacementfile} 22 44 used to define id replacements as described in a separate file 23 {-clearId=path/to[0]/gui(htmlId=element)}24 used to define GUI elements of which the ids shall be ignored25 {-clearIndex=path/to[0]/gui(htmlId=element)}26 used to define GUI elements of which the indexes shall be ignored27 45 28 46 Example(s): 29 47 parseDirHTML /path/to/directory 30 parseDirHTML /path/to/directory sequences -clearId=table(htmlId=overview)/tbody[0]/tr 31 parseDirHTML /path/to/directory sequences -idReplacements=idReplacements.txt -clearId=body 48 parseDirHTML /path/to/directory sequences -parseParams=idReplacements.txt -
trunk/autoquest-plugin-html/src/main/resources/manuals/parseHTML
r1354 r1496 1 1 Parses an HTML log file them into an event sequence and a GUI model. 2 2 3 The parsing process can be parameterized. This allows to replace or ignore ids orindexes of GUI elements in the log files. If they are replaced or ignored, the GUI model is more harmonized and GUI elements are considered equal although they are not. This may be helpful, e.g., if you have a table where each row is semantically the same. Without ignoring indexes or ids of the rows, each row is treated separately. But with ignored or replaced indexes or ids, all rows are considered the same.3 The parsing process can be parameterized. This allows to replace ids or ignore indexes of GUI elements in the log files. If they are replaced or ignored, the GUI model is more harmonized and GUI elements are considered equal although they are not. This may be helpful, e.g., if you have a table where each row is semantically the same. Without ignoring indexes or ids of the rows, each row is treated separately. But with ignored or replaced indexes or ids, all rows are considered the same. 4 4 5 T o ignore the indexes, add -clearIndex=<path to GUI element> as parameter to the command call. To ignore ids, add -clearId=<path to GUI element> to the command call. The path to the GUI element is written using the HTML tag names and either their index or their id as identification. E.g., to denote all rows in a table where the table has the id "table_1" you can specify "table(htmlId=table_1)/tbody/tr". To denote e.g. all divs being the child of a div with an index 1, you specify "div[1]/div".5 The parameterization is done in a separate properties file. The keys in the file specify the tags for which either the id shall be replaced or the index shall be ignored. A specification for a simple tag either simply by its name, by its name and index or by its name and id looks as follows: 6 6 7 To replace ids, a separate files with mappings must be created. The path to this file must be provided using the idReplacements parameter. The file follows a typical properties format. The key is the path denoting the GUI element of which the id shall be set. The value is the actual id. The key may contain the # character to denote a wildcard in html ids. This allows matching several GUI elements with similar ids at once and to give them the same id. An example entry of this file is: 7 tagName 8 tagName[index] 9 tagName(htmlId\=id) 8 10 9 div(htmlId\=id_number_#)=div_number_X 11 Furthermore, tags can be specified as paths through the DOM in that several tags specifications are given and concatenated using /. An example with three specified tag (tag1 with index 5, tag 2, and tag 3 with id "id") is the following: 10 12 11 This line would give all divs with an id "id_number_#" where # denotes any character the new id "div_number_X". Please note that for specifying the keys, it is required to escape any = sign in the key specification. This is usually required if the path to the denoted GUI elements denotes elements by their id as shown in the example. 13 tag1[5]/tag2/tag3(htmlId\=id) 12 14 15 The specification of a tag id may contain the # character to denote a wildcard. This allows matching several GUI elements with similar ids at once and to give them the same id. An example entry of this is: 13 16 17 div(htmlId\=id_number_#) 18 19 This line would match all divs with an id starting with "id_number_" where # denotes any character. 20 21 It is also possible to specify the document in which the tag path should match. A document is specified by giving a part of the documents path in the URL. After the document specification, the full path to the specified tag must be given. An example is the following: 22 23 document(path\=accounts)/html/body/div[0]/ul/li(htmlId\=breadcrumb1)/a 24 25 Please note that for specifying the keys, it is required to escape any = sign in the key specification. This is usually required if the path to the denoted GUI elements denotes elements by their id as shown in the example. 26 27 To remove the id of a specified tag, the value must be empty. To set the id, the value must the id the tag shall have. To clear the index of the specified tag, that value must be CLEAR_INDEX. Here are some further example entries: 28 29 body/div/div/div/form= 30 body/p/small/a=imprint-link 31 document(path\=accounts/login)/html/body/div[0]/div[1]/div[0]/form/p/a=password-reset-link 32 document(path\=accounts/login)/html/body/div[0]/div[1]/div[0]/form/div/button=CLEAR_INDEX 33 body/div[5]=date-chooser 34 div(htmlId\=date-chooser)/div[0]=date-chooser_day 14 35 15 36 $USAGE$ … … 19 40 [<sequenceNames>] 20 41 array of sequences into which the parsed events shall be stored 21 {- idReplacements=path/to/replacementfile}42 {-parseParams=path/to/replacementfile} 22 43 used to define id replacements as described in a separate file 23 {-clearId=path/to[0]/gui(htmlId=element)}24 used to define GUI elements of which the ids shall be ignored25 {-clearIndex=path/to[0]/gui(htmlId=element)}26 used to define GUI elements of which the indexes shall be ignored27 44 28 45 Example(s): 29 46 parseDirHTML /path/to/file.log 30 parseDirHTML /path/to/file.log sequences -clearId=table(htmlId=overview)/tbody[0]/tr 31 parseDirHTML /path/to/directory sequences -idReplacements=idReplacements.txt -clearId=body 47 parseDirHTML /path/to/file.log sequences -parseParams=idReplacements.txt
Note: See TracChangeset
for help on using the changeset viewer.