Clover Coverage Report
Coverage timestamp: Sa Aug 2 2008 13:56:27 CEST
../../../../../img/srcFileCovDistChart8.png 47% of files have more coverage
115   439   36   6,76
24   225   0,31   17
17     2,12  
1    
 
  XPathLocationParser       Line # 59 115 36 79,5% 0.7948718
 
  (30)
 
1    /* $Id: XPathLocationParser.java,v 1.1 2008/07/26 08:00:50 m31 Exp $
2    *
3    * This file is part of the project "Hilbert II" - http://www.qedeq.org
4    *
5    * Copyright 2000-2008, Michael Meyling <mime@qedeq.org>.
6    *
7    * "Hilbert II" is free software; you can redistribute
8    * it and/or modify it under the terms of the GNU General Public
9    * License as published by the Free Software Foundation; either
10    * version 2 of the License, or (at your option) any later version.
11    *
12    * This program is distributed in the hope that it will be useful,
13    * but WITHOUT ANY WARRANTY; without even the implied warranty of
14    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15    * GNU General Public License for more details.
16    */
17    package org.qedeq.kernel.xml.tracker;
18   
19    import java.io.File;
20    import java.io.FileInputStream;
21    import java.io.IOException;
22    import java.io.InputStream;
23    import java.io.Reader;
24    import java.net.URL;
25    import java.util.ArrayList;
26    import java.util.HashMap;
27    import java.util.List;
28    import java.util.Map;
29   
30    import javax.xml.parsers.ParserConfigurationException;
31    import javax.xml.parsers.SAXParser;
32    import javax.xml.parsers.SAXParserFactory;
33   
34    import org.qedeq.base.io.TextInput;
35    import org.qedeq.base.trace.Trace;
36    import org.qedeq.base.utility.Enumerator;
37    import org.qedeq.kernel.common.SourcePosition;
38    import org.qedeq.kernel.xml.parser.SimpleHandler;
39    import org.xml.sax.Attributes;
40    import org.xml.sax.InputSource;
41    import org.xml.sax.SAXException;
42    import org.xml.sax.XMLReader;
43   
44    import com.sun.syndication.io.XmlReader;
45   
46    /**
47    * Parser for XML files. Search simple XPath within an XML file.
48    * Usage:
49    * <pre>
50    * final XPathLocationParser parser = new XPathLocationParser(xpath);
51    * parser.parse(xmlFile, original);
52    * return parser.getFind();
53    *
54    * </pre>
55    *
56    * @version $Revision: 1.1 $
57    * @author Michael Meyling
58    */
 
