Index: tmp/org.txm.core/src/java/org/txm/importer/StaxIdentityParser.java
===================================================================
--- tmp/org.txm.core/src/java/org/txm/importer/StaxIdentityParser.java	(revision 2541)
+++ tmp/org.txm.core/src/java/org/txm/importer/StaxIdentityParser.java	(revision 2542)
@@ -6,6 +6,8 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
 
 import javax.xml.stream.XMLInputFactory;
 import javax.xml.stream.XMLOutputFactory;
@@ -15,31 +17,49 @@
 import javax.xml.stream.XMLStreamWriter;
 
 public class StaxIdentityParser {
+	
 	/** The input */
 	protected URL inputurl;
+	
 	protected InputStream inputData;
+	
 	protected XMLInputFactory factory;
+	
 	protected XMLStreamReader parser;
-
+	
 	/** The output. */
 	protected XMLOutputFactory outfactory = XMLOutputFactory.newInstance();
+	
 	protected BufferedOutputStream output;
+	
 	protected XMLStreamWriter writer;
-
+	
 	public static String TXMNS = "http://textometrie.org/1.0";
+	
 	public static String TXM = "txm";
+	
 	public static String TEINS = "http://www.tei-c.org/ns/1.0";
+	
 	public static String TEI = "tei";
+	
 	protected static PersonalNamespaceContext Nscontext = new PersonalNamespaceContext();
-
-	//protected StringBuilder currentXPath = new StringBuilder("/")
+	
+	protected StringBuilder currentXPath = new StringBuilder("");
+	
 	protected String localname;
+	
 	int processingXInclude = 0;
-
+	
+	StaxIdentityParser parentParser = null;
+	
+	StaxIdentityParser activeHook = null;
+	
+	LinkedHashMap<String, StaxIdentityParser> hooks = new LinkedHashMap<>();
+	
 	public StaxIdentityParser(File infile) throws IOException, XMLStreamException {
 		this(infile.toURI().toURL());
 	}
-
+	
 	public StaxIdentityParser(URL inputurl) throws IOException, XMLStreamException {
 		this.inputurl = inputurl;
 		this.inputData = inputurl.openStream();
@@ -48,8 +68,61 @@
 	}
 	
 	/**
-	 * Helper method to get an attribute value 
+	 * create a hook parser. When a hook parser is activated, the processXYZ methods are used instead of the parent processXTZ methods.
 	 * 
+	 * The hook can be activated / deactivated by the parent using the mustActivated mustDeactivated methods
+	 * 
+	 * @param parentParser
+	 * @throws IOException
+	 * @throws XMLStreamException
+	 */
+	public StaxIdentityParser(String name, StaxIdentityParser parentParser) throws IOException, XMLStreamException {
+		this.inputurl = null;
+		this.factory = null;
+		this.parentParser = parentParser;
+		this.writer = parentParser.writer;
+		this.parser = parentParser.parser;
+		
+		parentParser.hooks.put(name, this);
+	}
+	
+	/**
+	 * called when the parser is activated by its parent
+	 * 
+	 * @return true if correctly activated
+	 */
+	public boolean activate() {
+		return false;
+	}
+	
+	/**
+	 * called when the parser is deactivated by its parent
+	 * 
+	 * @return true if correctly activated
+	 */
+	public boolean deactivate() {
+		return false;
+	}
+	
+	/**
+	 * 
+	 * @return true if this hook parser must be activated
+	 */
+	public boolean mustActivate() {
+		return false;
+	}
+	
+	/**
+	 * 
+	 * @return true if this hook parser must be desactivated
+	 */
+	public boolean mustDeactivate() {
+		return true;
+	}
+	
+	/**
+	 * Helper method to get an attribute value by its name
+	 * 
 	 * @param name the attribute name
 	 * @return the value if any
 	 */
@@ -57,7 +130,7 @@
 		if (name == null) return null;
 		
 		int c = parser.getAttributeCount();
-		for (int i = 0 ; i < c ; i++) {
+		for (int i = 0; i < c; i++) {
 			if (name.equals(parser.getAttributeLocalName(i))) {
 				return parser.getAttributeValue(i);
 			}
@@ -65,26 +138,40 @@
 		
 		return null;
 	}
-
+	
 	protected void before() {
-
+		
 	}
-
+	
 	protected void after() throws XMLStreamException, IOException {
-		factory = null;
-		if (parser !=null) parser.close();
-		writer.flush();
-		if (writer != null) writer.close();
-		if (inputData != null) inputData.close();
-		writer = null;
-		parser = null;
+		if (factory != null) {
+			factory = null;
+			if (parser != null) {
+				parser.close();
+			}
+			writer.flush();
+			if (writer != null) {
+				writer.close();
+			}
+			if (inputData != null) {
+				inputData.close();
+			}
+			writer = null;
+			parser = null;
+		}
 	}
-
+	
 	protected void closeForError() throws XMLStreamException, IOException {
-		if (parser !=null) parser.close();
-		if (inputData != null) inputData.close();
+		if (factory != null) {
+			if (parser != null) {
+				parser.close();
+			}
+			if (inputData != null) {
+				inputData.close();
+			}
+		}
 	}
-
+	
 	/**
 	 * Creates the output.
 	 *
@@ -93,27 +180,34 @@
 	 */
 	private boolean createOutput(File f) {
 		try {
-			if (writer != null) // process from a file
+			if (writer != null) { // process from a file
 				writer.close();
-			if (output != null) // process from a file
+			}
+			if (output != null) { // process from a file
 				output.close();
-
-			output = new BufferedOutputStream(new FileOutputStream(f), 16*1024);
-
-			writer = outfactory.createXMLStreamWriter(output, "UTF-8");//create a new file
+			}
+			
+			output = new BufferedOutputStream(new FileOutputStream(f), 16 * 1024);
+			
+			writer = outfactory.createXMLStreamWriter(output, "UTF-8");// create a new file
 			writer.setNamespaceContext(Nscontext);
 			return true;
-		} catch (Exception e) {
-			System.out.println("Error: create output of "+f+": "+e);
+		}
+		catch (Exception e) {
+			System.out.println("Error: create output of " + f + ": " + e);
 			return false;
 		}
 	}
-
-	public boolean process(File outfile) throws XMLStreamException, IOException
-	{
-		if (!createOutput(outfile))
+	
+	public boolean process(File outfile) throws XMLStreamException, IOException {
+		if (factory == null) {
+			System.out.println("Error: this parser is a Hook parser to be used with another StaxIdentityParser as a Hook");
 			return false;
-
+		}
+		if (!createOutput(outfile)) {
+			return false;
+		}
+		
 		writer.writeStartDocument("UTF-8", "1.0");
 		writer.writeCharacters("\n");
 		boolean ret = process(writer);
@@ -121,255 +215,352 @@
 			writer.close();
 		}
 		if (output != null) {
-			try {output.close();} catch(Exception e){System.out.println("output excep: "+e);}
+			try {
+				output.close();
+			}
+			catch (Exception e) {
+				System.out.println("output excep: " + e);
+			}
 		}
-
+		
 		if (parser != null) {
-			try {parser.close();} catch(Exception e){System.out.println("parser excep: "+e);}
+			try {
+				parser.close();
+			}
+			catch (Exception e) {
+				System.out.println("parser excep: " + e);
+			}
 		}
 		
 		if (inputData != null) {
-			try {inputData.close();} catch(Exception e){System.out.println("inputData excep: "+e);}
+			try {
+				inputData.close();
+			}
+			catch (Exception e) {
+				System.out.println("inputData excep: " + e);
+			}
 		}
-
+		
 		return ret;
 	}
-
+	
 	public final static String SLASH = "/";
-	public boolean process(XMLStreamWriter awriter) throws XMLStreamException, IOException
-	{
+	
+	public boolean process(XMLStreamWriter awriter) throws XMLStreamException, IOException {
+		
+		if (factory == null) {
+			System.out.println("Error: this parser is a Hook parser to be used with another StaxIdentityParser as a Hook");
+			return false;
+		}
+		
 		this.writer = awriter;
-		//if (processingXInclude == 0) {
+		// if (processingXInclude == 0) {
 		before(); // if you need to do something before reading the xml
-		//}
+		// }
 		try {
 			for (int event = parser.next(); event != XMLStreamConstants.END_DOCUMENT; event = parser.next()) {
-				switch (event) {
-				case XMLStreamConstants.NAMESPACE:
-					processNamespace();
-					break;
-				case XMLStreamConstants.START_ELEMENT:
-					localname = parser.getLocalName();
-					//currentXPath.append(SLASH)
-					processStartElement();
-					break;		
-				case XMLStreamConstants.CHARACTERS:
-					processCharacters();
-					break;
-				case XMLStreamConstants.END_ELEMENT:
-					localname = parser.getLocalName();
-					processEndElement();
-					//currentXPath.substring(0, currentXPath.length() - localname.length() -1)
-					break;
-				case XMLStreamConstants.PROCESSING_INSTRUCTION:
-					processProcessingInstruction();
-					break;
-				case XMLStreamConstants.DTD:
-					processDTD();
-					break;
-				case XMLStreamConstants.CDATA:
-					processCDATA();
-					break;
-				case XMLStreamConstants.COMMENT:
-					processComment();
-					break;
-				case XMLStreamConstants.END_DOCUMENT:
-					processEndDocument();
-					break;
-				case XMLStreamConstants.ENTITY_REFERENCE:
-					processEntityReference();
-					break;
+				
+				if (hooks.size() == 0) {
+					this.processParserEvent(event);
+					continue;
 				}
+				else {
+					
+					if (activeHook != null) {
+						
+						if (activeHook.mustDeactivate()) {
+							activeHook.deactivate();
+							activeHook = null;
+						}
+						else {
+							activeHook.processParserEvent(event);
+							continue;
+						}
+					}
+					
+					if (activeHook == null) {
+						for (StaxIdentityParser hook : hooks.values()) {
+							if (hook.mustActivate()) {
+								if (hook.activate()) {
+									activeHook = hook;
+									activeHook.processParserEvent(event);
+									continue;
+								}
+							}
+						}
+					}
+					
+					if (activeHook == null) {
+						this.processParserEvent(event);
+					}
+				}
 			}
-		} catch(Exception e) {
-			System.out.println("Unexpected error while parsing file "+inputurl+" : "+e);
-			System.out.println("Location line: "+parser.getLocation().getLineNumber()+" character: "+parser.getLocation().getColumnNumber());
+		}
+		catch (Exception e) {
+			System.out.println("Unexpected error while parsing file " + inputurl + " : " + e);
+			System.out.println("Location line: " + parser.getLocation().getLineNumber() + " character: " + parser.getLocation().getColumnNumber());
 			org.txm.utils.logger.Log.printStackTrace(e);
-			//e.printStackTrace();
+			// e.printStackTrace();
 			if (writer != null) writer.close();
 			if (output != null) output.close();
 			parser.close();
 			inputData.close();
 			return false;
 		}
-		//if (processingXInclude == 0) {
+		
+		// if (processingXInclude == 0) {
 		after(); // if you need to do something before closing the parser();
-		//}
+		// }
 		return true;
+		
 	}
-
+	
+	protected void processParserEvent(int event) throws XMLStreamException, IOException {
+		switch (event) {
+			case XMLStreamConstants.NAMESPACE:
+				processNamespace();
+				break;
+			case XMLStreamConstants.START_ELEMENT:
+				localname = parser.getLocalName();
+				currentXPath.append(SLASH);
+				currentXPath.append(localname);
+				buildCurrentAttributes(); // for easier access later
+				
+				
+				
+				processStartElement();
+				break;
+			case XMLStreamConstants.CHARACTERS:
+				processCharacters();
+				break;
+			case XMLStreamConstants.END_ELEMENT:
+				localname = parser.getLocalName();
+				processEndElement();
+				currentXPath.setLength(currentXPath.length() - localname.length() - 1);
+				break;
+			case XMLStreamConstants.PROCESSING_INSTRUCTION:
+				processProcessingInstruction();
+				break;
+			case XMLStreamConstants.DTD:
+				processDTD();
+				break;
+			case XMLStreamConstants.CDATA:
+				processCDATA();
+				break;
+			case XMLStreamConstants.COMMENT:
+				processComment();
+				break;
+			case XMLStreamConstants.END_DOCUMENT:
+				processEndDocument();
+				break;
+			case XMLStreamConstants.ENTITY_REFERENCE:
+				processEntityReference();
+				break;
+		}
+	}
+	
 	/**
 	 * The start element has already been written
+	 * 
 	 * @param tagname
-	 * @throws XMLStreamException 
-	 * @throws IOException 
+	 * @throws XMLStreamException
+	 * @throws IOException
 	 */
 	public void goToEnd(String tagname) throws XMLStreamException, IOException {
-		//System.out.println("start gotoend $tagname"
 		int elements = 1;
 		try {
 			for (int event = parser.next(); event != XMLStreamConstants.END_DOCUMENT; event = parser.next()) {
-				//System.out.println("event "+event
+				// System.out.println("event "+event
 				switch (event) {
-				case XMLStreamConstants.NAMESPACE:
-					processNamespace();
-					break;
-				case XMLStreamConstants.START_ELEMENT:
-					elements++;
-					localname = parser.getLocalName();
-					//currentXPath.append(SLASH)
-					_processStartElement();
-					break;
-				case XMLStreamConstants.CHARACTERS:
-					processCharacters();
-					break;
-				case XMLStreamConstants.PROCESSING_INSTRUCTION:
-					processProcessingInstruction();
-					break;
-				case XMLStreamConstants.DTD:
-					processDTD();
-					break;
-				case XMLStreamConstants.CDATA:
-					processCDATA();
-					break;
-				case XMLStreamConstants.COMMENT:
-					processComment();
-					break;
-				case XMLStreamConstants.END_ELEMENT:
-					elements--;
-					localname = parser.getLocalName();
-					//currentXPath.substring(0, currentXPath.length() - localname.length() -1)
-					writer.writeEndElement();
-					if (elements == 0 && localname == tagname)
-						return;
-					break;
-				case XMLStreamConstants.END_DOCUMENT:
-					processEndDocument();
-					break;
-				case XMLStreamConstants.ENTITY_REFERENCE:
-					processEntityReference();
-					break;
+					case XMLStreamConstants.NAMESPACE:
+						processNamespace();
+						break;
+					case XMLStreamConstants.START_ELEMENT:
+						elements++;
+						localname = parser.getLocalName();
+						currentXPath.append(SLASH);
+						currentXPath.append(localname);
+						buildCurrentAttributes();
+						
+						_processStartElement();
+						break;
+					case XMLStreamConstants.CHARACTERS:
+						processCharacters();
+						break;
+					case XMLStreamConstants.PROCESSING_INSTRUCTION:
+						processProcessingInstruction();
+						break;
+					case XMLStreamConstants.DTD:
+						processDTD();
+						break;
+					case XMLStreamConstants.CDATA:
+						processCDATA();
+						break;
+					case XMLStreamConstants.COMMENT:
+						processComment();
+						break;
+					case XMLStreamConstants.END_ELEMENT:
+						elements--;
+						localname = parser.getLocalName();
+						
+						writer.writeEndElement();
+						
+						currentXPath.setLength(currentXPath.length() - localname.length() - 1);
+						
+						if (elements == 0 && localname == tagname)
+							return;
+						break;
+					case XMLStreamConstants.END_DOCUMENT:
+						processEndDocument();
+						break;
+					case XMLStreamConstants.ENTITY_REFERENCE:
+						processEntityReference();
+						break;
 				}
 			}
-		} catch(Exception e) {
-			System.out.println("Error while parsing file "+inputurl);
-			System.out.println("Location "+parser.getLocation());
+		}
+		catch (Exception e) {
+			System.out.println("Error while parsing file " + inputurl);
+			System.out.println("Location " + parser.getLocation());
 			org.txm.utils.logger.Log.printStackTrace(e);
 			output.close();
 			parser.close();
 			return;
 		}
 	}
-
+	
 	public String getLocation() {
-		if (parser != null)
-			return "Line: "+parser.getLocation().getLineNumber()+" Col: "+parser.getLocation().	getColumnNumber();
+		if (parser != null) {
+			return "Line: " + parser.getLocation().getLineNumber() + " Col: " + parser.getLocation().getColumnNumber();
+		}
 		return null;
 	}
-
+	
+	public static final String INCLUDE = "include";
+	
+	public static final String XI = "xi";
+	
+	
 	protected void processNamespace() throws XMLStreamException {
 		writer.writeNamespace(parser.getPrefix(), parser.getNamespaceURI());
 	}
-
-	public static final String INCLUDE = "include";
-	public static final String XI = "xi";
-
-	protected void processStartElement() throws XMLStreamException, IOException
-	{
+	
+	
+	protected void processStartElement() throws XMLStreamException, IOException {
 		String prefix = parser.getPrefix();
 		if (INCLUDE == localname && XI == prefix) {
 			processXInclude();
-		} else {
-			if (prefix != null && prefix.length() > 0)
+		}
+		else {
+			if (prefix != null && prefix.length() > 0) {
 				writer.writeStartElement(Nscontext.getNamespaceURI(prefix), localname);
-			else
+			}
+			else {
 				writer.writeStartElement(localname);
-
-			for (int i = 0 ; i < parser.getNamespaceCount() ; i++) {
+			}
+			
+			for (int i = 0; i < parser.getNamespaceCount(); i++) {
 				writer.writeNamespace(parser.getNamespacePrefix(i), parser.getNamespaceURI(i));
 			}
-
+			
 			writeAttributes();
 		}
 	}
-
-	private void _processStartElement() throws XMLStreamException, IOException
-	{
+	
+	private void _processStartElement() throws XMLStreamException, IOException {
 		String prefix = parser.getPrefix();
 		if (INCLUDE == localname && XI == prefix) {
 			processXInclude();
-		} else {
-			if (prefix != null && prefix.length() > 0)
+		}
+		else {
+			if (prefix != null && prefix.length() > 0) {
 				writer.writeStartElement(Nscontext.getNamespaceURI(prefix), localname);
-			else
+			}
+			else {
 				writer.writeStartElement(localname);
-
-			for (int i = 0 ; i < parser.getNamespaceCount() ; i++) {
+			}
+			for (int i = 0; i < parser.getNamespaceCount(); i++) {
 				writer.writeNamespace(parser.getNamespacePrefix(i), parser.getNamespaceURI(i));
 			}
-
+			
 			writeAttributes();
 		}
 	}
-
+	
+	HashMap<String, String> currentAttributes = new HashMap<>();
+	
+	public void buildCurrentAttributes() throws XMLStreamException {
+		currentAttributes.clear();
+		for (int i = 0; i < parser.getAttributeCount(); i++) {
+			currentAttributes.put(parser.getAttributeLocalName(i), parser.getAttributeValue(i));
+		}
+	}
+	
+	public HashMap<String, String> getCurrentAttributes() throws XMLStreamException {
+		currentAttributes.clear();
+		for (int i = 0; i < parser.getAttributeCount(); i++) {
+			currentAttributes.put(parser.getAttributeLocalName(i), parser.getAttributeValue(i));
+		}
+		return currentAttributes;
+	}
+	
 	protected void writeAttributes() throws XMLStreamException {
-		for (int i = 0 ; i < parser.getAttributeCount() ; i++) {
+		for (int i = 0; i < parser.getAttributeCount(); i++) {
 			writeAttribute(parser.getAttributePrefix(i), parser.getAttributeLocalName(i), parser.getAttributeValue(i));
 		}
 	}
-
+	
 	protected void writeAttribute(String prefix, String name, String value) throws XMLStreamException {
-		if (prefix != null && prefix.length() > 0)
-			writer.writeAttribute(prefix+":"+name, value);
-		else
+		if (prefix != null && prefix.length() > 0) {
+			writer.writeAttribute(prefix + ":" + name, value);
+		}
+		else {
 			writer.writeAttribute(name, value);
+		}
 	}
-
-	protected void processCharacters() throws XMLStreamException
-	{
+	
+	protected void processCharacters() throws XMLStreamException {
 		writer.writeCharacters(parser.getText());
 	}
-
-	protected void processProcessingInstruction() throws XMLStreamException
-	{
+	
+	protected void processProcessingInstruction() throws XMLStreamException {
 		writer.writeProcessingInstruction(parser.getPITarget(), parser.getPIData());
 	}
-
-	protected void processDTD() throws XMLStreamException
-	{
+	
+	protected void processDTD() throws XMLStreamException {
 		writer.writeDTD(parser.getText());
 	}
-
-	protected void processCDATA() throws XMLStreamException
-	{
-		writer.writeCData(parser.getText())	;
+	
+	protected void processCDATA() throws XMLStreamException {
+		writer.writeCData(parser.getText());
 	}
-
-	protected void processComment() throws XMLStreamException
-	{
+	
+	protected void processComment() throws XMLStreamException {
 		writer.writeComment(parser.getText());
 	}
-
-	protected void processEndElement() throws XMLStreamException
-	{
+	
+	protected void processEndElement() throws XMLStreamException {
 		if (localname == INCLUDE && parser.getPrefix() == XI) {
 			// nothing !!
-		} else {
+		}
+		else {
 			writer.writeEndElement();
 		}
 	}
-
+	
 	protected void processEndDocument() throws XMLStreamException {
 		writer.writeEndDocument();
 	}
-
+	
 	protected void processEntityReference() throws XMLStreamException {
 		writer.writeEntityRef(parser.getLocalName());
 	}
+	
 	/**
 	 * Process the XInclude elements
-	 * @throws IOException 
-	 * @throws XMLStreamException 
+	 * 
+	 * @throws IOException
+	 * @throws XMLStreamException
 	 */
 	protected void processXInclude() throws XMLStreamException, IOException {
 		String url = parser.getAttributeValue(null, "href"); // relative only
@@ -378,7 +569,7 @@
 		if (ref.exists()) {
 			URL includeurl = ref.toURI().toURL();
 			// save variables before killing them
-			System.out.println("process xi include: "+ref);
+			System.out.println("process xi include: " + ref);
 			XMLStreamReader parserSave = this.parser; // back up current parser
 			InputStream xiIncludeInputData = includeurl.openStream();
 			XMLStreamReader xiIncludeParser = factory.createXMLStreamReader(xiIncludeInputData);
@@ -387,32 +578,39 @@
 			this.process(writer);
 			processingXInclude--; // end of XInclude processing
 			this.parser = parserSave; // restore parser
-		} else {
+		}
+		else {
 			System.out.println("Warning referenced file: $ref does not exists");
 		}
 	}
-
-	public static void main(String[] args)
-	{
+	
+	public String getCurrentPath() {
+		return currentXPath.toString();
+	}
+	
+	public static void main(String[] args) {
 		try {
-			File input = new File("/home/mdecorde/xml/xiinclude/master.xml");
-			File output = new File("/home/mdecorde/xml/xiinclude/merged.xml");
+			File input = new File(System.getProperty("user.home"), "xml/tdm80j/out.xml");
+			File output = new File(System.getProperty("user.home"), "TEMP/identity.xml");
 			if (!(input.exists() && input.canRead())) {
 				System.out.println("cannot found $input");
 				return;
 			}
 			StaxIdentityParser builder;
-
+			
 			builder = new StaxIdentityParser(input.toURI().toURL());
-
+			long time = System.currentTimeMillis();
 			if (builder.process(output)) {
-				System.out.println("success ? "+ValidateXml.test(output));
-			} else {
+				System.out.println("Time=" + (System.currentTimeMillis() - time));
+				System.out.println("success ? " + ValidateXml.test(output));
+			}
+			else {
 				System.out.println("failure !");
 			}
-		} catch (Exception e) {
+		}
+		catch (Exception e) {
 			// TODO Auto-generated catch block
 			e.printStackTrace();
 		}
 	}
-}
\ No newline at end of file
+}
