Clover coverage report - QedeqKernelSe Coverage Report
Coverage timestamp: Do Mai 10 2007 03:16:40 CEST
file stats: LOC: 370   Methods: 17
NCLOC: 178   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
XPathLocationParser.java 93,8% 94,3% 70,6% 90,8%
coverage coverage
 1    /* $Id: XPathLocationParser.java,v 1.17 2007/05/10 00:37:49 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.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.common.SourcePosition;
 31    import org.qedeq.kernel.dto.list.Enumerator;
 32    import org.qedeq.kernel.trace.Trace;
 33    import org.qedeq.kernel.utility.TextInput;
 34    import org.qedeq.kernel.xml.parser.SaxEntityResolver;
 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.17 $
 46    * @author Michael Meyling
 47    */
 48    public 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  28962 public XPathLocationParser(final String xpath) throws ParserConfigurationException,
 91    SAXException {
 92  28962 super();
 93   
 94  28962 find = new SimpleXPath(xpath);
 95  28962 elements = new ArrayList(20);
 96  28962 level = 0;
 97   
 98  28962 final String factoryImpl = System.getProperty("javax.xml.parsers.SAXParserFactory");
 99  28962 if (factoryImpl == null) {
 100  0 System.setProperty("javax.xml.parsers.SAXParserFactory",
 101    "org.apache.xerces.jaxp.SAXParserFactoryImpl");
 102    }
 103  28962 SAXParserFactory factory = SAXParserFactory.newInstance();
 104  28962 factory.setNamespaceAware(false);
 105  28962 factory.setValidating(false);
 106   
 107  28962 factory.setFeature(NAMESPACES_FEATURE_ID, false);
 108  28962 factory.setFeature(VALIDATION_FEATURE_ID, false);
 109   
 110  28962 final SAXParser parser = factory.newSAXParser();
 111   
 112  28962 reader = parser.getXMLReader();
 113  28962 reader.setEntityResolver(new SaxEntityResolver());
 114   
 115    // set parser features
 116  28962 reader.setFeature(NAMESPACES_FEATURE_ID, false);
 117  28962 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  28962 public final void parse(final String fileName) throws SAXException, IOException {
 128  28962 final File file = new File(fileName);
 129  28962 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  28962 public final void parse(final File file) throws SAXException, IOException {
 140  28962 final TextInput source = new TextInput(file);
 141  28962 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  28962 public final void parse(final TextInput input) throws SAXException, IOException {
 152  28962 xml = input;
 153  28962 elements.clear();
 154  28962 level = 0;
 155  28962 try {
 156  28962 current = new SimpleXPath();
 157  28962 summary = new SimpleXPath();
 158  28962 reader.setContentHandler(this);
 159    // TODO mime 20060609: what if input has no local address (e.g. == null)?
 160  28962 reader.parse(new InputSource(input.getLocalAddress().openStream()));
 161  28962 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  28962 public void endDocument() throws SAXException {
 174  28962 elements.clear();
 175  28962 level = 0;
 176    }
 177   
 178    /*
 179    * (non-Javadoc)
 180    *
 181    * @see org.xml.sax.ContentHandler#startDocument()
 182    */
 183  28962 public void startDocument() throws SAXException {
 184  28962 elements.clear();
 185  28962 level = 0;
 186    }
 187   
 188    /*
 189    * (non-Javadoc)
 190    *
 191    * @see org.xml.sax.ContentHandler#characters(char[], int, int)
 192    */
 193  147775017 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  28962 public final void setDocumentLocator(final Locator locator) {
 230  28962 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  61912924 public void startElement(final String namespaceURI, final String localName, final String qName,
 256    final Attributes atts) throws SAXException {
 257  61912924 final String method = "startElement(String, String, Attributes)";
 258  61912924 level++;
 259  61912924 summary.addElement("*", addOccurence("*"));
 260  61912924 current.addElement(qName, addOccurence(qName));
 261   
 262    // LATER 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  61912924 if (find.matchesElements(current, summary)) {
 278  28962 Trace.trace(this, method, "matching elements");
 279  28962 Trace.param(this, method, qName, current);
 280  28962 xml.setRow(locator.getLineNumber());
 281  28962 xml.setColumn(locator.getColumnNumber());
 282   
 283  28962 try {
 284  28962 xml.skipBackToBeginOfXmlTag();
 285    } catch (RuntimeException e) {
 286  0 Trace.trace(this, method, e);
 287    }
 288  28962 find.setStartLocation(new SourcePosition(xml.getLocalAddress(), xml.getRow(), xml
 289    .getColumn()));
 290  28962 if (find.getAttribute() != null) {
 291  3166 xml.read(); // skip <
 292  3166 xml.readNextXmlName(); // must be element name
 293  3166 String tag;
 294  3166 do {
 295  3434 xml.skipWhiteSpace();
 296  3434 int row = xml.getRow();
 297  3434 int col = xml.getColumn();
 298  3434 try {
 299  3434 tag = xml.readNextXmlName();
 300    } catch (IllegalArgumentException e) {
 301  0 break; // TODO mime 20050621: create named exception in readNextXmlName
 302    }
 303  3434 if (tag.equals(find.getAttribute())) {
 304  3166 find.setStartLocation(new SourcePosition(xml.getLocalAddress(), row, col));
 305  3166 xml.readNextAttributeValue();
 306  3166 find.setEndLocation(new SourcePosition(xml.getLocalAddress(), xml.getRow(),
 307    xml.getColumn()));
 308  3166 break;
 309    }
 310  268 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  123825848 private int addOccurence(final String name) {
 323  123825848 while (level < elements.size()) {
 324  32186273 elements.remove(elements.size() - 1);
 325    }
 326  123825848 while (level > elements.size()) {
 327  32306324 elements.add(new HashMap());
 328    }
 329  123825848 final Map levelMap = (Map) elements.get(level - 1);
 330  123825848 final Enumerator counter;
 331  123825848 if (levelMap.containsKey(name)) {
 332  46857880 counter = (Enumerator) levelMap.get(name);
 333  46857880 counter.increaseNumber();
 334    } else {
 335  76967968 counter = new Enumerator(1);
 336  76967968 levelMap.put(name, counter);
 337    }
 338  123825848 return counter.getNumber();
 339    }
 340   
 341    /*
 342    * (non-Javadoc)
 343    *
 344    * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String,
 345    * java.lang.String)
 346    */
 347  61912924 public void endElement(final String namespaceURI, final String localName, final String qName)
 348    throws SAXException {
 349  61912924 level--;
 350  61912924 if (find.matchesElements(current, summary) && find.getAttribute() == null) {
 351  25796 xml.setRow(locator.getLineNumber());
 352  25796 xml.setColumn(locator.getColumnNumber());
 353    // xml.skipForwardToEndOfXmlTag(); // TODO mime 20050810: remove? comment in?
 354  25796 find.setEndLocation(new SourcePosition(xml.getLocalAddress(), xml.getRow(), xml
 355    .getColumn()));
 356    }
 357  61912924 current.deleteLastElement();
 358  61912924 summary.deleteLastElement();
 359    }
 360   
 361    /**
 362    * Get searched XPath. Possibly the start and end location are set.
 363    *
 364    * @return Searched XPath.
 365    */
 366  28962 public SimpleXPath getFind() {
 367  28962 return find;
 368    }
 369   
 370    }