Index: TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/scripts/importer/transcriber/transcriberLoader.groovy
===================================================================
--- TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/scripts/importer/transcriber/transcriberLoader.groovy	(revision 3406)
+++ TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/scripts/importer/transcriber/transcriberLoader.groovy	(revision 3407)
@@ -172,7 +172,16 @@
 			println "Failed to prepare files - Aborting";
 			return;
 		}
-		if (MONITOR != null) MONITOR.worked(20)
+		if (MONITOR != null) MONITOR.worked(20)
+			
+//		File antractXSL = new File(srcDir, "special.xsl")
+//		if (antractXSL.exists()) {
+//			println "Applying special XSL: $antractXSL"
+//			if (!ApplyXsl2.processImportSources(antractXSL, txmDir, txmDir)) {
+//				println "Error while processing XML-TXM files."
+//				return false;
+//			}
+//		}
 
 		println "-- Xml Validation"
 		if (MONITOR != null && MONITOR.isCanceled()) { return MONITOR.done(); }
@@ -187,7 +196,9 @@
 		cpb.done()
 
 		if (MONITOR != null && MONITOR.isCanceled()) { return MONITOR.done(); }
-		if (MONITOR != null) MONITOR.worked(20, "ANNOTATE")
+		if (MONITOR != null) MONITOR.worked(20, "ANNOTATE")
+			
+			
 
 		boolean annotationSuccess = false;
 		if (annotate) {
Index: TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/scripts/importer/transcriber/compiler.groovy
===================================================================
--- TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/scripts/importer/transcriber/compiler.groovy	(revision 3406)
+++ TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/scripts/importer/transcriber/compiler.groovy	(revision 3407)
@@ -46,59 +46,59 @@
  * The Class compiler.
  */
 class compiler {
-
+	
 	boolean ADD_TEXTID_TO_REF = true
 	
 	/** The input data. */
 	private def inputData;
-
+	
 	/** The factory. */
 	private def factory;
-
+	
 	/** The parser. */
 	private XMLStreamReader parser;
-
+	
 	/** The output. */
 	OutputStreamWriter output;
-
+	
 	/** The basename. */
 	String corpusname;
-
+	
 	/** The projectname. */
 	String projectname
-
+	
 	/** The outdir. */
 	String outdir;
-
+	
 	/** The debug. */
 	boolean debug = false;
-
+	
 	/** The indexInterviewer: index interviewer speech if true. */
 	boolean indexInterviewer = true;
-
+	
 	/** The trans. */
 	HashMap<String, ArrayList<Pair<String, String>>> trans;
-
+	
 	/** The speakers. */
 	HashMap<String, ArrayList<Pair<String, String>>> speakers;
-
+	
 	/** The speakersname. */
 	HashMap<String, String> speakersname = new HashMap<String, String>();
-
+	
 	/** The topics. */
 	HashMap<String, ArrayList<Pair<String, String>>> topics;
-
-
+	
+	
 	/** The interviewers regex */
 	def interviewers = null
 	static LinkedHashSet<String> sectionAttrs;
 	static LinkedHashSet<String> spAttrs;
 	static LinkedHashSet<String> uAttrs;
-
+	
 	/** The anatypes. */
 	private static anatypes = []
 	private static anavalues = [:]
-
+	
 	/**
 	 * Removes the interviewers.
 	 *
@@ -108,8 +108,11 @@
 	public setIndexInterviewer(boolean value) {
 		this.indexInterviewer = value;
 	}
-
+	
 	File cqpFile
+	LinkedHashMap<String, LinkedHashMap<String, String>> projectionsFromValues = new LinkedHashMap<String, LinkedHashMap<String, String>>(); // values of properties to inject
+	LinkedHashMap<String, LinkedHashMap<String, ArrayList<ArrayList>>> projectionsToDo = new LinkedHashMap<String, LinkedHashMap<String, ArrayList<ArrayList>>>(); // list of projections to do
+	
 	/**
 	 * Run.
 	 *
@@ -125,14 +128,14 @@
 		this.outdir = binDir;
 		this.corpusname = corpusname;
 		this.projectname = projectname;
-
+		
 		anatypes = ["event"] // reset
 		anavalues = [:] // reset
-
+		
 		sectionAttrs = new LinkedHashSet<String>() // reset section attributs set
 		spAttrs = new LinkedHashSet<String>() // reset section attributs set
 		uAttrs = new LinkedHashSet<String>() // reset section attributs set
-
+		
 		CorpusBuild corpus = project.getCorpusBuild(project.getName(), MainCorpus.class);
 		if (corpus != null) {
 			if (project.getDoUpdate()) {
@@ -152,16 +155,47 @@
 		new File(binDir,"cqp").mkdirs()
 		new File(binDir,"data").mkdirs()
 		new File(binDir,"registry").mkdirs()
-
+		
 		// get all anatypes
 		for (File f : xmlfiles) {
 			getAnaTypes(f)
 		}
+		
+		// Building projections datas to use for each step
+		String projectionsParameterValue = project.getTextualPlan("Projections").trim()
+		projectionsParameterValue = projectionsParameterValue.replace("\n", "\t")
+		def projectionsParameter = projectionsParameterValue.split("\t");
+		if (projectionsParameterValue.length() > 0) {
+			for (def projection : projectionsParameter) {
+				if (!projection.contains("->")) continue;
+				String[] fromTo = projection.split("->", 2)
+				String from = fromTo[0].trim()
+				String to = fromTo[1].trim()
+				if (projection.contains("->") && from.contains("_") && to.contains("_")) {
+					String toStructure = to.substring(0, to.indexOf("_"))
+					String toStructureProperty = to.substring(to.indexOf("_") + 1)
+					String fromStructure = from.substring(0, from.indexOf("_"))
+					String fromStructureProperty = from.substring(from.indexOf("_") + 1)
+					
+					if (!projectionsToDo.containsKey(toStructure)) {
+						projectionsToDo[toStructure] = new LinkedHashMap<String, ArrayList<ArrayList>>();
+					}
+					if (!projectionsToDo[toStructure].containsKey(fromStructure)) {
+						projectionsToDo[toStructure][fromStructure] = new ArrayList<ArrayList>();
+					}
+					projectionsToDo[toStructure][fromStructure].add([toStructureProperty, fromStructureProperty])
+					
+					if (!projectionsFromValues.containsKey(fromStructure)) projectionsFromValues[fromStructure] = new LinkedHashMap<String, String>();
+					projectionsFromValues[fromStructure][fromStructureProperty] = "";
+				}
+			}
+		}
+		
 		//println "ANATYPES: "+anatypes
 		if (!createOutput(cqpFile)) return false;
 		output.write("<txmcorpus lang=\"fr\">\n")
 		output.close();
-
+		
 		println("Compiling "+xmlfiles.size()+" files")
 		ConsoleProgressBar cpb = new ConsoleProgressBar(xmlfiles.size())
 		for (File txmFile :xmlfiles) {
@@ -176,17 +210,17 @@
 		if (!createOutput(cqpFile)) return false;
 		output.write("</txmcorpus>\n")
 		output.close();
-
+		
 		//2- Import into CWB
 		File registryFile = new File(binDir, "registry/"+corpusname.toLowerCase())
 		File dataDir = new File(binDir, "data/$corpusname")
-
+		
 		new File(binDir, "registry").mkdir();
 		if (!new File(binDir, "registry").exists()) {
 			println "Can't create registry directory"
 			return false;
 		}
-
+		
 		if (!(CwbEncode.isExecutableAvailable() && CwbMakeAll.isExecutableAvailable())) {
 			println ("Error: CWB executables not well set.")
 			return false;
@@ -195,7 +229,7 @@
 		CwbMakeAll cwbMa = new CwbMakeAll();
 		cwbEn.setDebug(debug);
 		cwbMa.setDebug(debug);
-
+		
 		String uAttr = "u:0";
 		for (String attr : uAttrs) {
 			uAttr += "+"+attr
@@ -218,7 +252,7 @@
 					if (ignoreTranscriberMetadata) {
 						String meta =p.getFirst();
 						if (meta != "scribe" && meta != "audio_filename" &&
-							meta != "version" && meta != "version_date")
+								meta != "version" && meta != "version_date")
 							textAttr+="+"+meta
 					} else {
 						textAttr+="+"+p.getFirst()
@@ -227,14 +261,30 @@
 				break;
 			}
 		}
-
+		
 		List<String> pargs = ["spk", "ref", "id", "entitytype", "entityid"]
 		for (String ana : anatypes) if (!pargs.contains(ana)) pargs.add(ana)
-
+		
 		String[] pAttributes = pargs
-
+		
 		String[] sAttributes = ["txmcorpus:0+lang", uAttr , textAttr, "event:0+id+desc+type+extent", sectionAttr, spAttr];
-
+		
+		// registering the projected structure properties
+		//println "registering: $projectionsToDo"
+		for (String struct : projectionsToDo.keySet()) {
+			for (String struct2 : projectionsToDo[struct].keySet()) {
+				for (def couple : projectionsToDo[struct][struct2]) {
+					//sattrsListener.getStructs()[struct].add(couple[0])
+					//println "add $struct $couple"
+					for (int i = 0 ; i < sAttributes.size() ; i++) {
+						if (sAttributes[i].startsWith(struct+":") && !sAttributes[i].contains(couple[0])) {
+							sAttributes[i] = sAttributes[i] + "+"+couple[0]
+						}
+					}
+				}
+			}
+		}
+		
 		println "pAttributes: $pAttributes"
 		println "sAttributes: $sAttributes"
 		//return;
@@ -246,16 +296,16 @@
 				return false;
 			}
 			cwbMa.run(corpusname, registryFile.getParent());
-
+			
 		} catch (Exception ex) {System.out.println(ex); return false;}
-
+		
 		if (project.getCleanAfterBuild()) {
 			new File(project.getProjectDirectory(), "cqp").deleteDir()
 		}
 		
 		return true;
 	}
-
+	
 	/**
 	 * Creates the output.
 	 *
@@ -273,30 +323,44 @@
 			return false;
 		}
 	}
-
+	
 	/** The text_id. */
 	String text_id
-
+	
 	/** The u opened. */
 	boolean uOpened = false;
-
+	
 	/** The idturn. */
 	int idturn = 1;
-
+	
 	/** The idsection. */
 	int idsection = 1;
-
+	
 	/** The idu. */
 	int idu = 1;
-
+	
 	/** The idevent. */
 	int idevent = 1;
-
+	
 	/** The events. */
 	List<String> events = [];
 	static int vEntityId = 0;
 	static int vEntityIdCount = 1;
-
+	
+	protected void writeProjections(String localname) {
+		if (projectionsToDo.containsKey(localname)) {
+			for (String from : projectionsToDo[localname].keySet()) {
+				for (def couple : projectionsToDo[localname][from]) {
+					def o = couple[0]
+					def p = couple[1]
+					def r = projectionsFromValues[from][p]
+					//println "o=$o p=$p r=$r"
+					output.write(" "+o+"=\""+r+"\"");
+				}
+			}
+		}
+	}
+	
 	/**
 	 * Process.
 	 *
@@ -306,11 +370,11 @@
 	private boolean process(File xmlfile) {
 		text_id = xmlfile.getName();
 		text_id = text_id.substring(0, text_id.length() -4);
-
+		
 		idturn = 1;
 		idsection = 1;
 		idu = 1;
-
+		
 		boolean flagAna;
 		boolean flagForm;
 		boolean flagWord;
@@ -324,29 +388,29 @@
 		String anatype = "";
 		String anaresp = "";
 		String anavalue = "";
-
+		
 		String formatedTime;
-
+		
 		LinkedHashMap<String, String> anahash = new LinkedHashMap<String, String>();
 		String currentType;
-
+		
 		URL url = xmlfile.toURI().toURL();
 		inputData = url.openStream();
 		factory = XMLInputFactory.newInstance();
 		parser = factory.createXMLStreamReader(inputData);
 		String filename = xmlfile.getName()
 		String textid = filename.substring(0, filename.length() - 4);
-
+		
 		createOutput(cqpFile);
 		String localname;
-
+		
 		//get all metadatas declared before Episode tag
 		speakers = new HashMap<String, ArrayList<Pair<String, String>>>();
 		trans = new HashMap<String, ArrayList<Pair<String, String>>>();
 		topics = new HashMap<String, ArrayList<Pair<String, String>>>();
 		//println "parse infos"
 		parseInfos();
-
+		
 		//		println "Trans: $trans"
 		//		println "Topics: $topics"
 		//		println "Speakers: $speakers"
@@ -358,15 +422,23 @@
 		//		}
 		//		println "Trans properties: "+transproperties
 		List<String> localspeakers;
-
-
+		
+		
 		for (int event = parser.next(); event != XMLStreamConstants.END_DOCUMENT; event = parser.next()) {
 			//print "event: "+event +" "
 			switch (event) {
 				case XMLStreamConstants.START_ELEMENT:
 					localname = parser.getLocalName();
+				
+					if (projectionsFromValues.containsKey(localname)) { // get projections values
+						for (String attr : projectionsFromValues[localname].keySet()) {
+							projectionsFromValues[localname][attr] = parser.getAttributeValue(null, attr);
+						}
+					}
+				
 				//println localname
 					switch(localname) {
+						
 						case "div":
 							output.write("<div");
 							for (int i = 0 ; i < parser.getAttributeCount() ; i ++) {
@@ -374,6 +446,7 @@
 								output.write(" "+name+"=\""+parser.getAttributeValue(i).replace("\"", "&quot;")+"\"");
 								sectionAttrs << name
 							}
+							writeProjections(localname)
 							output.write ">\n"
 							break;
 						case "sp":
@@ -383,6 +456,7 @@
 								output.write(" "+name+"=\""+parser.getAttributeValue(i).replace("\"", "&quot;")+"\"");
 								spAttrs << name
 							}
+							writeProjections(localname)
 							output.write ">\n"
 							break;
 						case "u":
@@ -390,21 +464,23 @@
 							for (int i = 0 ; i < parser.getAttributeCount() ; i ++) {
 								String name = parser.getAttributeLocalName(i).replace("_","").toLowerCase()
 								output.write(" "+name+"=\""+parser.getAttributeValue(i).replace("\"", "&quot;")+"\"");
-								if (name == "time") { 
-									formatedTime = parser.getAttributeValue(i) 
-								} else if (name == "who") { 
-									u_name = parser.getAttributeValue(i) 
+								if (name == "time") {
+									formatedTime = parser.getAttributeValue(i)
+								} else if (name == "who") {
+									u_name = parser.getAttributeValue(i)
 								}
-									
+								
 								uAttrs << name
 							}
+							writeProjections(localname)
 							output.write ">\n"
 							break;
 						case "event":
 							output.write("<event");
 							writeAttributes();
+							writeProjections(localname)
 							output.write ">\n"
-
+						
 							if (parser.getAttributeValue(null, "type") == "entities") {
 								if (parser.getAttributeValue(null, "extent") == "begin") {
 									vEntityType = parser.getAttributeValue(null, "desc");
@@ -463,7 +539,13 @@
 					break;
 				case XMLStreamConstants.END_ELEMENT:
 					localname = parser.getLocalName();
-
+				
+					if (projectionsFromValues.containsKey(localname)) { // reset values
+						for (String attr : projectionsFromValues[localname].keySet()) {
+							projectionsFromValues[localname][attr] = "";
+						}
+					}
+				
 					switch (localname) {
 						case "text":
 							output.write("</text>\n")
@@ -507,21 +589,21 @@
 							String ref = (u_name+", "+formatedTime+""+isEnq)
 							if (ADD_TEXTID_TO_REF) ref = textid+", "+ref
 							vForm +="\t"+u_name+"\t"+ref
-
+						
 						// concat entity and entity ID
 							vAna+= "\t"+vEntityType+"\t"+vEntityId;
-
+						
 						//concat ana values
 							for (String type : anatypes) {
 								def v = anavalues.get(type);
 								if (v == null) v = "";
-
+								
 								if ("event" == type) {
 									if (v.length() > 0)
 										vAna+="\t#"+v;
 									else
 										vAna+="\t";
-
+									
 									//concat <Event> values
 									if (vEvents != null && vEvents.length() > 0 && vEvents != "N/A")
 										vAna += "#"+vEvents;
@@ -529,9 +611,9 @@
 									vAna+="\t"+v;
 								}
 							}
-
+						
 							vForm = vForm.replaceAll("\n", "").replaceAll("&", "&amp;").replaceAll("<", "&lt;");
-
+						
 							if (interviewers != null && !indexInterviewer) { // we must remove some words
 								if (!interviewers.matches(u_name)) { // keep what is now an interviewer
 									output.write(vForm+"\t"+wordid+vAna+"\n");
@@ -539,7 +621,7 @@
 							} else {
 								output.write(vForm+"\t"+wordid+vAna+"\n");
 							}
-
+						
 							vAna = "";
 							vForm = "";
 							break;
@@ -554,16 +636,16 @@
 					break;
 			}
 		}
-
+		
 		parser.close();
 		inputData.close();
 		output.close();
 		return true;
 	}
-
+	
 	/** The u_name. */
 	String u_name;
-
+	
 	/**
 	 * Write start tag.
 	 */
@@ -572,7 +654,7 @@
 		writeAttributes();
 		output.write ">\n"
 	}
-
+	
 	/**
 	 * Write attributes.
 	 */
@@ -581,7 +663,7 @@
 			output.write(" "+parser.getAttributeLocalName(i).replace("_","").toLowerCase()+"=\""+parser.getAttributeValue(i).replace("\"", "&quot;")+"\"");
 		}
 	}
