Révision 2549

tmp/org.txm.core/src/java/org/txm/xml/Hook.java (revision 2549)
1
package org.txm.xml;
2

  
3
import java.io.BufferedOutputStream;
4
import java.io.File;
5
import java.io.FileOutputStream;
6
import java.io.IOException;
7
import java.io.InputStream;
8
import java.net.URL;
9
import java.util.HashMap;
10
import java.util.LinkedHashMap;
11

  
12
import javax.xml.stream.XMLInputFactory;
13
import javax.xml.stream.XMLOutputFactory;
14
import javax.xml.stream.XMLStreamConstants;
15
import javax.xml.stream.XMLStreamException;
16
import javax.xml.stream.XMLStreamReader;
17
import javax.xml.stream.XMLStreamWriter;
18

  
19
import org.txm.importer.PersonalNamespaceContext;
20

  
21
public class Hook {
22
	
23
	protected StringBuilder currentXPath = new StringBuilder("");
24
	
25
	protected String localname;
26
	
27
	XMLProcessor parentParser = null;
28

  
29
	private String name;
30
	
31
	/**
32
	 * create a hook parser. When a hook parser is activated, the processXYZ methods are used instead of the parent processXTZ methods.
33
	 * 
34
	 * The hook can be activated / deactivated by the parent using the mustActivated mustDeactivated methods
35
	 * 
36
	 * @param parentParser
37
	 * @throws IOException
38
	 * @throws XMLStreamException
39
	 */
40
	public Hook(String name, XMLProcessor parentParser) throws IOException, XMLStreamException {
41
		this.parentParser = parentParser;
42
		this.name = name;
43
	}
44
	
45
	/**
46
	 * called when the parser is activated by its parent
47
	 * 
48
	 * @return true if correctly activated
49
	 */
50
	public boolean activate() {
51
		return false;
52
	}
53
	
54
	/**
55
	 * called when the parser is deactivated by its parent
56
	 * 
57
	 * @return true if correctly activated
58
	 */
59
	public boolean deactivate() {
60
		return false;
61
	}
62
	
63
	/**
64
	 * 
65
	 * @return true if this hook parser must be activated
66
	 */
67
	public boolean mustActivate() {
68
		return false;
69
	}
70
	
71
	/**
72
	 * 
73
	 * @return true if this hook parser must be desactivated
74
	 */
75
	public boolean mustDeactivate() {
76
		return true;
77
	}
78
		
79
	protected void before() {
80
		
81
	}
82
	
83
	protected void after() throws XMLStreamException, IOException {
84
	}
85
	
86
	protected void closeForError() throws XMLStreamException, IOException {
87

  
88
	}
89
	
90
	public final static String SLASH = "/";
91
		
92
	protected void processParserEvent(int event) throws XMLStreamException, IOException {
93
		switch (event) {
94
			case XMLStreamConstants.NAMESPACE:
95
				processNamespace();
96
				break;
97
			case XMLStreamConstants.START_ELEMENT:
98
				localname = parentParser.parser.getLocalName();
99
				currentXPath.append(SLASH);
100
				currentXPath.append(localname);
101
				buildCurrentAttributes(); // for easier access later
102
				
103
				processStartElement();
104
				break;
105
			case XMLStreamConstants.CHARACTERS:
106
				processCharacters();
107
				break;
108
			case XMLStreamConstants.END_ELEMENT:
109
				localname = parentParser.parser.getLocalName();
110
				processEndElement();
111
				currentXPath.setLength(currentXPath.length() - localname.length() - 1);
112
				break;
113
			case XMLStreamConstants.PROCESSING_INSTRUCTION:
114
				processProcessingInstruction();
115
				break;
116
			case XMLStreamConstants.DTD:
117
				processDTD();
118
				break;
119
			case XMLStreamConstants.CDATA:
120
				processCDATA();
121
				break;
122
			case XMLStreamConstants.COMMENT:
123
				processComment();
124
				break;
125
			case XMLStreamConstants.END_DOCUMENT:
126
				processEndDocument();
127
				break;
128
			case XMLStreamConstants.ENTITY_REFERENCE:
129
				processEntityReference();
130
				break;
131
		}
132
	}
133
		
134
	public final String getLocation() {
135
		if (parentParser.parser != null) {
136
			return "Line: " +name+": "+ parentParser.parser.getLocation().getLineNumber() + " Col: " + parentParser.parser.getLocation().getColumnNumber();
137
		}
138
		return null;
139
	}
140
	
141
	protected void processNamespace() throws XMLStreamException {
142
	}
143
	
144
	
145
	protected void processStartElement() throws XMLStreamException, IOException {
146

  
147
	}
148
	
149
	private HashMap<String, String> currentAttributes = new HashMap<>();
150
	
151
	public final void buildCurrentAttributes() throws XMLStreamException {
152
		currentAttributes.clear();
153
		for (int i = 0; i < parentParser.parser.getAttributeCount(); i++) {
154
			currentAttributes.put(parentParser.parser.getAttributeLocalName(i), parentParser.parser.getAttributeValue(i));
155
		}
156
	}
157
	
158
	public final HashMap<String, String> getCurrentAttributes() throws XMLStreamException {
159
		return currentAttributes;
160
	}
161

  
162
	
163
	protected void processCharacters() throws XMLStreamException {
164
	}
165
	
166
	protected void processProcessingInstruction() throws XMLStreamException {
167
	}
168
	
169
	protected void processDTD() throws XMLStreamException {
170
	}
171
	
172
	protected void processCDATA() throws XMLStreamException {
173
	}
174
	
175
	protected void processComment() throws XMLStreamException {
176
	}
177
	
178
	protected void processEndElement() throws XMLStreamException {
179
	}
180
	
181
	protected void processEndDocument() throws XMLStreamException {
182
	}
183
	
184
	protected void processEntityReference() throws XMLStreamException {
185
	}
186

  
187
	public String getCurrentPath() {
188
		return currentXPath.toString();
189
	}
190
}
0 191

  
tmp/org.txm.core/src/java/org/txm/xml/XMLProcessor.java (revision 2549)
1
package org.txm.xml;
2

  
3
import java.io.BufferedOutputStream;
4
import java.io.File;
5
import java.io.FileOutputStream;
6
import java.io.IOException;
7
import java.io.InputStream;
8
import java.net.URL;
9
import java.util.HashMap;
10
import java.util.LinkedHashMap;
11

  
12
import javax.xml.stream.XMLInputFactory;
13
import javax.xml.stream.XMLOutputFactory;
14
import javax.xml.stream.XMLStreamConstants;
15
import javax.xml.stream.XMLStreamException;
16
import javax.xml.stream.XMLStreamReader;
17
import javax.xml.stream.XMLStreamWriter;
18

  
19
import org.txm.importer.PersonalNamespaceContext;
20

  
21
public class XMLProcessor {
22
	
23
	/** The input */
24
	protected URL inputurl;
25
	
26
	protected InputStream inputData;
27
	
28
	protected XMLInputFactory factory;
29
	
30
	protected XMLStreamReader parser;
31
	
32
	/** The output. */
33
	protected XMLOutputFactory outfactory = XMLOutputFactory.newInstance();
34
	
35
	protected BufferedOutputStream output;
36
	
37
	protected XMLStreamWriter writer;
38
	
39
	public static String TXMNS = "http://textometrie.org/1.0";
40
	
41
	public static String TXM = "txm";
42
	
43
	public static String TEINS = "http://www.tei-c.org/ns/1.0";
44
	
45
	public static String TEI = "tei";
46
	
47
	protected static PersonalNamespaceContext Nscontext = new PersonalNamespaceContext();
48
	
49
	protected StringBuilder currentXPath = new StringBuilder("");
50
	
51
	protected String localname;
52
	
53
	int processingXInclude = 0;
54
	
55
	Hook activeHook = null;
56
	
57
	LinkedHashMap<String, Hook> hooks = new LinkedHashMap<>();
58
	
59
	public XMLProcessor(File infile) throws IOException, XMLStreamException {
60
		this(infile.toURI().toURL());
61
	}
62
	
63
	public XMLProcessor(URL inputurl) throws IOException, XMLStreamException {
64
		this.inputurl = inputurl;
65
		this.inputData = inputurl.openStream();
66
		this.factory = XMLInputFactory.newInstance();
67
		this.parser = factory.createXMLStreamReader(inputData);
68
	}
69
	
70
	/**
71
	 * called when the parser is activated by its parent
72
	 * 
73
	 * @return true if correctly activated
74
	 */
75
	public boolean activate() {
76
		return false;
77
	}
78
	
79
	/**
80
	 * called when the parser is deactivated by its parent
81
	 * 
82
	 * @return true if correctly activated
83
	 */
84
	public boolean deactivate() {
85
		return false;
86
	}
87
	
88
	/**
89
	 * 
90
	 * @return true if this hook parser must be activated
91
	 */
92
	public boolean mustActivate() {
93
		return false;
94
	}
95
	
96
	/**
97
	 * 
98
	 * @return true if this hook parser must be desactivated
99
	 */
100
	public boolean mustDeactivate() {
101
		return true;
102
	}
103
	
104
	/**
105
	 * Helper method to get an attribute value by its name
106
	 * 
107
	 * @param name the attribute name
108
	 * @return the value if any
109
	 */
110
	public String getParserAttributeValue(String name) {
111
		if (name == null) return null;
112
		
113
		int c = parser.getAttributeCount();
114
		for (int i = 0; i < c; i++) {
115
			if (name.equals(parser.getAttributeLocalName(i))) {
116
				return parser.getAttributeValue(i);
117
			}
118
		}
119
		
120
		return null;
121
	}
122
	
123
	protected void before() {
124
		
125
	}
126
	
127
	protected void after() throws XMLStreamException, IOException {
128
		if (factory != null) {
129
			factory = null;
130
			if (parser != null) {
131
				parser.close();
132
			}
133
			writer.flush();
134
			if (writer != null) {
135
				writer.close();
136
			}
137
			if (inputData != null) {
138
				inputData.close();
139
			}
140
			writer = null;
141
			parser = null;
142
		}
143
	}
144
	
145
	protected void closeForError() throws XMLStreamException, IOException {
146
		if (factory != null) {
147
			if (parser != null) {
148
				parser.close();
149
			}
150
			if (inputData != null) {
151
				inputData.close();
152
			}
153
		}
154
	}
155
	
156
	/**
157
	 * Creates the output.
158
	 *
159
	 * @param outfile the outfile
160
	 * @return true, if successful
161
	 */
162
	private boolean createOutput(File f) {
163
		try {
164
			if (writer != null) { // process from a file
165
				writer.close();
166
			}
167
			if (output != null) { // process from a file
168
				output.close();
169
			}
170
			
171
			output = new BufferedOutputStream(new FileOutputStream(f), 16 * 1024);
172
			
173
			writer = outfactory.createXMLStreamWriter(output, "UTF-8");// create a new file
174
			writer.setNamespaceContext(Nscontext);
175
			return true;
176
		}
177
		catch (Exception e) {
178
			System.out.println("Error: create output of " + f + ": " + e);
179
			return false;
180
		}
181
	}
182
	
183
	public boolean process(File outfile) throws XMLStreamException, IOException {
184
		if (factory == null) {
185
			System.out.println("Error: this parser is a Hook parser to be used with another StaxIdentityParser as a Hook");
186
			return false;
187
		}
188
		if (!createOutput(outfile)) {
189
			return false;
190
		}
191
		
192
		writer.writeStartDocument("UTF-8", "1.0");
193
		writer.writeCharacters("\n");
194
		boolean ret = process(writer);
195
		if (writer != null) {
196
			writer.close();
197
		}
198
		if (output != null) {
199
			try {
200
				output.close();
201
			}
202
			catch (Exception e) {
203
				System.out.println("output excep: " + e);
204
			}
205
		}
206
		
207
		if (parser != null) {
208
			try {
209
				parser.close();
210
			}
211
			catch (Exception e) {
212
				System.out.println("parser excep: " + e);
213
			}
214
		}
215
		
216
		if (inputData != null) {
217
			try {
218
				inputData.close();
219
			}
220
			catch (Exception e) {
221
				System.out.println("inputData excep: " + e);
222
			}
223
		}
224
		
225
		return ret;
226
	}
227
	
228
	public final static String SLASH = "/";
229
	
230
	public boolean process(XMLStreamWriter awriter) throws XMLStreamException, IOException {
231
		
232
		if (factory == null) {
233
			System.out.println("Error: this parser is a Hook parser to be used with another StaxIdentityParser as a Hook");
234
			return false;
235
		}
236
		
237
		this.writer = awriter;
238
		// if (processingXInclude == 0) {
239
		before(); // if you need to do something before reading the xml
240
		// }
241
		try {
242
			for (int event = parser.next(); event != XMLStreamConstants.END_DOCUMENT; event = parser.next()) {
243
				
244
				if (hooks.size() == 0) {
245
					this.processParserEvent(event);
246
					continue;
247
				}
248
				else {
249
					
250
					if (activeHook != null) {
251
						
252
						if (activeHook.mustDeactivate()) {
253
							activeHook.deactivate();
254
							activeHook = null;
255
						}
256
						else {
257
							activeHook.processParserEvent(event);
258
							continue;
259
						}
260
					}
261
					
262
					if (activeHook == null) {
263
						for (Hook hook : hooks.values()) {
264
							if (hook.mustActivate()) {
265
								if (hook.activate()) {
266
									activeHook = hook;
267
									activeHook.processParserEvent(event);
268
									continue;
269
								}
270
							}
271
						}
272
					}
273
					
274
					if (activeHook == null) {
275
						this.processParserEvent(event);
276
					}
277
				}
278
			}
279
		}
280
		catch (Exception e) {
281
			System.out.println("Unexpected error while parsing file " + inputurl + " : " + e);
282
			System.out.println("Location line: " + parser.getLocation().getLineNumber() + " character: " + parser.getLocation().getColumnNumber());
283
			org.txm.utils.logger.Log.printStackTrace(e);
284
			// e.printStackTrace();
285
			if (writer != null) writer.close();
286
			if (output != null) output.close();
287
			parser.close();
288
			inputData.close();
289
			return false;
290
		}
291
		
292
		// if (processingXInclude == 0) {
293
		after(); // if you need to do something before closing the parser();
294
		// }
295
		return true;
296
		
297
	}
298
	
299
	protected void processParserEvent(int event) throws XMLStreamException, IOException {
300
		switch (event) {
301
			case XMLStreamConstants.NAMESPACE:
302
				processNamespace();
303
				break;
304
			case XMLStreamConstants.START_ELEMENT:
305
				localname = parser.getLocalName();
306
				currentXPath.append(SLASH);
307
				currentXPath.append(localname);
308
				buildCurrentAttributes(); // for easier access later
309
				
310
				
311
				
312
				processStartElement();
313
				break;
314
			case XMLStreamConstants.CHARACTERS:
315
				processCharacters();
316
				break;
317
			case XMLStreamConstants.END_ELEMENT:
318
				localname = parser.getLocalName();
319
				processEndElement();
320
				currentXPath.setLength(currentXPath.length() - localname.length() - 1);
321
				break;
322
			case XMLStreamConstants.PROCESSING_INSTRUCTION:
323
				processProcessingInstruction();
324
				break;
325
			case XMLStreamConstants.DTD:
326
				processDTD();
327
				break;
328
			case XMLStreamConstants.CDATA:
329
				processCDATA();
330
				break;
331
			case XMLStreamConstants.COMMENT:
332
				processComment();
333
				break;
334
			case XMLStreamConstants.END_DOCUMENT:
335
				processEndDocument();
336
				break;
337
			case XMLStreamConstants.ENTITY_REFERENCE:
338
				processEntityReference();
339
				break;
340
		}
341
	}
342
	
343
	/**
344
	 * The start element has already been written
345
	 * 
346
	 * @param tagname
347
	 * @throws XMLStreamException
348
	 * @throws IOException
349
	 */
350
	public void goToEnd(String tagname) throws XMLStreamException, IOException {
351
		int elements = 1;
352
		try {
353
			for (int event = parser.next(); event != XMLStreamConstants.END_DOCUMENT; event = parser.next()) {
354
				// System.out.println("event "+event
355
				switch (event) {
356
					case XMLStreamConstants.NAMESPACE:
357
						processNamespace();
358
						break;
359
					case XMLStreamConstants.START_ELEMENT:
360
						elements++;
361
						localname = parser.getLocalName();
362
						currentXPath.append(SLASH);
363
						currentXPath.append(localname);
364
						buildCurrentAttributes();
365
						
366
						_processStartElement();
367
						break;
368
					case XMLStreamConstants.CHARACTERS:
369
						processCharacters();
370
						break;
371
					case XMLStreamConstants.PROCESSING_INSTRUCTION:
372
						processProcessingInstruction();
373
						break;
374
					case XMLStreamConstants.DTD:
375
						processDTD();
376
						break;
377
					case XMLStreamConstants.CDATA:
378
						processCDATA();
379
						break;
380
					case XMLStreamConstants.COMMENT:
381
						processComment();
382
						break;
383
					case XMLStreamConstants.END_ELEMENT:
384
						elements--;
385
						localname = parser.getLocalName();
386
						
387
						writer.writeEndElement();
388
						
389
						currentXPath.setLength(currentXPath.length() - localname.length() - 1);
390
						
391
						if (elements == 0 && localname == tagname)
392
							return;
393
						break;
394
					case XMLStreamConstants.END_DOCUMENT:
395
						processEndDocument();
396
						break;
397
					case XMLStreamConstants.ENTITY_REFERENCE:
398
						processEntityReference();
399
						break;
400
				}
401
			}
402
		}
403
		catch (Exception e) {
404
			System.out.println("Error while parsing file " + inputurl);
405
			System.out.println("Location " + parser.getLocation());
406
			org.txm.utils.logger.Log.printStackTrace(e);
407
			output.close();
408
			parser.close();
409
			return;
410
		}
411
	}
412
	
413
	public String getLocation() {
414
		if (parser != null) {
415
			return "Line: " + parser.getLocation().getLineNumber() + " Col: " + parser.getLocation().getColumnNumber();
416
		}
417
		return null;
418
	}
419
	
420
	public static final String INCLUDE = "include";
421
	
422
	public static final String XI = "xi";
423
	
424
	
425
	protected void processNamespace() throws XMLStreamException {
426
		writer.writeNamespace(parser.getPrefix(), parser.getNamespaceURI());
427
	}
428
	
429
	
430
	protected void processStartElement() throws XMLStreamException, IOException {
431
		String prefix = parser.getPrefix();
432
		if (INCLUDE == localname && XI == prefix) {
433
			processXInclude();
434
		}
435
		else {
436
			if (prefix != null && prefix.length() > 0) {
437
				writer.writeStartElement(Nscontext.getNamespaceURI(prefix), localname);
438
			}
439
			else {
440
				writer.writeStartElement(localname);
441
			}
442
			
443
			for (int i = 0; i < parser.getNamespaceCount(); i++) {
444
				writer.writeNamespace(parser.getNamespacePrefix(i), parser.getNamespaceURI(i));
445
			}
446
			
447
			writeAttributes();
448
		}
449
	}
450
	
451
	private void _processStartElement() throws XMLStreamException, IOException {
452
		String prefix = parser.getPrefix();
453
		if (INCLUDE == localname && XI == prefix) {
454
			processXInclude();
455
		}
456
		else {
457
			if (prefix != null && prefix.length() > 0) {
458
				writer.writeStartElement(Nscontext.getNamespaceURI(prefix), localname);
459
			}
460
			else {
461
				writer.writeStartElement(localname);
462
			}
463
			for (int i = 0; i < parser.getNamespaceCount(); i++) {
464
				writer.writeNamespace(parser.getNamespacePrefix(i), parser.getNamespaceURI(i));
465
			}
466
			
467
			writeAttributes();
468
		}
469
	}
470
	
471
	HashMap<String, String> currentAttributes = new HashMap<>();
472
	
473
	public void buildCurrentAttributes() throws XMLStreamException {
474
		currentAttributes.clear();
475
		for (int i = 0; i < parser.getAttributeCount(); i++) {
476
			currentAttributes.put(parser.getAttributeLocalName(i), parser.getAttributeValue(i));
477
		}
478
	}
479
	
480
	public HashMap<String, String> getCurrentAttributes() throws XMLStreamException {
481
		currentAttributes.clear();
482
		for (int i = 0; i < parser.getAttributeCount(); i++) {
483
			currentAttributes.put(parser.getAttributeLocalName(i), parser.getAttributeValue(i));
484
		}
485
		return currentAttributes;
486
	}
487
	
488
	protected void writeAttributes() throws XMLStreamException {
489
		for (int i = 0; i < parser.getAttributeCount(); i++) {
490
			writeAttribute(parser.getAttributePrefix(i), parser.getAttributeLocalName(i), parser.getAttributeValue(i));
491
		}
492
	}
493
	
494
	protected void writeAttribute(String prefix, String name, String value) throws XMLStreamException {
495
		if (prefix != null && prefix.length() > 0) {
496
			writer.writeAttribute(prefix + ":" + name, value);
497
		}
498
		else {
499
			writer.writeAttribute(name, value);
500
		}
501
	}
502
	
503
	protected void processCharacters() throws XMLStreamException {
504
		writer.writeCharacters(parser.getText());
505
	}
506
	
507
	protected void processProcessingInstruction() throws XMLStreamException {
508
		writer.writeProcessingInstruction(parser.getPITarget(), parser.getPIData());
509
	}
510
	
511
	protected void processDTD() throws XMLStreamException {
512
		writer.writeDTD(parser.getText());
513
	}
514
	
515
	protected void processCDATA() throws XMLStreamException {
516
		writer.writeCData(parser.getText());
517
	}
518
	
519
	protected void processComment() throws XMLStreamException {
520
		writer.writeComment(parser.getText());
521
	}
522
	
523
	protected void processEndElement() throws XMLStreamException {
524
		if (localname == INCLUDE && parser.getPrefix() == XI) {
525
			// nothing !!
526
		}
527
		else {
528
			writer.writeEndElement();
529
		}
530
	}
531
	
532
	protected void processEndDocument() throws XMLStreamException {
533
		writer.writeEndDocument();
534
	}
535
	
536
	protected void processEntityReference() throws XMLStreamException {
537
		writer.writeEntityRef(parser.getLocalName());
538
	}
539
	
540
	/**
541
	 * Process the XInclude elements
542
	 * 
543
	 * @throws IOException
544
	 * @throws XMLStreamException
545
	 */
546
	protected void processXInclude() throws XMLStreamException, IOException {
547
		String url = parser.getAttributeValue(null, "href"); // relative only
548
		File driver = new File(inputurl.getFile());
549
		File ref = new File(driver.getParent(), url);
550
		if (ref.exists()) {
551
			URL includeurl = ref.toURI().toURL();
552
			// save variables before killing them
553
			System.out.println("process xi include: " + ref);
554
			XMLStreamReader parserSave = this.parser; // back up current parser
555
			InputStream xiIncludeInputData = includeurl.openStream();
556
			XMLStreamReader xiIncludeParser = factory.createXMLStreamReader(xiIncludeInputData);
557
			parser = xiIncludeParser;
558
			processingXInclude++; // to avoid recalling before & after methods
559
			this.process(writer);
560
			processingXInclude--; // end of XInclude processing
561
			this.parser = parserSave; // restore parser
562
		}
563
		else {
564
			System.out.println("Warning referenced file: $ref does not exists");
565
		}
566
	}
567
	
568
	public String getCurrentPath() {
569
		return currentXPath.toString();
570
	}
571
	
572
	public static void main(String[] args) {
573
		try {
574
			File input = new File(System.getProperty("user.home"), "xml/tdm80j/out.xml");
575
			File output = new File(System.getProperty("user.home"), "TEMP/identity.xml");
576
			if (!(input.exists() && input.canRead())) {
577
				System.out.println("cannot found $input");
578
				return;
579
			}
580
			XMLProcessor builder;
581
			
582
			builder = new XMLProcessor(input.toURI().toURL());
583
			long time = System.currentTimeMillis();
584
			if (builder.process(output)) {
585
				System.out.println("Time=" + (System.currentTimeMillis() - time));
586
			}
587
			else {
588
				System.out.println("failure !");
589
			}
590
		}
591
		catch (Exception e) {
592
			// TODO Auto-generated catch block
593
			e.printStackTrace();
594
		}
595
	}
596
}
0 597

  

Formats disponibles : Unified diff