Clover coverage report - QedeqKernelSe Coverage Report
Coverage timestamp: Sa Jan 26 2008 14:11:34 CET
file stats: LOC: 411   Methods: 18
NCLOC: 190   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
XPathLocationParser.java 93,8% 92,1% 66,7% 88,6%
coverage coverage
 1    /* $Id: XPathLocationParser.java,v 1.22 2008/01/26 12:39:11 m31 Exp $
 2    *
 3    * This file is part of the project "Hilbert II" - http://www.qedeq.org
 4    *
 5    * Copyright 2000-2007, 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.FileReader;
 21    import java.io.IOException;
 22    import java.net.URL;
 23    import java.util.ArrayList;
 24    import java.util.HashMap;
 25    import java.util.List;
 26    import java.util.Map;
 27   
 28    import javax.xml.parsers.ParserConfigurationException;
 29    import javax.xml.parsers.SAXParser;
 30    import javax.xml.parsers.SAXParserFactory;
 31   
 32    import org.qedeq.kernel.common.SourcePosition;
 33    import org.qedeq.kernel.dto.list.Enumerator;
 34    import org.qedeq.kernel.trace.Trace;
 35    import org.qedeq.kernel.utility.TextInput;
 36    import org.xml.sax.Attributes;
 37    import org.xml.sax.ContentHandler;
 38    import org.xml.sax.InputSource;
 39    import org.xml.sax.Locator;
 40    import org.xml.sax.SAXException;
 41    import org.xml.sax.XMLReader;
 42   
 43    /**
 44    * Parser for XML files. Search simple XPath within an XML file.
 45    * Usage:
 46    * <pre>
 47    * final XPathLocationParser parser = new XPathLocationParser(xpath);
 48    * parser.parse(xmlFile, original);
 49    * return parser.getFind();
 50    *
 51    * </pre>
 52    *
 53    * <p>
 54    * This class uses features specific for Xerces.
 55    *
 56    * @version $Revision: 1.22 $
 57    * @author Michael Meyling
 58    */
 59    public class XPathLocationParser implements ContentHandler {
 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    /** Position locator during parsing. */
 74    private Locator locator;
 75   
 76    /** Search for this simple XPath expression. */
 77    private final SimpleXPath find;
 78   
 79    /** We are currently at this position. */
 80    private SimpleXPath current;
 81   
 82    /** We are currently at this position if we count only occurrences and take every element. The
 83    * elements are all named "*". */
 84    private SimpleXPath summary;
 85   
 86    /** This object is parsed. */
 87    private TextInput xml;
 88   
 89    /** Element stack. */
 90    private final List elements;
 91   
 92    /** Current stack level. */
 93    private int level;
 94   
 95    /** Original file location. */
 96    private URL original;
 97   
 98    /**
 99    * Search simple XPath within an XML file.
 100    *
 101    * @param xmlFile Search this file.
 102    * @param xpath Search for this simple XPath.
 103    * @param original Original file location.
 104    * @return Source position information.
 105    * @throws ParserConfigurationException
 106    * @throws SAXException
 107    * @throws IOException
 108    */
 109  32032 public static final SimpleXPath getXPathLocation(final File xmlFile, final String xpath,
 110    final URL original)
 111    throws ParserConfigurationException, SAXException, IOException {
 112  32032 final XPathLocationParser parser = new XPathLocationParser(xpath);
 113  32032 parser.parse(xmlFile, original);
 114  32032 return parser.getFind();
 115    }
 116   
 117    /**
 118    * Search simple XPath within an XML file.
 119    *
 120    * @param xmlFile Search this file.
 121    * @param xpath Search for this simple XPath.
 122    * @param original Original file location.
 123    * @return Source position information.
 124    * @throws ParserConfigurationException
 125    * @throws SAXException
 126    * @throws IOException
 127    */
 128  24512 public static final SimpleXPath getXPathLocation(final File xmlFile, final SimpleXPath xpath,
 129    final URL original)
 130    throws ParserConfigurationException, SAXException, IOException {
 131  24512 return getXPathLocation(xmlFile, xpath.toString(), original);
 132    }
 133   
 134    /**
 135    * Constructor.
 136    *
 137    * @param xpath XML file path.
 138    * @throws ParserConfigurationException Severe parser configuration problem.
 139    * @throws SAXException
 140    */
 141  32032 public XPathLocationParser(final String xpath) throws ParserConfigurationException,
 142    SAXException {
 143  32032 super();
 144   
 145  32032 find = new SimpleXPath(xpath);
 146  32032 elements = new ArrayList(20);
 147  32032 level = 0;
 148   
 149  32032 final String factoryImpl = System.getProperty("javax.xml.parsers.SAXParserFactory");
 150  32032 if (factoryImpl == null) {
 151  0 System.setProperty("javax.xml.parsers.SAXParserFactory",
 152    "org.apache.xerces.jaxp.SAXParserFactoryImpl");
 153    }
 154  32032 SAXParserFactory factory = SAXParserFactory.newInstance();
 155  32032 factory.setNamespaceAware(false);
 156  32032 factory.setValidating(false);
 157   
 158  32032 factory.setFeature(NAMESPACES_FEATURE_ID, false);
 159  32032 factory.setFeature(VALIDATION_FEATURE_ID, false);
 160   
 161  32032 final SAXParser parser = factory.newSAXParser();
 162   
 163  32032 reader = parser.getXMLReader();
 164   
 165    // set parser features
 166  32032 reader.setFeature(NAMESPACES_FEATURE_ID, false);
 167  32032 reader.setFeature(VALIDATION_FEATURE_ID, false);
 168    }
 169   
 170    /**
 171    * Parses XML file.
 172    *
 173    * @param fileName Parse this input.
 174    * @param original Original file location.
 175    * @throws SAXException Syntactical or semantical problem occurred.
 176    * @throws IOException Technical problem occurred.
 177    */
 178  0 public final void parse(final String fileName, final URL original) throws SAXException,
 179    IOException {
 180  0 final File file = new File(fileName);
 181  0 parse(file, original);
 182    }
 183   
 184    /**
 185    * Parses XML file.
 186    *
 187    * @param file Parse this input.
 188    * @param original Original file location.
 189    * @throws SAXException Syntactical or semantical problem occurred.
 190    * @throws IOException Technical problem occurred.
 191    */
 192  32032 public final void parse(final File file, final URL original) throws SAXException, IOException {
 193  32032 xml = new TextInput(file);
 194  32032 this.original = original;
 195  32032 elements.clear();
 196  32032 level = 0;
 197  32032 try {
 198  32032 current = new SimpleXPath();
 199  32032 summary = new SimpleXPath();
 200  32032 reader.setContentHandler(this);
 201  32032 reader.parse(new InputSource(new FileReader(file)));
 202  32032 xml = null;
 203    } catch (SAXException e) {
 204  0 Trace.trace(CLASS, this, "parse", e);
 205  0 throw e;
 206    }
 207    }
 208   
 209    /*
 210    * (non-Javadoc)
 211    *
 212    * @see org.xml.sax.ContentHandler#endDocument()
 213    */
 214  32032 public void endDocument() throws SAXException {
 215  32032 elements.clear();
 216  32032 level = 0;
 217    }
 218   
 219    /*
 220    * (non-Javadoc)
 221    *
 222    * @see org.xml.sax.ContentHandler#startDocument()
 223    */
 224  32032 public void startDocument() throws SAXException {
 225  32032 elements.clear();
 226  32032 level = 0;
 227    }
 228   
 229    /*
 230    * (non-Javadoc)
 231    *
 232    * @see org.xml.sax.ContentHandler#characters(char[], int, int)
 233    */
 234  159212115 public void characters(final char[] ch, final int start, final int length) throws SAXException {
 235    }
 236   
 237    /*
 238    * (non-Javadoc)
 239    *
 240    * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
 241    */
 242  0 public void ignorableWhitespace(final char[] ch, final int start, final int length)
 243    throws SAXException {
 244    }
 245   
 246    /*
 247    * (non-Javadoc)
 248    *
 249    * @see org.xml.sax.ContentHandler#endPrefixMapping(java.lang.String)
 250    */
 251  0 public void endPrefixMapping(final String prefix) throws SAXException {
 252    }
 253   
 254    /*
 255    * (non-Javadoc)
 256    *
 257    * @see org.xml.sax.ContentHandler#skippedEntity(java.lang.String)
 258    */
 259  0 public void skippedEntity(final String name) throws SAXException {
 260    }
 261   
 262    /**
 263    * Receive a Locator object for document events. Store the locator for use with other document
 264    * events.
 265    *
 266    * @param locator A locator for all SAX document events.
 267    * @see org.xml.sax.ContentHandler#setDocumentLocator
 268    * @see org.xml.sax.Locator
 269    */
 270  32032 public final void setDocumentLocator(final Locator locator) {
 271  32032 this.locator = locator;
 272    }
 273   
 274    /*
 275    * (non-Javadoc)
 276    *
 277    * @see org.xml.sax.ContentHandler#processingInstruction(java.lang.String, java.lang.String)
 278    */
 279  0 public void processingInstruction(final String target, final String data) throws SAXException {
 280    }
 281   
 282    /*
 283    * (non-Javadoc)
 284    *
 285    * @see org.xml.sax.ContentHandler#startPrefixMapping(java.lang.String, java.lang.String)
 286    */
 287  0 public void startPrefixMapping(final String prefix, final String uri) throws SAXException {
 288    }
 289   
 290    /*
 291    * (non-Javadoc)
 292    *
 293    * @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String,
 294    * java.lang.String, org.xml.sax.Attributes)
 295    */
 296  67658866 public void startElement(final String namespaceURI, final String localName, final String qName,
 297    final Attributes atts) throws SAXException {
 298  67658866 final String method = "startElement(String, String, Attributes)";
 299  67658866 level++;
 300  67658866 summary.addElement("*", addOccurence("*"));
 301  67658866 current.addElement(qName, addOccurence(qName));
 302   
 303    // LATER mime 20070109: just for testing is the next if
 304    /*
 305    if (find.matchesElementsBegining(current, summary)) {
 306    System.out.println("part match " + qName);
 307    xml.setRow(locator.getLineNumber());
 308    xml.setColumn(locator.getColumnNumber());
 309    try {
 310    xml.skipBackToBeginOfXmlTag();
 311    } catch (RuntimeException e) {
 312    Trace.trace(this, method, e);
 313    }
 314    find.setStartLocation(new SourcePosition(xml.getLocalAddress(), xml.getRow(), xml
 315    .getColumn()));
 316    }
 317    */
 318  67658866 if (find.matchesElements(current, summary)) {
 319  32032 Trace.trace(CLASS, this, method, "matching elements");
 320  32032 Trace.param(CLASS, this, method, qName, current);
 321  32032 xml.setRow(locator.getLineNumber());
 322  32032 xml.setColumn(locator.getColumnNumber());
 323   
 324  32032 try {
 325  32032 xml.skipBackToBeginOfXmlTag();
 326    } catch (RuntimeException e) {
 327  0 Trace.trace(CLASS, this, method, e);
 328    }
 329  32032 find.setStartLocation(new SourcePosition(xml.getAddress(), xml.getRow(), xml
 330    .getColumn()));
 331  32032 if (find.getAttribute() != null) {
 332  3230 xml.read(); // skip <
 333  3230 xml.readNextXmlName(); // must be element name
 334  3230 String tag;
 335  3230 do {
 336  3510 xml.skipWhiteSpace();
 337  3510 int row = xml.getRow();
 338  3510 int col = xml.getColumn();
 339  3510 try {
 340  3510 tag = xml.readNextXmlName();
 341    } catch (IllegalArgumentException e) {
 342  0 break; // TODO mime 20050621: create named exception in readNextXmlName
 343    }
 344  3510 if (tag.equals(find.getAttribute())) {
 345  3230 find.setStartLocation(new SourcePosition(xml.getAddress(), row, col));
 346  3230 xml.readNextAttributeValue();
 347  3230 find.setEndLocation(new SourcePosition(xml.getAddress(), xml.getRow(),
 348    xml.getColumn()));
 349  3230 break;
 350    }
 351  280 xml.readNextAttributeValue();
 352    } while (true);
 353    }
 354    }
 355    }
 356   
 357    /**
 358    * Add element occurrence.
 359    *
 360    * @param name Element that occurred.
 361    * @return Number of occurrences including this one.
 362    */
 363  135317732 private int addOccurence(final String name) {
 364  135317732 while (level < elements.size()) {
 365  35013472 elements.remove(elements.size() - 1);
 366    }
 367  135317732 while (level > elements.size()) {
 368  35145840 elements.add(new HashMap());
 369    }
 370  135317732 final Map levelMap = (Map) elements.get(level - 1);
 371  135317732 final Enumerator counter;
 372  135317732 if (levelMap.containsKey(name)) {
 373  51396114 counter = (Enumerator) levelMap.get(name);
 374  51396114 counter.increaseNumber();
 375    } else {
 376  83921618 counter = new Enumerator(1);
 377  83921618 levelMap.put(name, counter);
 378    }
 379  135317732 return counter.getNumber();
 380    }
 381   
 382    /*
 383    * (non-Javadoc)
 384    *
 385    * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String,
 386    * java.lang.String)
 387    */
 388  67658866 public void endElement(final String namespaceURI, final String localName, final String qName)
 389    throws SAXException {
 390  67658866 level--;
 391  67658866 if (find.matchesElements(current, summary) && find.getAttribute() == null) {
 392  28802 xml.setRow(locator.getLineNumber());
 393  28802 xml.setColumn(locator.getColumnNumber());
 394    // xml.skipForwardToEndOfXmlTag(); // TODO mime 20050810: remove? comment in?
 395  28802 find.setEndLocation(new SourcePosition(original, xml.getRow(), xml
 396    .getColumn()));
 397    }
 398  67658866 current.deleteLastElement();
 399  67658866 summary.deleteLastElement();
 400    }
 401   
 402    /**
 403    * Get searched XPath. Hopefully the start and end location are set.
 404    *
 405    * @return Searched XPath.
 406    */
 407  32032 public SimpleXPath getFind() {
 408  32032 return find;
 409    }
 410   
 411    }