-
+	
 	private void getAnaTypes(File xmlFile) {
 		inputData = xmlFile.toURI().toURL().openStream();
 		factory = XMLInputFactory.newInstance();
@@ -609,7 +691,7 @@
 			}
 		}
 	}
-
+	
 	/**
 	 * Write start tag.
 	 *
@@ -621,17 +703,17 @@
 		writeAttributes();
 		output.write ">\n"
 	}
-
+	
 	/**
 	 * Write end tag.
 	 */
 	private void writeEndTag() {
 		output.write("</"+parser.getLocalName().toLowerCase()+">\n");
 	}
-
+	
 	/** The ignore transcriber metadata. */
 	boolean ignoreTranscriberMetadata = false;
-
+	
 	/**
 	 * Sets the ignore transcriber metadata.
 	 *
@@ -640,7 +722,7 @@
 	public void setIgnoreTranscriberMetadata(boolean state) {
 		this.ignoreTranscriberMetadata = state;
 	}
-
+	
 	public static int MAXATTRIBUTEVALUELENGTH = 8191;
 	
 	/**
@@ -652,6 +734,13 @@
 		for (int event = parser.next(); event != XMLStreamConstants.END_DOCUMENT; event = parser.next()) {
 			if (event == XMLStreamConstants.START_ELEMENT) {
 				localname = parser.getLocalName();
+				
+				if (projectionsFromValues.containsKey(localname)) { // get projections values
+					for (String attr : projectionsFromValues[localname].keySet()) {
+						projectionsFromValues[localname][attr] = parser.getAttributeValue(null, attr);
+					}
+				}
+				
 				switch (localname) {
 					case "text":
 						output.write("<text project=\""+projectname+"\" base=\""+corpusname+"\"")
@@ -659,27 +748,27 @@
 							
 							String value = parser.getAttributeValue(i).replace("\"", "&quot;");
 							if (value.length() > MAXATTRIBUTEVALUELENGTH) {
-//								value = value.substring(0, MAXATTRIBUTEVALUELENGTH-1)
+								//								value = value.substring(0, MAXATTRIBUTEVALUELENGTH-1)
 								println "WARNING: attribute value is too long ( > $MAXATTRIBUTEVALUELENGTH). The value will be truncated to: $value"
 							}
 							
 							if (ignoreTranscriberMetadata) {
 								if (parser.getAttributeLocalName(i) != "scribe" &&
-								parser.getAttributeLocalName(i) != "audio_filename" &&
-								parser.getAttributeLocalName(i) != "version" &&
-								parser.getAttributeLocalName(i) != "version_date") {
+										parser.getAttributeLocalName(i) != "audio_filename" &&
+										parser.getAttributeLocalName(i) != "version" &&
+										parser.getAttributeLocalName(i) != "version_date") {
 									output.write(" "+parser.getAttributeLocalName(i).replace("_","").toLowerCase()+"=\""+value+"\"");
 								}
 							} else {
 								output.write(" "+parser.getAttributeLocalName(i).replace("_","").toLowerCase()+"=\""+value+"\"");
 							}
 						}
-
+					
 						output.write ">\n"
-
+					
 						ArrayList list = new ArrayList<Pair<String, String>>()
 						trans.put("trans", list);
-
+					
 						for (int i = 0 ; i < parser.getAttributeCount() ; i ++) {
 							list.add(new Pair(parser.getAttributeLocalName(i).replace("_","").toLowerCase(), parser.getAttributeValue(i)));
 							if (parser.getAttributeLocalName(i).equals("interviewer-id-regex"))
@@ -708,7 +797,7 @@
 						if (id != null) {
 							ArrayList list = new ArrayList<Pair<String, String>>()
 							speakers.put(id, list);
-
+							
 							for (int i = 0 ; i < parser.getAttributeCount() ; i ++) {
 								list.add(new Pair(parser.getAttributeLocalName(i), parser.getAttributeValue(i)));
 							}
@@ -721,7 +810,7 @@
 			}
 		}
 	}
-
+	
 	/**
 	 * Sets the debug.
 	 */
