Index: trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/HTMLLogParser.java
===================================================================
--- trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/HTMLLogParser.java	(revision 1353)
+++ trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/HTMLLogParser.java	(revision 1354)
@@ -15,7 +15,13 @@
 package de.ugoe.cs.autoquest.plugin.html;
 
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Properties;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -62,5 +68,5 @@
      */
     private Pattern htmlElementSpecPattern =
-        Pattern.compile("(\\w+)(\\[(\\d+)\\]|\\(htmlId=([\\w-]+)\\))?");
+        Pattern.compile("(\\w+)(\\[(\\d+)\\]|\\(htmlId=([\\w-#]+)\\))?");
     
     /**
@@ -70,4 +76,11 @@
      */
     private Map<String, List<String>> parseParams;
+
+    /**
+     * <p>
+     * a map containing replacement specifications for ids of GUI elements
+     * </p>
+     */
+    private Map<String, String> idReplacements;
 
     /**
@@ -82,5 +95,7 @@
         
         for (String paramKey : parseParams.keySet()) {
-            if (!"clearId".equals(paramKey) && !"clearIndex".equals(paramKey)) {
+            if (!"clearId".equals(paramKey) && !"clearIndex".equals(paramKey) &&
+                !"idReplacements".equals(paramKey))
+            {
                 throw new IllegalArgumentException("unknown parse parameter key " + paramKey);
             }
@@ -163,5 +178,9 @@
                 }
                 
-                if (clearHTMLId(tagName, index, htmlId, parent)) {
+                String idReplacement = replaceHTMLId(tagName, index, htmlId, parent);
+                if (idReplacement != null) {
+                    htmlId = idReplacement;
+                }
+                else if (clearHTMLId(tagName, index, htmlId, parent)) {
                     htmlId = null;
                 }
@@ -210,4 +229,60 @@
     private boolean clearIndex(String tagName, int index, String id, HTMLGUIElement parent) {
         return clearSomething("clearIndex", tagName, index, id, parent);
+    }
+
+    /**
+     * <p>
+     * TODO: comment
+     * </p>
+     *
+     * @param tagName
+     * @param index
+     * @param htmlId
+     * @param parent
+     * @return
+     */
+    private String replaceHTMLId(String tagName, int index, String htmlId, HTMLGUIElement parent)
+        throws SAXException
+    {
+        if ((idReplacements == null) && (parseParams.containsKey("idReplacements"))) {
+            idReplacements = new HashMap<String, String>();
+            for (String fileName : parseParams.get("idReplacements")) {
+                Properties props = new Properties();
+                try {
+                    props.load(new FileInputStream(new File(fileName)));
+                }
+                catch (FileNotFoundException e) {
+                    throw new SAXException("could not find file " + fileName, e);
+                }
+                catch (IOException e) {
+                    throw new SAXException("error reading file " + fileName, e);
+                }
+                
+                for (Map.Entry<Object, Object> entry : props.entrySet()) {
+                    idReplacements.put((String) entry.getKey(), (String) entry.getValue());
+                }
+            }
+        }
+        
+        if (idReplacements != null) {
+            for (Map.Entry<String, String> replacementSpec : idReplacements.entrySet()) {
+                String tagSpec = replacementSpec.getKey();
+
+                if (tagSpec.startsWith("/")) {
+                    throw new IllegalArgumentException("can not handle absolute specifications");
+                }
+                else if (tagSpec.endsWith("/")) {
+                    throw new IllegalArgumentException("specifications may not end with a /");
+                }
+
+                String[] tagSpecs = tagSpec.split("/");
+
+                if (tagMatchesTagSpec(tagName, index, htmlId, parent, tagSpecs)) {
+                    return replacementSpec.getValue();
+                }
+            }
+        }
+        
+        return null;
     }
 
