Index: tmp/org.txm.groovy.core/src/groovy/org/txm/macro/xml/ForceWordIDsMacro.groovy
===================================================================
--- tmp/org.txm.groovy.core/src/groovy/org/txm/macro/xml/ForceWordIDsMacro.groovy	(revision 3242)
+++ tmp/org.txm.groovy.core/src/groovy/org/txm/macro/xml/ForceWordIDsMacro.groovy	(revision 3243)
@@ -1,81 +0,0 @@
-// Copyright © 2019 ENS de Lyon, CNRS, University of Franche-Comté
-// Licensed under the terms of the GNU General Public License version 3 or any later version (https://www.gnu.org/licenses/gpl.html)
-// @author mdecorde
-// @author sheiden
-
-// STANDARD DECLARATIONS
-package org.txm.macro.xml
-
-import org.txm.utils.FileUtils;
-import org.kohsuke.args4j.*
-import groovy.transform.Field
-import org.txm.rcpapplication.swt.widget.parameters.*
-import org.txm.importer.StaxIdentityParser
-import javax.xml.stream.XMLStreamException
-
-@Field @Option(name="inputFile", usage="input file (XML)", widget="FileOpen", required=true, def="input.xml")
-def inputFile
-
-@Field @Option(name="outputFile", usage="output file", widget="FileSave", required=true, def="output.xml")
-def outputFile
-
-// Open the parameters input dialog box
-if (!ParametersDialog.open(this)) return
-
-// END OF PARAMETERS
-
-if (!(inputFile.exists() && inputFile.canRead())) {
-	println "** ForceWordIDs: cannot find $inputFile"
-	return false
-}
-
-print "Processing "+inputFile+"..."
-
-outputFile.getParentFile().mkdirs()
-
-// build text id
-textid = FileUtils.stripExtension(inputFile)
-
-def parser = new StaxIdentityParser(inputFile) {
-	
-	int wordnumber = 1
-	
-	/* ne fonctionne pas
-	protected void writeStartElement() throws XMLStreamException {
-		println localname
-		if (localname ==~ "w|pc") { // a word
-			localname = "w"
-		} 
-		
-		super.writeStartElement()
-	}
-	*/
-	
-	protected void writeAttributes() throws XMLStreamException {
-		if (localname ==~ "w|pc") { 																								// a word
-			boolean idwritten = false
-			attCount = parser.getAttributeCount()
-			attCount.times { i ->
-				if (parser.getAttributeLocalName(i) == "id") { // update & backup
-					writeAttribute(parser.getAttributePrefix(i), parser.getAttributeLocalName(i), "w_"+textid+"_"+(wordnumber++)) 	// force id
-					writeAttribute(parser.getAttributePrefix(i), "foreign-id", parser.getAttributeValue(i)) 						// backup
-					idwritten = true
-				} else if (parser.getAttributeLocalName(i) != "foreign-id") {
-					writeAttribute(parser.getAttributePrefix(i), parser.getAttributeLocalName(i), parser.getAttributeValue(i))
-				}
-			}
-			
-			if (!idwritten) { 																										// create id
-				writeAttribute(null, "id", "w_"+textid+"_"+(wordnumber++))
-			}
-		} else {
-			super.writeAttributes()
-		}
-	}
-}
-
-res = parser.process(outputFile)
-
-println " done."
-
-return res
Index: tmp/org.txm.groovy.core/src/groovy/org/txm/macro/xml/ForceWordIDParser.groovy
===================================================================
--- tmp/org.txm.groovy.core/src/groovy/org/txm/macro/xml/ForceWordIDParser.groovy	(revision 0)
+++ tmp/org.txm.groovy.core/src/groovy/org/txm/macro/xml/ForceWordIDParser.groovy	(revision 3243)
@@ -0,0 +1,49 @@
+// Copyright © 2021 MY_INSTITUTION
+// Licensed under the terms of the GNU General Public License version 3 (http://www.gnu.org/licenses/gpl-3.0.html)
+// @author mdecorde
+
+// STANDARD DECLARATIONS
+package org.txm.macro.xml
+
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.rcp.swt.widget.parameters.*
+import org.txm.importer.StaxIdentityParser
+import javax.xml.stream.XMLStreamException
+
+class ForceWordIDParser extends StaxIdentityParser {
+	public int wordnumber = 1
+	String wordElement;
+	String foreingIDAttribute;
+	String textid
+	
+	public ForceWordIDParser(File xmlFile, String wordElement, String foreingIDAttribute, String textid) {
+		super(xmlFile);
+		this.wordElement = wordElement
+		this.foreingIDAttribute = foreingIDAttribute
+		this.textid = textid
+	}
+	
+	protected void writeAttributes() throws XMLStreamException {
+		if (localname ==~ wordElement) { 																								// a word
+			boolean idwritten = false
+			def attCount = parser.getAttributeCount()
+			attCount.times { i ->
+				if (parser.getAttributeLocalName(i) == "id") { // update & backup
+					writeAttribute(parser.getAttributePrefix(i), parser.getAttributeLocalName(i), "w_"+textid+"_"+(wordnumber++)) 	// force id
+					writeAttribute(parser.getAttributePrefix(i), foreingIDAttribute, parser.getAttributeValue(i)) 						// backup
+					idwritten = true
+				} else if (parser.getAttributeLocalName(i) != foreingIDAttribute) {
+					writeAttribute(parser.getAttributePrefix(i), parser.getAttributeLocalName(i), parser.getAttributeValue(i))
+				}
+			}
+			
+			if (!idwritten) { 																										// create id
+				writeAttribute(null, "id", "w_"+textid+"_"+(wordnumber++))
+			}
+		} else {
+			super.writeAttributes()
+		}
+	}
+
+}
\ No newline at end of file
Index: tmp/org.txm.groovy.core/src/groovy/org/txm/macro/xml/ForceWordIDDirMacro.groovy
===================================================================
--- tmp/org.txm.groovy.core/src/groovy/org/txm/macro/xml/ForceWordIDDirMacro.groovy	(revision 0)
+++ tmp/org.txm.groovy.core/src/groovy/org/txm/macro/xml/ForceWordIDDirMacro.groovy	(revision 3243)
@@ -0,0 +1,81 @@
+// Copyright © 2019,2021 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License version 3 or any later version (https://www.gnu.org/licenses/gpl.html)
+// @author mdecorde
+// @author sheiden
+
+// STANDARD DECLARATIONS
+package org.txm.macro.xml
+
+import org.txm.utils.FileUtils;
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.rcpapplication.swt.widget.parameters.*
+import org.txm.importer.StaxIdentityParser
+import javax.xml.stream.XMLStreamException
+
+@Field @Option(name="inputDirectory", usage="input directory (.xml files)", widget="Folder", required=true, def="")
+def inputDirectory
+
+@Field @Option(name="outputDirectory", usage="output directory", widget="Folder", required=true, def="")
+def outputDirectory
+
+@Field @Option(name="wordElement", usage="word element regex", widget="String", required=true, def="word")
+def wordElement
+
+@Field @Option(name="foreignIDAttribute", usage="forein id attribute to use if 'id' is already set", widget="String", required=true, def="fn-id")
+def foreignIDAttribute
+
+// Open the parameters input dialog box
+if (!ParametersDialog.open(this)) return
+
+// END OF PARAMETERS
+
+if (!inputDirectory.exists()) {
+	println "** ForceWordIDDir: no '"+inputDirectory.name+"' directory found. Aborting."
+	return false
+}
+
+if (!inputDirectory.canRead()) {
+	println "** ForceWordIDDir: '"+inputDirectory.name+"' directory not readable. Aborting."
+	return false
+}
+
+def f = []
+inputDirectory.eachFileMatch(~/.*xml/) { f << it }
+
+if (f.size() == 0) {
+	println "** ForceWordIDDir: no .xml file found. Aborting."
+	return false
+}
+
+try {
+
+f.sort{ it.name }.each { inputFile ->
+
+	def outputFile = new File(outputDirectory, inputFile.name)
+
+	res = gse.run(ForceWordIDFileMacro, ["args":[
+
+				"inputFile": inputFile,
+				"outputFile": outputFile,
+				"wordElement": wordElement,
+				"foreignIDAttribute": foreignIDAttribute,
+
+				"selection":selection,
+				"selections":selections,
+				"corpusViewSelection":corpusViewSelection,
+				"corpusViewSelections":corpusViewSelections,
+				"monitor":monitor]])
+				
+			if (!res) println "** problem calling ForceWordIDFileMacro."
+}
+
+} catch (Exception e) {
+	println "** ForceWordIDDir: unable to read input files. Aborting."
+	println e.getLocalizedMessage()
+	println e.printStackTrace()
+	return false
+}
+
+return true
+
Index: tmp/org.txm.groovy.core/src/groovy/org/txm/macro/xml/ForceWordIDFileMacro.groovy
===================================================================
--- tmp/org.txm.groovy.core/src/groovy/org/txm/macro/xml/ForceWordIDFileMacro.groovy	(revision 0)
+++ tmp/org.txm.groovy.core/src/groovy/org/txm/macro/xml/ForceWordIDFileMacro.groovy	(revision 3243)
@@ -0,0 +1,51 @@
+// Copyright © 2019 ENS de Lyon, CNRS, University of Franche-Comté
+// Licensed under the terms of the GNU General Public License version 3 or any later version (https://www.gnu.org/licenses/gpl.html)
+// @author mdecorde
+// @author sheiden
+
+// STANDARD DECLARATIONS
+package org.txm.macro.xml
+
+import org.txm.utils.FileUtils;
+import org.kohsuke.args4j.*
+import groovy.transform.Field
+import org.txm.rcpapplication.swt.widget.parameters.*
+import org.txm.importer.StaxIdentityParser
+import javax.xml.stream.XMLStreamException
+
+@Field @Option(name="inputFile", usage="input file (.xml)", widget="FileOpen", required=true, def="")
+def inputFile
+
+@Field @Option(name="outputFile", usage="output file", widget="FileSave", required=true, def="")
+def outputFile
+
+@Field @Option(name="wordElement", usage="word element regex", widget="String", required=true, def="w|pc")
+def wordElement
+
+@Field @Option(name="foreignIDAttribute", usage="forein id attribute to use if 'id' is already set", widget="String", required=true, def="fn-id")
+def foreignIDAttribute
+
+// Open the parameters input dialog box
+if (!ParametersDialog.open(this)) return
+
+// END OF PARAMETERS
+
+if (!(inputFile.exists() && inputFile.canRead())) {
+	println "** ForceWordIDFile: cannot find $inputFile"
+	return false
+}
+
+print "Processing "+inputFile+"..."
+
+outputFile.getParentFile().mkdirs()
+
+// build text id
+textid = FileUtils.stripExtension(inputFile)
+
+ForceWordIDParser parser = new ForceWordIDParser(inputFile, wordElement, foreignIDAttribute, textid);
+
+def res = parser.process(outputFile)
+
+println " Done."
+
+return "ok"