Index: TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/scripts/importer/xtz/XTZCompilerStep.groovy
===================================================================
--- TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/scripts/importer/xtz/XTZCompilerStep.groovy	(revision 3406)
+++ TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/scripts/importer/xtz/XTZCompilerStep.groovy	(revision 3407)
@@ -52,7 +52,9 @@
 		this.normalizeFormValues = n
 	}
 
-	public XTZCompilerStep(File xmlFile, File cqpFile, String textname, String corpusname, String projectname, def anatypes, def wtag) {
+	public XTZCompilerStep(ImportStep importStep, File xmlFile, File cqpFile, String textname, String corpusname, String projectname, def anatypes, def wtag) {
+		super(importStep)
+		
 		this.xmlFile = xmlFile
 		this.cqpFile = cqpFile
 		this.textname = textname
@@ -95,6 +97,7 @@
 	 * @return true, if successful
 	 */
 	public boolean process() {
+		
 		if (!createOutput(cqpFile)) {
 			return false
 		}
@@ -122,12 +125,21 @@
 		boolean foundtei = false;
 		boolean foundtext = false;
 		int nWords = 0;
+	
+		
 		try {
 			String localname;
 			for (int event = parser.next(); event != XMLStreamConstants.END_DOCUMENT; event = parser.next()) {
 				switch (event) {
 					case XMLStreamConstants.START_ELEMENT:
 						localname = parser.getLocalName().toLowerCase();
+						
+						if (importStep.projectionsFromValues.containsKey(localname)) {
+							for (String attr : importStep.projectionsFromValues[localname].keySet()) {
+								importStep.projectionsFromValues[localname][attr] = parser.getAttributeValue(null, attr);
+							}
+						}
+						
 						if ("tei".equals(localname)) foundtei = true;
 						switch (localname) {
 							case "text":
@@ -180,7 +192,7 @@
 								if (!foundtei || !foundtext) break;
 
 								output.write("<"+localname)
-
+								def toWrite = new LinkedHashMap()
 								for (int i = 0 ; i < parser.getAttributeCount() ; i++) {
 									String attrname = parser.getAttributeLocalName(i)
 
@@ -188,20 +200,47 @@
 									if (normalizeAttributeValues) {
 										attrvalue = attrvalue.trim()
 									}
-									output.write(" "+attrname.toLowerCase()+"=\""+attrvalue.replace("\"", "&quot;")+QUOTE)
+									//output.write(" "+attrname.toLowerCase()+"=\""+attrvalue.replace("\"", "&quot;")+QUOTE)
+									toWrite[attrname.toLowerCase()] = attrvalue.replace("\"", "&quot;")
 								}
 								if (parser.getAttributeCount() == 0) { // add the n attribute
 									if (!ncounts.containsKey(localname)) ncounts.put(localname, 0)
 									int ncount = ncounts.get(localname)
 									ncounts.put(localname, ncount+1)
 									output.write(" n=\""+ncount+QUOTE)
+									toWrite["n"] = ncount
 								}
+								
+								if (importStep.projectionsToDo.containsKey(localname)) {
+									for (String from : importStep.projectionsToDo[localname].keySet()) {
+										for (def couple : importStep.projectionsToDo[localname][from]) {
+											def o = couple[0]
+											def p = couple[1]
+											def r = importStep.projectionsFromValues[from][p]
+											//println "o=$o p=$p r=$r"
+											toWrite[o] = r
+										}
+									}
+								}
+								
+								//println "toWrite=$toWrite"
+								
+								for (String attr : toWrite.keySet()) {
+									output.write(" "+attr+"=\""+toWrite[attr]+QUOTE)
+								}
 								output.write(">\n")
 						}
 						break;
 
 					case XMLStreamConstants.END_ELEMENT:
 						localname = parser.getLocalName().toLowerCase();
+						
+						if (importStep.projectionsFromValues.containsKey(localname)) { // reset projection values
+							for (String attr : importStep.projectionsFromValues[localname].keySet()) {
+								importStep.projectionsFromValues[localname][attr] = "";
+							}
+						}
+						
 						switch (localname) {
 							case WTAG:
 								for (String type : anatypes) {
Index: TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/scripts/importer/xtz/XTZFacsPagerStep.groovy
===================================================================
--- TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/scripts/importer/xtz/XTZFacsPagerStep.groovy	(revision 3406)
+++ TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/scripts/importer/xtz/XTZFacsPagerStep.groovy	(revision 3407)
@@ -37,7 +37,9 @@
 	String wtag;
 	boolean debug = false;
 
-	public XTZFacsPagerStep(File xmlFile, File editionDir, File imageDirectory, String txtname, String corpusname, String tag, String attribute, String wtag, boolean debug) {
+	public XTZFacsPagerStep(ImportStep importStep, File xmlFile, File editionDir, File imageDirectory, String txtname, String corpusname, String tag, String attribute, String wtag, boolean debug) {
+		super(importStep)
+		
 		inputData = xmlFile.toURI().toURL().openStream()
 		factory = XMLInputFactory.newInstance()
 		parser = factory.createXMLStreamReader(inputData)
Index: TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/scripts/importer/xtz/XTZCompiler.groovy
===================================================================
--- TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/scripts/importer/xtz/XTZCompiler.groovy	(revision 3406)
+++ TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/scripts/importer/xtz/XTZCompiler.groovy	(revision 3407)
@@ -18,28 +18,28 @@
 import org.txm.searchengine.cqp.corpus.*
 
 class XTZCompiler extends Compiler {
-
+	
 	SAttributesListener sattrsListener; // store scanned structures
-
+	
 	String regPath;
 	String corpusname;
 	String wtag;
-
+	
 	boolean doNormalizeAttributeValues = false;
 	boolean doNormalizeAnaValues = true;
-
+	
 	public XTZCompiler(ImportModule module) {
 		super(module);
-
+		
 		corpusname = module.getProject().getName();
 		regPath = module.getBinaryDirectory().getAbsolutePath() + "/registry/"+corpusname.toLowerCase()
-
+		
 		wtag = module.getProject().getTokenizerWordElement();
-
+		
 		doNormalizeAttributeValues = "true".equals(module.getProject().getPreferencesScope().getNode("import").get(TBXPreferences.NORMALISEATTRIBUTEVALUES, "false"))
 		doNormalizeAnaValues = "true".equals(module.getProject().getPreferencesScope().getNode("import").get(TBXPreferences.NORMALISEANAVALUES, "false"))
 	}
-
+	
 	/**
 	 * the Text list
 	 */
@@ -51,18 +51,18 @@
 	def initialTypesValues;
 	@Override
 	public void _process() {
-
+		
 		if (orderedTextIDs == null) orderedTextIDs = module.getProject().getTextsID() ;
-
+		
 		Project project = module.getProject();
-
+		
 		texts = orderedTextIDs.collect() { id -> module.getProject().getText(id) }
 		textsToProcess = getTextsToProcess(texts)
-
+		
 		// get all structures
 		sattrsListener = new SAttributesListener() // will store the structure and properties declaration
 		sattrsListener.W = wtag
-
+		
 		File registryFile = new File(regPath)
 		
 		initialTypesValues = new HashSet<String>()
@@ -87,32 +87,32 @@
 			corpus.setName(project.getName());
 		}
 		corpus.setDescription("Built with the XTZ import module");
-
+		
 		if (!doScanStep()) return;
 		if (!doCQPStep()) return;
 		if (!doCWBEncodeStep()) return;
 		if (!doCWBMakeAllStep()) return;
-
-		if (module.getProject().getCleanAfterBuild() 
-			&& !module.getProject().getDoUpdate()) { // for optimization purpose, don't clean the CQP files
+		
+		if (module.getProject().getCleanAfterBuild()
+				&& !module.getProject().getDoUpdate()) { // for optimization purpose, don't clean the CQP files
 			new File(module.getBinaryDirectory(), "cqp").deleteDir()
 		}
-
+		
 		isSuccessFul = true;
 	}
-
+	
 	/**
 	 * Scan all XML-TXM files to find out structures and word properties
 	 */
 	public boolean doScanStep() {
-
+		
 		println "-- Scanning structures&properties to create for "+texts.size()+" texts..."
-
-
-
+		
+		
+		
 		//		def initialTypesValues = new HashSet<String>()
 		//		initialTypesValues.addAll(sattrsListener.getAnatypes())
-
+		
 		// get all word properties
 		ConsoleProgressBar cpb = new ConsoleProgressBar(texts.size())
 		for (Text t : texts) {
@@ -129,9 +129,9 @@
 				return false;
 			}
 		}
-
+		
 		if (initialTypesValues.size() == sattrsListener.getAnatypes().size()
-			&& initialTypesValues.containsAll(sattrsListener.getAnatypes())) { // the word properties changed all CQP files must be recreated
+				&& initialTypesValues.containsAll(sattrsListener.getAnatypes())) { // the word properties changed all CQP files must be recreated
 			// no new property
 		} else {
 			if (module.isUpdatingCorpus()) {
@@ -140,16 +140,17 @@
 			textsToProcess.clear()
 			textsToProcess.addAll(texts)
 		}
-
+		
 		println ""
 		return true;
 	}
-
+	
 	def getTextsToProcess(def texts) {
+		
 		def textsToProcess = texts.findAll() { text ->
 			File xmlFile = text.getXMLTXMFile()
 			String textname = text.getName()
-
+			
 			File cqpFile = new File(cqpDirectory, textname + ".cqp")
 			cqpFiles << cqpFile // insert cqp files to concat later
 			// skip step if cqpFile exists AND is more recent than the XML-TXM File
@@ -157,39 +158,80 @@
 			if (!cqpFile.exists() || xmlFile.lastModified() >= cqpFile.lastModified()) {
 				return true
 			}
-
+			
 			if (!text.isDirty() && !mustBuild) {
 				Log.finer("skipping .cqp step of $text");
 				return false
 			}
-
+			
 			return true
 		}
-
+		
 		return textsToProcess
 	}
-
+	
 	def cqpFiles = [] // ordered cqp files to concat before calling cwb-encode
 	int cqpFilesUpdated = 0;
+	LinkedHashMap<String, LinkedHashMap<String, String>> projectionsFromValues = new LinkedHashMap<String, LinkedHashMap<String, String>>(); // values of properties to inject
+	LinkedHashMap<String, LinkedHashMap<String, ArrayList<ArrayList>>> projectionsToDo = new LinkedHashMap<String, LinkedHashMap<String, ArrayList<ArrayList>>>(); // list of projections to do
 	public boolean doCQPStep() {
-
+		
 		cqpDirectory.mkdir(); // if not created
-
+		
 		println "-- Building CQP files ${textsToProcess.size()}/${texts.size()}..."
-
+		
+		// Building projections datas to use for each step
+		String projectionsParameterValue = module.project.getTextualPlan("Projections").trim()
+		projectionsParameterValue = projectionsParameterValue.replace("\n", "\t")
+		def projectionsParameter = projectionsParameterValue.split("\t");
+		if (projectionsParameterValue.length() > 0) {
+			for (def projection : projectionsParameter) {
+				if (!projection.contains("->")) continue;
+				
+				String[] fromTo = projection.split("->", 2)
+				String from = fromTo[0].trim()
+				String to = fromTo[1].trim()
+				if (projection.contains("->") && from.contains("_") && to.contains("_")) {
+					String toStructure = to.substring(0, to.indexOf("_"))
+					String toStructureProperty = to.substring(to.indexOf("_") + 1)
+					String fromStructure = from.substring(0, from.indexOf("_"))
+					String fromStructureProperty = from.substring(from.indexOf("_") + 1)
+					
+					if (!projectionsToDo.containsKey(toStructure)) {
+						projectionsToDo[toStructure] = new LinkedHashMap<String, ArrayList<ArrayList>>();
+					}
+					if (!projectionsToDo[toStructure].containsKey(fromStructure)) {
+						projectionsToDo[toStructure][fromStructure] = new ArrayList<ArrayList>();
+					}
+					projectionsToDo[toStructure][fromStructure].add([toStructureProperty, fromStructureProperty])
+					
+					if (!projectionsFromValues.containsKey(fromStructure)) projectionsFromValues[fromStructure] = new LinkedHashMap<String, String>();
+					projectionsFromValues[fromStructure][fromStructureProperty] = "";
+				}
+			}
+		}
+		// registering the new structure properties
+		for (String struct : projectionsToDo.keySet()) {
+			for (String struct2 : projectionsToDo[struct].keySet()) {
+				for (def couple : projectionsToDo[struct][struct2]) {
+					sattrsListener.getStructs()[struct].add(couple[0])
+				}
+			}
+		}
+		
 		ConsoleProgressBar cpb = new ConsoleProgressBar(textsToProcess.size())
 		cqpFilesUpdated = 0;
 		for (Text text : textsToProcess) {
 			cpb.tick();
-
+			
 			File xmlFile = text.getXMLTXMFile()
 			String textname = text.getName()
-
+			
 			File cqpFile = new File(cqpDirectory, textname + ".cqp")
-
+			
 			cqpFilesUpdated++
-
-			XTZCompilerStep step = new XTZCompilerStep(xmlFile, cqpFile, textname, corpusname, "default", sattrsListener.getAnatypes(), wtag)
+			
+			XTZCompilerStep step = new XTZCompilerStep(this, xmlFile, cqpFile, textname, corpusname, "default", sattrsListener.getAnatypes(), wtag)
 			step.setNormalizeAnaValues(doNormalizeAnaValues)
 			step.setNormalizeAttributeValues(doNormalizeAttributeValues)
 			if (!step.process()) {
@@ -200,7 +242,7 @@
 		println ""
 		return true;
 	}
-
+	
 	public boolean doCWBEncodeStep() {
 		println "-- Running cwb-encode..."
 		
@@ -208,46 +250,46 @@
 		DeleteDir.deleteDirectory(outputDirectory);
 		outputDirectory.mkdirs();
 		dataDirectory.mkdirs();
-
+		
 		DeleteDir.deleteDirectory(registryDirectory);
 		registryDirectory.mkdirs();
 		
 		CwbEncode cwbEn = new CwbEncode()
 		cwbEn.setDebug(debug)
-
+		
 		List<String> pargs = ["id"]
 		for (String ana : sattrsListener.getAnatypes()) {
 			if (ana == "word") continue; // no need to be added, cwb will declared it automatically
 			if (ana == "id") continue; // no need to be added, we did it already
 			pargs.add(ana)
 		}
-
+		
 		String[] pAttrs = pargs
-
+		
 		def structs = sattrsListener.getStructs()
 		def structsProf = sattrsListener.getProfs()
-
+		
 		if (debug) {
 			println structs
 			println structsProf
 		}
-
+		
 		List<String> sargs = new ArrayList<String>()
 		def tmpTextAttrs = []
 		for (String name : structs.keySet()) {
 			if (name == "txmcorpus") continue;
-
+			
 			if (name == "text") {
 				for (String value : structs.get(name)) // append the attributes
 					tmpTextAttrs << value // added after
 				continue;
 			}
-
+			
 			String concat = name+":"+structsProf.get(name); // append the depth
 			for (String attributeName : structs.get(name)) { // append the attributes
 				concat += "+"+attributeName.toLowerCase();
 			}
-
+			
 			if (structs.get(name).size() == 0) {
 				concat += "+n";
 			} else {
@@ -255,26 +297,26 @@
 					concat += "+n"
 				}
 			}
-
+			
 			if ((name == "p" || name == "body" || name == "back" || name == "front")
-			&& !concat.contains("+n+") && !concat.endsWith("+n")) {
+					&& !concat.contains("+n+") && !concat.endsWith("+n")) {
 				concat += "+n"
 			}
 			sargs.add(concat)
 		}
-
+		
 		String textSAttributes = "text:0+id+base+project";
 		for (String name : tmpTextAttrs) {
 			if (!("id".equals(name) || "base".equals(name) || "project".equals(name))) {
 				textSAttributes += "+"+name.toLowerCase()
 			}
 		}
-
+		
 		sargs.add(textSAttributes)
 		sargs.add("txmcorpus:0+lang")
-
+		
 		sargs.sort()
-
+		
 		String[] sAttributes = sargs
 		String[] pAttributes = pAttrs
 		println " Word properties: "+pAttributes.join(', ')
@@ -286,15 +328,15 @@
 				println "Fail to write the master cqp file: "+allcqpFile
 				return false;
 			}
-
+			
 			new File(regPath).delete()// ensure the registry file is deleted
-
+			
 			if (!cwbEn.run(outputDirectory.getAbsolutePath() + "/$corpusname",
-			allcqpFile.getAbsolutePath(), regPath, pAttributes, sAttributes, false)) {
+					allcqpFile.getAbsolutePath(), regPath, pAttributes, sAttributes, false)) {
 				println "** cwb-encode did not ends well. Please activate a finer log level to see more details."
 				return false;
 			}
-
+			
 			allcqpFile.delete(); // clean
 		} catch (Exception e) {
 			println "Error while running cwb-encode: "+e
@@ -305,13 +347,13 @@
 		println ""
 		return true;
 	}
-
+	
 	public boolean doCWBMakeAllStep() {
 		println "-- Running cwb-makeall..."
 		try {
 			CwbMakeAll cwbMa = new CwbMakeAll();
 			cwbMa.setDebug(debug);
-
+			
 			if (!new File(regPath).exists()) {
 				println "Error: The registry file was not created: $regPath. See https://groupes.renater.fr/wiki/txm-users/public/faq"
 				return false;
@@ -320,7 +362,7 @@
 				println "** cwb-makeall did not ends well. Activate finer logs to see details."
 				return false;
 			}
-
+			
 			// remove milestones from CWB registry and data files
 			FixMilestoneDeclarations fm = new FixMilestoneDeclarations(
 					new File(regPath), new File(outputDirectory.getAbsolutePath(), corpusname));
Index: TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/scripts/importer/xtz/XTZPager.groovy
===================================================================
--- TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/scripts/importer/xtz/XTZPager.groovy	(revision 3406)
+++ TXM/trunk/org.txm.groovy.core/src/groovy/org/txm/scripts/importer/xtz/XTZPager.groovy	(revision 3407)
@@ -236,7 +236,7 @@
 			edition.setIndex(outputDirectory.getAbsolutePath());
 
 			try {
-				def ed = new XTZFacsPagerStep(txmFile, newEditionDirectory, imageDirectory, txtname, corpusname, "pb", "facs", wordTag, debug);
+				def ed = new XTZFacsPagerStep(this, txmFile, newEditionDirectory, imageDirectory, txtname, corpusname, "pb", "facs", wordTag, debug);
 				if (!ed.process()) {
 					println "Fail to build 'facs' edition for text: $txmFile"
 					continue;
Index: TXM/trunk/org.txm.core/src/java/org/txm/importer/xtz/Step.java
===================================================================
--- TXM/trunk/org.txm.core/src/java/org/txm/importer/xtz/Step.java	(revision 3406)
+++ TXM/trunk/org.txm.core/src/java/org/txm/importer/xtz/Step.java	(revision 3407)
@@ -1,9 +1,11 @@
 package org.txm.importer.xtz;
 
 public class Step {
+	
+	protected ImportStep importStep;
 
-	public Step() {
-		// TODO Auto-generated constructor stub
+	public Step(ImportStep importStep) {
+		this.importStep = importStep;
 	}
 
 	public boolean process() {
Index: TXM/trunk/org.txm.rcp/src/main/java/org/txm/rcp/editors/imports/sections/TextualPlansSection.java
===================================================================
--- TXM/trunk/org.txm.rcp/src/main/java/org/txm/rcp/editors/imports/sections/TextualPlansSection.java	(revision 3406)
+++ TXM/trunk/org.txm.rcp/src/main/java/org/txm/rcp/editors/imports/sections/TextualPlansSection.java	(revision 3407)
@@ -26,6 +26,8 @@
 	private Text noteElementsText;
 	
 	private Text milestoneElementsText;
+
+	private Text projectionsText;
 	
 	public TextualPlansSection(ImportFormEditor editor, FormToolkit toolkit2, ScrolledForm form2, Composite parent, int style) {
 		super(editor, toolkit2, form2, parent, style, "textualplans");
@@ -82,6 +84,18 @@
 		milestoneElementsText = toolkit.createText(sectionClient, "", SWT.BORDER); //$NON-NLS-1$
 		gdata = getTextGridData();
 		milestoneElementsText.setLayoutData(gdata);
+		
+		Label label = toolkit.createLabel(sectionClient, "Projections", SWT.WRAP);
+		gdata = getLabelGridData();
+		gdata.colspan = 2;
+		label.setLayoutData(gdata);
+		
+		projectionsText = toolkit.createText(sectionClient, "", SWT.BORDER | SWT.MULTI | SWT.V_SCROLL); //$NON-NLS-1$
+		gdata = getTextGridData();
+		gdata.heightHint = 50;
+		gdata.colspan = 2;
+		
+		projectionsText.setLayoutData(gdata);
 	}
 	
 	@Override
@@ -91,6 +105,7 @@
 			outsideTextElementsToEditText.setText(project.getTextualPlan("OutSideTextTagsAndKeepContent"));
 			noteElementsText.setText(project.getTextualPlan("Note"));
 			milestoneElementsText.setText(project.getTextualPlan("MileStones"));
+			projectionsText.setText(project.getTextualPlan("Projections"));
 		}
 	}
 	
@@ -106,6 +121,8 @@
 			
 			project.setTextualPlan("MileStones", milestoneElementsText.getText().trim());
 			
+			project.setTextualPlan("Projections", projectionsText.getText().trim());
+			
 			return true;
 		}
 		
Index: TXM/trunk/org.txm.rcp/src/main/java/org/txm/rcp/editors/imports/ImportModuleCustomization.java
===================================================================
--- TXM/trunk/org.txm.rcp/src/main/java/org/txm/rcp/editors/imports/ImportModuleCustomization.java	(revision 3406)
+++ TXM/trunk/org.txm.rcp/src/main/java/org/txm/rcp/editors/imports/ImportModuleCustomization.java	(revision 3407)
@@ -168,7 +168,7 @@
 		params.put(PREBUILD, true);
 		params.put(QUERIES, true);
 		params.put(UI, true);
-		params.put(TEXTUALPLANS, false);
+		params.put(TEXTUALPLANS, true);
 		params.put(OPTIONS, true);
 		sectionsPerImportModule.put("transcriberLoader.groovy", params); //$NON-NLS-1$
 		names.put("transcriberLoader.groovy", "XML-TRS + CSV"); //$NON-NLS-1$ //$NON-NLS-2$