@@ -294,5 +369,26 @@
             if (idCondition != null) {
                 if (!idCondition.equals(id)) {
-                    return false;
+                    // check if the id condition would match with ignoring specific characters
+                    if ((id != null) && (idCondition.indexOf('#') > -1)) {
+                        // first of all, the length must match
+                        if (idCondition.length() != id.length()) {
+                            return false;
+                        }
+                        
+                        for (int i = 0; i < idCondition.length(); i++) {
+                            if ((idCondition.charAt(i) != '#') &&
+                                (idCondition.charAt(i) != id.charAt(i)))
+                            {
+                                // if there is a character that is neither ignored not matches
+                                // the condition at a specific position, return "no match"
+                                return false;
+                            }
+                        }
+                        
+                    }
+                    else {
+                        // no condition ignoring specific characters
+                        return false;
+                    }
                 }
             }
Index: trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/commands/CMDcondenseHTMLGUIModel.java
===================================================================
--- trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/commands/CMDcondenseHTMLGUIModel.java	(revision 1353)
+++ trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/commands/CMDcondenseHTMLGUIModel.java	(revision 1354)
@@ -927,4 +927,28 @@
 
         /* (non-Javadoc)
+         * @see java.lang.Object#equals(java.lang.Object)
+         */
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == this) {
+                return true;
+            }
+            else if (obj instanceof SimilarGUIElement) {
+                return (similarGUIElement.equals(((SimilarGUIElement) obj).similarGUIElement));
+            }
+            else {
+                return false;
+            }
+        }
+
+        /* (non-Javadoc)
+         * @see java.lang.Object#hashCode()
+         */
+        @Override
+        public int hashCode() {
+            return similarGUIElement.hashCode();
+        }
+
+        /* (non-Javadoc)
          * @see java.lang.Object#toString()
          */
@@ -933,4 +957,5 @@
             return similarGUIElement + " (" + mainClusterParent + ")";
         }
+
     }
         
Index: trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/commands/CMDparseDirHTML.java
===================================================================
--- trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/commands/CMDparseDirHTML.java	(revision 1353)
+++ trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/commands/CMDparseDirHTML.java	(revision 1354)
@@ -69,5 +69,5 @@
                 }
                 else {
-                    Pattern parseParamPattern = Pattern.compile("-(\\w*)=([\\w=\\[\\]\\(\\)/]*)");
+                    Pattern parseParamPattern = Pattern.compile("-(\\w*)=([\\w=\\[\\]\\(\\)/\\.]*)");
                     Matcher matcher = parseParamPattern.matcher(param);
                     
@@ -161,5 +161,7 @@
     @Override
     public String help() {
-        return "parseDirHTML <directory> {<sequencesName>} {<clearId>} {<clearIndex>}";
+        return "parseDirHTML <directory> [<sequencesName>] " +
+            "{-idReplacements=path/to/replacementfile} {-clearId=path/to[0]/gui(htmlId=element)} " +
+            "{-clearIndex=path/to[0]/gui(htmlId=element)}";
     }
 
Index: trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/commands/CMDparseHTML.java
===================================================================
--- trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/commands/CMDparseHTML.java	(revision 1353)
+++ trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/commands/CMDparseHTML.java	(revision 1354)
@@ -64,5 +64,5 @@
                 }
                 else {
-                    Pattern parseParamPattern = Pattern.compile("-(\\w*)=([\\w=\\[\\]\\(\\)/]*)");
+                    Pattern parseParamPattern = Pattern.compile("-(\\w*)=([\\w=\\[\\]\\(\\)/\\.]*)");
                     Matcher matcher = parseParamPattern.matcher(param);
                     
@@ -124,5 +124,7 @@
     @Override
     public String help() {
-        return "parseHTML <filename> {<sequencesName>}";
+        return "parseHTML <filename> [<sequencesName>] " +
+            "{-idReplacements=path/to/replacementfile} {-clearId=path/to[0]/gui(htmlId=element)} " +
+            "{-clearIndex=path/to[0]/gui(htmlId=element)}";
     }
 
Index: trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/eventcore/HTMLEventTypeFactory.java
===================================================================
--- trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/eventcore/HTMLEventTypeFactory.java	(revision 1353)
+++ trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/eventcore/HTMLEventTypeFactory.java	(revision 1354)
@@ -163,5 +163,6 @@
         String xCoord = eventParameters.get(xParamName);
         if (xCoord == null) {
-            Console.printerrln("eventParameters do not contain " + xParamName + " coordinate.");
+            Console.traceln(Level.WARNING,
+                            "eventParameters do not contain " + xParamName + " coordinate.");
             xCoord = "0";
         }
@@ -169,5 +170,6 @@
         String yCoord = eventParameters.get(yParamName);
         if (yCoord == null) {
-            Console.printerrln("eventParameters do not contain " + yParamName + " coordinate.");
+            Console.traceln(Level.WARNING,
+                            "eventParameters do not contain " + yParamName + " coordinate.");
             yCoord = "0";
         }
@@ -179,5 +181,5 @@
         catch (NumberFormatException e) {
             throw new IllegalArgumentException("the coordinates provided by an " + eventName +
-                " event are no numbers");
+                                               " event are no numbers");
         }
     }