59    public final class XPathLocationParser extends SimpleHandler {
60   
61    /** This class. */
62    private static final Class CLASS = XPathLocationParser.class;
63   
64    /** Namespaces feature id (http://xml.org/sax/features/namespaces). */
65    private static final String NAMESPACES_FEATURE_ID = "http://xml.org/sax/features/namespaces";
66   
67    /** Validation feature id (http://xml.org/sax/features/validation). */
68    private static final String VALIDATION_FEATURE_ID = "http://xml.org/sax/features/validation";
69   
70    /** SAX parser. */
71    private XMLReader reader;
72   
73    /** Search for this simple XPath expression. */
74    private final SimpleXPath find;
75   
76    /** We are currently at this position. */
77    private SimpleXPath current;
78   
79    /** We are currently at this position if we count only occurrences and take every element. The
80    * elements are all named "*". */
81    private SimpleXPath summary;
82   
83    /** This object is parsed. */
84    private File xmlFile;
85   
86    /** Element stack. */
87    private final List elements;
88   
89    /** Current stack level. */
90    private int level;
91   
92    /** Original file location. */
93    private URL original;
94   
95    /**
96    * Search simple XPath within an XML file.
97    *
98    * @param xmlFile Search this file.
99    * @param xpath Search for this simple XPath.
100    * @param original Original file location.
101    * @return Source position information.
102    * @throws ParserConfigurationException
103    * @throws SAXException
104    * @throws IOException
105    */
 
106  32555 toggle public static final SimpleXPath getXPathLocation(final File xmlFile, final String xpath,
107    final URL original)
108    throws ParserConfigurationException, SAXException, IOException {
109  32555 final XPathLocationParser parser = new XPathLocationParser(xpath);
110  32555 parser.parse(xmlFile, original);
111  32555 return parser.getFind();
112    }
113   
114    /**
115    * Search simple XPath within an XML file.
116    *
117    * @param xmlFile Search this file.
118    * @param xpath Search for this simple XPath.
119    * @param original Original file location.
120    * @return Source position information.
121    * @throws ParserConfigurationException
122    * @throws SAXException
123    * @throws IOException
124    */
 
125  24824 toggle public static final SimpleXPath getXPathLocation(final File xmlFile, final SimpleXPath xpath,
126    final URL original)
127    throws ParserConfigurationException, SAXException, IOException {
128  24824 return getXPathLocation(xmlFile, xpath.toString(), original);
129    }
130   
131    /**
132    * Constructor.
133    *
134    * @param xpath XML file path.
135    * @throws ParserConfigurationException Severe parser configuration problem.
136    * @throws SAXException
137    */
 
138  32555 toggle private XPathLocationParser(final String xpath) throws ParserConfigurationException,
139    SAXException {
140  32555 super();
141   
142  32555 find = new SimpleXPath(xpath);
143  32555 elements = new ArrayList(20);
144  32555 level = 0;
145   
146  32555 final String factoryImpl = System.getProperty("javax.xml.parsers.SAXParserFactory");
147  32555 if (factoryImpl == null) {
148  1 System.setProperty("javax.xml.parsers.SAXParserFactory",
149    "org.apache.xerces.jaxp.SAXParserFactoryImpl");
150    }
151  32555 SAXParserFactory factory = SAXParserFactory.newInstance();
152  32555 factory.setNamespaceAware(false);
153  32555 factory.setValidating(false);
154   
155  32555 factory.setFeature(NAMESPACES_FEATURE_ID, false);
156  32555 factory.setFeature(VALIDATION_FEATURE_ID, false);
157   
158  32555 final SAXParser parser = factory.newSAXParser();
159   
160  32555 reader = parser.getXMLReader();
161   
162    // set parser features
163  32555 reader.setFeature(NAMESPACES_FEATURE_ID, false);
164  32555 reader.setFeature(VALIDATION_FEATURE_ID, false);
165    }
166   
167    /**
168    * Parses XML file.
169    *
170    * @param fileName Parse this input.
171    * @param original Original file location.
172    * @throws SAXException Syntactical or semantical problem occurred.
173    * @throws IOException Technical problem occurred.
174    */
 
175  0 toggle public final void parse(final String fileName, final URL original) throws SAXException,
176    IOException {
177  0 final File file = new File(fileName);
178  0 parse(file, original);
179    }
180   
181    /**
182    * Parses XML file.
183    *
184    * @param file Parse this input.
185    * @param original Original file location.
186    * @throws SAXException Syntactical or semantical problem occurred.
187    * @throws IOException Technical problem occurred.
188    */
 
189  32555 toggle public final void parse(final File file, final URL original) throws SAXException, IOException {
190  32555 this.xmlFile = file;
191  32555 this.original = original;
192  32555 elements.clear();
193  32555 level = 0;
194  32555 try {
195  32555 current = new SimpleXPath();
196  32555 summary = new SimpleXPath();
197  32555 reader.setContentHandler(this);
198  32555 InputStream stream = new FileInputStream(file);
199  32555 reader.parse(new InputSource(stream));
200    } catch (SAXException e) {
201  0 Trace.trace(CLASS, this, "parse", e);
202  0 throw e;
203    }
204    }
205   
206    /*
207    * (non-Javadoc)
208    *
209    * @see org.xml.sax.ContentHandler#endDocument()
210    */
 
211  32555 toggle public void endDocument() throws SAXException {
212  32555 elements.clear();
213  32555 level = 0;
214    }
215   
216    /*
217    * (non-Javadoc)
218    *
219    * @see org.xml.sax.ContentHandler#startDocument()
220    */
 
221  32555 toggle public void startDocument() throws SAXException {
222  32555 elements.clear();
223  32555 level = 0;
224    }
225   
226    /*
227    * (non-Javadoc)
228    *
229    * @see org.xml.sax.ContentHandler#characters(char[], int, int)
230    */
 
231  166759188 toggle public void characters(final char[] ch, final int start, final int length) throws SAXException {
232    }
233   
234    /*
235    * (non-Javadoc)
236    *
237    * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
238    */
 
239  0 toggle public void ignorableWhitespace(final char[] ch, final int start, final int length)
240    throws SAXException {
241    }
242   
243    /*
244    * (non-Javadoc)
245    *
246    * @see org.xml.sax.ContentHandler#endPrefixMapping(java.lang.String)
247    */
 
248  0 toggle public void endPrefixMapping(final String prefix) throws SAXException {
249    }
250   
251    /*
252    * (non-Javadoc)
253    *
254    * @see org.xml.sax.ContentHandler#skippedEntity(java.lang.String)
255    */
 
256  0 toggle public void skippedEntity(final String name) throws SAXException {
257    }
258   
259    /*
260    * (non-Javadoc)
261    *
262    * @see org.xml.sax.ContentHandler#processingInstruction(java.lang.String, java.lang.String)
263    */
 
264  0 toggle public void processingInstruction(final String target, final String data) throws SAXException {
265    }
266   
267    /*
268    * (non-Javadoc)
269    *
270    * @see org.xml.sax.ContentHandler#startPrefixMapping(java.lang.String, java.lang.String)
271    */
 
272  0 toggle public void startPrefixMapping(final String prefix, final String uri) throws SAXException {
273    }
274   
275    /*
276    * (non-Javadoc)
277    *
278    * @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String,
279    * java.lang.String, org.xml.sax.Attributes)
280    */
 
281  69328657 toggle public void startElement(final String namespaceURI, final String localName, final String qName,
282    final Attributes atts) throws SAXException {
283  69328657 final String method = "startElement(String, String, Attributes)";
284  69328657 level++;
285  69328657 summary.addElement("*", addOccurence("*"));
286  69328657 current.addElement(qName, addOccurence(qName));
287   
288    // LATER mime 20070109: just for testing is the next if
289    /*
290    if (find.matchesElementsBegining(current, summary)) {
291    System.out.println("part match " + qName);
292    xml.setRow(locator.getLineNumber());
293    xml.setColumn(locator.getColumnNumber());
294    try {
295    xml.skipBackToBeginOfXmlTag();
296    } catch (RuntimeException e) {
297    Trace.trace(this, method, e);
298    }
299    find.setStartLocation(new SourcePosition(xml.getLocalAddress(), xml.getRow(), xml
300    .getColumn()));
301    }
302    */
303  69328657 if (getLocator() == null) {
304  0 throw new SAXException("Locator unexpectedly null");
305    }
306  69328657 if (find.matchesElements(current, summary)) {
307  32555 Trace.trace(CLASS, this, method, "matching elements");
308  32555 Trace.param(CLASS, this, method, qName, current);
309  32555 TextInput xml = null;
310  32555 Reader xmlReader = null;
311  32555 try {
312  32555 xmlReader = new XmlReader(xmlFile);
313  32555 xml = new TextInput(xmlReader);
314    // LATER mime 20080608: old code
315    // xml = new TextInput(xmlFile, IoUtility.getWorkingEncoding(getEncoding()));
316    } catch (IOException io) {
317  0 Trace.fatal(CLASS, this, method, "File \"" + xmlFile + "\" should be readable", io);
318  0 if (getLocator() == null) {
319  0 throw new SAXException("Locator unexpectedly null");
320    }
321    // at least we can set the current location as find location
322  0 find.setStartLocation(new SourcePosition(original,
323    getLocator().getLineNumber(), getLocator().getColumnNumber()));
324  0 return;
325    }
326  32555 xml.setRow(getLocator().getLineNumber());
327  32555 xml.setColumn(getLocator().getColumnNumber());
328   
329  32555 try {
330  32555 xml.skipBackToBeginOfXmlTag();
331    } catch (RuntimeException e) {
332  0 Trace.trace(CLASS, this, method, e);
333    }
334  32555 find.setStartLocation(new SourcePosition(original, xml.getRow(), xml
335    .getColumn()));
336  32555 if (find.getAttribute() != null) {
337  3419 xml.read(); // skip <
338  3419 xml.readNextXmlName(); // must be element name
339  3419 String tag;
340  3419 do {
341  3745 xml.skipWhiteSpace();
342  3745 int row = xml.getRow();
343  3745 int col = xml.getColumn();
344  3745 try {
345  3745 tag = xml.readNextXmlName();
346    } catch (IllegalArgumentException e) {
347  0 break; // LATER mime 20050621: create named exception in readNextXmlName
348    }
349  3745 if (tag.equals(find.getAttribute())) {
350  3419 find.setStartLocation(new SourcePosition(original, row, col));
351  3419 xml.readNextAttributeValue();
352  3419 find.setEndLocation(new SourcePosition(original, xml.getRow(),
353    xml.getColumn()));
354  3419 break;
355    }
356  326 xml.readNextAttributeValue();
357    } while (true);
358    }
359    }
360    }
361   
362    /**
363    * Add element occurrence.
364    *
365    * @param name Element that occurred.
366    * @return Number of occurrences including this one.
367    */
 
368  138657314 toggle private int addOccurence(final String name) {
369  174488894 while (level < elements.size()) {
370  35831580 elements.remove(elements.size() - 1);
371    }
372  174623680 while (level > elements.size()) {
373  35966366 elements.add(new HashMap());
374    }
375  138657314 final Map levelMap = (Map) elements.get(level - 1);
376  138657314 final Enumerator counter;
377  138657314 if (levelMap.containsKey(name)) {
378  52760919 counter = (Enumerator) levelMap.get(name);
379  52760919 counter.increaseNumber();
380    } else {
381  85896395 counter = new Enumerator(1);
382  85896395 levelMap.put(name, counter);
383    }
384  138657314 return counter.getNumber();
385    }
386   
387    /*
388    * (non-Javadoc)
389    *
390    * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String,
391    * java.lang.String)
392    */
 
393  69328657 toggle public void endElement(final String namespaceURI, final String localName, final String qName)
394    throws SAXException {
395  69328657 final String method = "endElement(String, String, Attributes)";
396  69328657 level--;
397  69328657 if (getLocator() == null) {
398  0 current.deleteLastElement();
399  0 summary.deleteLastElement();
400  0 throw new SAXException("Locator unexpectly null");
401    }
402  69328657 if (find.matchesElements(current, summary) && find.getAttribute() == null) {
403  29136 TextInput xml = null;
404  29136 Reader xmlReader = null;
405  29136 try {
406  29136 xmlReader = new XmlReader(xmlFile);
407  29136 xml = new TextInput(xmlReader);
408    // LATER mime 20080608: old code
409    // xml = new TextInput(xmlFile, IoUtility.getWorkingEncoding(getEncoding()));
410    } catch (IOException io) {
411  0 Trace.fatal(CLASS, this, method, "File \"" + xmlFile + "\" should be readable", io);
412  0 if (getLocator() == null) {
413  0 throw new SAXException("Locator unexpectedly null");
414    }
415    // at least we can set the current location as find location
416  0 find.setStartLocation(new SourcePosition(original,
417    getLocator().getLineNumber(), getLocator().getColumnNumber()));
418  0 return;
419    }
420  29136 xml.setRow(getLocator().getLineNumber());
421  29136 xml.setColumn(getLocator().getColumnNumber());
422    // xml.skipForwardToEndOfXmlTag(); // LATER mime 20050810: remove? comment in?
423  29136 find.setEndLocation(new SourcePosition(original, xml.getRow(), xml
424    .getColumn()));
425    }
426  69328657 current.deleteLastElement();
427  69328657 summary.deleteLastElement();
428    }
429   
430    /**
431    * Get searched XPath. Hopefully the start and end location are set.
432    *
433    * @return Searched XPath.
434    */
 
435  32555 toggle public SimpleXPath getFind() {
436  32555 return find;
437    }
438   
439    }