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