Index: trunk/autoquest-plugin-html/src/main/resources/manuals/parseDirHTML
===================================================================
--- trunk/autoquest-plugin-html/src/main/resources/manuals/parseDirHTML	(revision 1353)
+++ trunk/autoquest-plugin-html/src/main/resources/manuals/parseDirHTML	(revision 1354)
@@ -1,15 +1,31 @@
 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.
 
-The parsing process can be parameterized. This allows to ignore ids or indexes of GUI elements in the log files. If they are 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 indexes or ids, all rows are considered the same.
+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.
 
 To 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".  
 
+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:
+
+div(htmlId\=id_number_#)=div_number_X
+
+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.
+
+
+
 $USAGE$
-<directory> path to the directory 
-[<sequenceNames>] array of sequences into which the parsed events shall be stored
-[<clearId>] used to define GUI elements of which the ids shall be ignored
-[<clearIndex>] used to define GUI elements of which the indexes shall be ignored
+
+<directory>
+    path to the directory 
+[<sequenceNames>]
+    array of sequences into which the parsed events shall be stored
+{-idReplacements=path/to/replacementfile}
+    used to define id replacements as described in a separate file
+{-clearId=path/to[0]/gui(htmlId=element)}
+    used to define GUI elements of which the ids shall be ignored
+{-clearIndex=path/to[0]/gui(htmlId=element)}
+    used to define GUI elements of which the indexes shall be ignored
 
 Example(s):
 parseDirHTML /path/to/directory
 parseDirHTML /path/to/directory sequences -clearId=table(htmlId=overview)/tbody[0]/tr
+parseDirHTML /path/to/directory sequences -idReplacements=idReplacements.txt -clearId=body
Index: trunk/autoquest-plugin-html/src/main/resources/manuals/parseHTML
===================================================================
--- trunk/autoquest-plugin-html/src/main/resources/manuals/parseHTML	(revision 1353)
+++ trunk/autoquest-plugin-html/src/main/resources/manuals/parseHTML	(revision 1354)
@@ -1,15 +1,31 @@
 Parses an HTML log file them into an event sequence and a GUI model.
 
-The parsing process can be parameterized. This allows to ignore ids or indexes of GUI elements in the log files. If they are 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 indexes or ids, all rows are considered the same.
+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 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.
 
 To 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".  
 
+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:
+
+div(htmlId\=id_number_#)=div_number_X
+
+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.
+
+
+
 $USAGE$
-<file> path to the file to be parsed 
-[<sequenceNames>] array of sequences into which the parsed events shall be stored
-[<clearId>] used to define GUI elements of which the ids shall be ignored
-[<clearIndex>] used to define GUI elements of which the indexes shall be ignored
+
+<file>
+    path to the file to be parsed 
+[<sequenceNames>]
+    array of sequences into which the parsed events shall be stored
+{-idReplacements=path/to/replacementfile}
+    used to define id replacements as described in a separate file
+{-clearId=path/to[0]/gui(htmlId=element)}
+    used to define GUI elements of which the ids shall be ignored
+{-clearIndex=path/to[0]/gui(htmlId=element)}
+    used to define GUI elements of which the indexes shall be ignored
 
 Example(s):
 parseDirHTML /path/to/file.log
 parseDirHTML /path/to/file.log sequences -clearId=table(htmlId=overview)/tbody[0]/tr
+parseDirHTML /path/to/directory sequences -idReplacements=idReplacements.txt -clearId=body
