Coverage Report - net.sf.jmatchparser.template.Parser
 
Classes in this File Line Coverage Branch Coverage Complexity
Parser
69%
46/66
75%
3/4
1,083
 
 1  
 /*
 2  
  * Copyright (c) 2006 - 2011 Michael Schierl
 3  
  * All rights reserved.
 4  
  * 
 5  
  * This program is free software: you can redistribute it and/or modify
 6  
  * it under the terms of the GNU General Public License as published by
 7  
  * the Free Software Foundation, either version 2 of the License, or
 8  
  * (at your option) any later version.
 9  
  * 
 10  
  * This program is distributed in the hope that it will be useful,
 11  
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 13  
  * GNU General Public License for more details.
 14  
  * 
 15  
  * You should have received a copy of the GNU General Public License
 16  
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 17  
  */
 18  
 package net.sf.jmatchparser.template;
 19  
 
 20  
 import java.io.BufferedReader;
 21  
 import java.io.File;
 22  
 import java.io.IOException;
 23  
 import java.io.InputStream;
 24  
 import java.io.InputStreamReader;
 25  
 import java.io.PrintStream;
 26  
 import java.io.StringWriter;
 27  
 
 28  
 import javax.xml.bind.JAXBException;
 29  
 import javax.xml.bind.Unmarshaller;
 30  
 import javax.xml.bind.annotation.XmlRootElement;
 31  
 import javax.xml.parsers.DocumentBuilderFactory;
 32  
 import javax.xml.parsers.ParserConfigurationException;
 33  
 
 34  
 import net.sf.jmatchparser.template.engine.ParserImpl;
 35  
 import net.sf.jmatchparser.util.StreamForwarder;
 36  
 import net.sf.jmatchparser.util.csv.AbstractCSVWriter;
 37  
 import net.sf.jmatchparser.util.csv.XMLCSVReader;
 38  
 
 39  
 import org.w3c.dom.Document;
 40  
 import org.w3c.dom.Element;
 41  
 
 42  
 /**
 43  
  * A parser for {@link MatchTemplate}s. Each parser can be used for parsing
 44  
  * exactly one file/input stream; the templates can be reused for parsing more
 45  
  * than one file.
 46  
  */
 47  
 public class Parser {
 48  
 
 49  
         private final ParserImpl impl;
 50  
 
 51  
         /**
 52  
          * Create a new parser using a new {@link MatchTemplate}.
 53  
          * 
 54  
          * @param filename
 55  
          *            Name of the file
 56  
          * @param encoding
 57  
          *            File encoding
 58  
          * @see MatchTemplate#MatchTemplate(String, String, Formatter...)
 59  
          */
 60  
         public Parser(String filename, String encoding) throws IOException {
 61  1
                 this(new MatchTemplate(filename, encoding));
 62  1
         }
 63  
 
 64  
         /**
 65  
          * Create a new parser using a new {@link MatchTemplate}.
 66  
          * 
 67  
          * @param file
 68  
          *            The file
 69  
          * @param encoding
 70  
          *            File encoding
 71  
          * @see MatchTemplate#MatchTemplate(File, String, Formatter...)
 72  
          */
 73  
         public Parser(File file, String encoding) throws IOException {
 74  0
                 this(new MatchTemplate(file, encoding));
 75  0
         }
 76  
 
 77  
         /**
 78  
          * Create a new parser using a new {@link MatchTemplate}.
 79  
          * 
 80  
          * @param clazz
 81  
          *            Class to use as a base for finding the resource
 82  
          * @param resourceName
 83  
          *            Name of the resource
 84  
          * @param encoding
 85  
          *            File encoding
 86  
          * @see MatchTemplate#MatchTemplate(Class, String, String, Formatter...)
 87  
          */
 88  
         public Parser(Class<?> clazz, String resourceName, String encoding) throws IOException {
 89  1
                 this(new MatchTemplate(clazz, resourceName, encoding));
 90  0
         }
 91  
 
 92  
         /**
 93  
          * Create a new parser using a new {@link MatchTemplate}.
 94  
          * 
 95  
          * @param resolver
 96  
          *            Match template resolver for resolving additional template
 97  
          *            names ($INCLUDE), optional
 98  
          * @param templateName
 99  
          *            Name of the template
 100  
          * @param br
 101  
          *            Reader to read the template from
 102  
          * 
 103  
          * @see MatchTemplate#MatchTemplate(MatchTemplate.MatchTemplateResolver,
 104  
          *      String, BufferedReader, Formatter...)
 105  
          */
 106  
         public Parser(MatchTemplate.MatchTemplateResolver resolver, String templateName, BufferedReader br) throws IOException {
 107  1
                 this(new MatchTemplate(resolver, templateName, br));
 108  1
         }
 109  
 
 110  
         /**
 111  
          * Create a new parser using an existing {@link MatchTemplate}.
 112  
          * 
 113  
          * @param template
 114  
          *            The match template to use
 115  
          */
 116  
         public Parser(MatchTemplate template) {
 117  114
                 this(new ParserImpl(template.getImpl()));
 118  114
         }
 119  
 
 120  188
         private Parser(ParserImpl impl) {
 121  188
                 this.impl = impl;
 122  188
         }
 123  
 
 124  
         /**
 125  
          * Set a local variable in this parser. This method can only be called
 126  
          * before parsing started.
 127  
          * 
 128  
          * @param name
 129  
          *            Name of the variable
 130  
          * @param value
 131  
          *            Value of the variable
 132  
          */
 133  
         public void setLocal(String name, String value) {
 134  1
                 impl.setLocal(name, value);
 135  1
         }
 136  
 
 137  
         /**
 138  
          * Set the name of this parser. This name is used in error messages and can
 139  
          * be used to distinguish multiple parsers easily.
 140  
          */
 141  
         public void setParserName(String parserName) {
 142  1
                 impl.setParserName(parserName);
 143  1
         }
 144  
 
 145  
         /**
 146  
          * Parse an input stream using a JAXB {@link Unmarshaller} for parsing the
 147  
          * resulting XML.
 148  
          * 
 149  
          * @param <T>
 150  
          *            Type of the unmarshalled object
 151  
          * @param stream
 152  
          *            Input stream to parse
 153  
          * @param encoding
 154  
          *            Encoding of the stream
 155  
          * @param unmarshaller
 156  
          *            {@link Unmarshaller} to use
 157  
          * @param clazz
 158  
          *            Class of the unmarshalled object
 159  
          * @return Unmarshalled object
 160  
          */
 161  
         public <T> T parse(InputStream stream, String encoding, Unmarshaller unmarshaller, Class<T> clazz) throws ParserException, ParserConfigurationException, IOException, JAXBException {
 162  0
                 String name = clazz.getAnnotation(XmlRootElement.class).name();
 163  0
                 Document doc = parse(stream, encoding, name);
 164  0
                 return unmarshaller.unmarshal(doc.getDocumentElement(), clazz).getValue();
 165  
         }
 166  
 
 167  
         /**
 168  
          * Parse an input stream and create a new DOM {@link Document} from the
 169  
          * resulting XML.
 170  
          * 
 171  
          * @param stream
 172  
          *            Input stream to parse
 173  
          * @param encoding
 174  
          *            Encoding of the stream
 175  
          * @param toplevelTag
 176  
          *            Tag of the document element to use in the new document
 177  
          * @return {@link Document}
 178  
          */
 179  
         public Document parse(InputStream stream, String encoding, String toplevelTag) throws ParserException, ParserConfigurationException, IOException {
 180  1
                 BufferedReader br = new BufferedReader(new InputStreamReader(stream, encoding));
 181  1
                 return parse(br, toplevelTag);
 182  
         }
 183  
 
 184  
         /**
 185  
          * Parse an input stream and add the resulting XML to a DOM {@link Element}.
 186  
          * 
 187  
          * @param stream
 188  
          *            Input stream to parse
 189  
          * @param encoding
 190  
          *            Encoding of the stream
 191  
          * @param target
 192  
          *            Element to add the XML to
 193  
          */
 194  
         public void parse(InputStream stream, String encoding, Element target) throws ParserException, IOException {
 195  0
                 BufferedReader br = new BufferedReader(new InputStreamReader(stream, encoding));
 196  0
                 parse(br, target);
 197  0
         }
 198  
 
 199  
         /**
 200  
          * Parse a buffered reader using a JAXB {@link Unmarshaller} for parsing the
 201  
          * resulting XML.
 202  
          * 
 203  
          * @param <T>
 204  
          *            Type of the unmarshalled object
 205  
          * @param reader
 206  
          *            {@link BufferedReader} to parse
 207  
          * @param unmarshaller
 208  
          *            {@link Unmarshaller} to use
 209  
          * @param clazz
 210  
          *            Class of the unmarshalled object
 211  
          * @return Unmarshalled object
 212  
          */
 213  
         public <T> T parse(BufferedReader reader, Unmarshaller unmarshaller, Class<T> clazz) throws ParserException, ParserConfigurationException, IOException, JAXBException {
 214  0
                 String name = clazz.getAnnotation(XmlRootElement.class).name();
 215  0
                 Document doc = parse(reader, name);
 216  0
                 return unmarshaller.unmarshal(doc.getDocumentElement(), clazz).getValue();
 217  
         }
 218  
 
 219  
         /**
 220  
          * Parse a buffered reader and create a new DOM {@link Document} from the
 221  
          * resulting XML.
 222  
          * 
 223  
          * @param reader
 224  
          *            {@link BufferedReader} to parse
 225  
          * @param toplevelTag
 226  
          *            Tag of the document element to use in the new document
 227  
          * @return {@link Document}
 228  
          */
 229  
         public Document parse(BufferedReader reader, String toplevelTag) throws ParserException, ParserConfigurationException, IOException {
 230  2
                 Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
 231  2
                 doc.appendChild(doc.createElement(toplevelTag));
 232  2
                 parse(reader, doc.getDocumentElement());
 233  2
                 return doc;
 234  
         }
 235  
 
 236  
         /**
 237  
          * Parse a buffered reader and add the resulting XML to a DOM
 238  
          * {@link Element}.
 239  
          * 
 240  
          * @param reader
 241  
          *            {@link BufferedReader} to parse
 242  
          * @param target
 243  
          *            Element to add the XML to
 244  
          */
 245  
         public void parse(BufferedReader reader, Element target) throws ParserException, IOException {
 246  2
                 StringWriter sw = new StringWriter();
 247  2
                 StreamForwarder.forward(reader, sw);
 248  2
                 String file = sw.toString().replace("\r\n", "\n").replace('\r', '\n');
 249  2
                 if (!file.endsWith("\n"))
 250  0
                         file += "\n";
 251  2
                 parse(file, target);
 252  2
         }
 253  
 
 254  
         /**
 255  
          * Parse a {@link String} or other char sequence using a JAXB
 256  
          * {@link Unmarshaller} for parsing the resulting XML.
 257  
          * 
 258  
          * @param <T>
 259  
          *            Type of the unmarshalled object
 260  
          * @param file
 261  
          *            {@link CharSequence} to parse
 262  
          * @param unmarshaller
 263  
          *            {@link Unmarshaller} to use
 264  
          * @param clazz
 265  
          *            Class of the unmarshalled object
 266  
          * @return Unmarshalled object
 267  
          */
 268  
         public <T> T parse(CharSequence file, Unmarshaller unmarshaller, Class<T> clazz) throws ParserException, ParserConfigurationException, IOException, JAXBException {
 269  0
                 String name = clazz.getAnnotation(XmlRootElement.class).name();
 270  0
                 Document doc = parse(file, name);
 271  0
                 return unmarshaller.unmarshal(doc.getDocumentElement(), clazz).getValue();
 272  
         }
 273  
 
 274  
         /**
 275  
          * Parse a {@link String} or other char sequence and create a new DOM
 276  
          * {@link Document} from the resulting XML.
 277  
          * 
 278  
          * @param file
 279  
          *            {@link CharSequence} to parse
 280  
          * @param toplevelTag
 281  
          *            Tag of the document element to use in the new document
 282  
          * @return {@link Document}
 283  
          */
 284  
         public Document parse(CharSequence file, String toplevelTag) throws ParserException, ParserConfigurationException, IOException {
 285  186
                 Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
 286  186
                 doc.appendChild(doc.createElement(toplevelTag));
 287  186
                 parse(file, doc.getDocumentElement());
 288  162
                 return doc;
 289  
         }
 290  
 
 291  
         /**
 292  
          * Parse a {@link String} or other char sequence and add the resulting XML
 293  
          * to a DOM {@link Element}.
 294  
          * 
 295  
          * @param file
 296  
          *            {@link CharSequence} to parse
 297  
          * @param target
 298  
          *            Element to add the XML to
 299  
          */
 300  
         public void parse(CharSequence file, Element target) throws ParserException, IOException {
 301  188
                 impl.parse(file, target);
 302  164
         }
 303  
 
 304  
         /**
 305  
          * Parse an input stream to a CSV file.
 306  
          * 
 307  
          * @param stream
 308  
          *            Input stream to parse
 309  
          * @param encoding
 310  
          *            Encoding of the stream
 311  
          * @param writer
 312  
          *            {@link AbstractCSVWriter} to write the file to
 313  
          */
 314  
         public void parseToCSV(InputStream stream, String encoding, AbstractCSVWriter writer) throws ParserConfigurationException, ParserException, IOException {
 315  0
                 convertDOMToCSV(parse(stream, encoding, "csv"), writer);
 316  0
         }
 317  
 
 318  
         /**
 319  
          * Parse a buffered reader to a CSV file.
 320  
          * 
 321  
          * @param reader
 322  
          *            {@link BufferedReader} to parse
 323  
          * @param writer
 324  
          *            {@link AbstractCSVWriter} to write the file to
 325  
          */
 326  
         public void parseToCSV(BufferedReader reader, AbstractCSVWriter writer) throws ParserConfigurationException, ParserException, IOException {
 327  0
                 convertDOMToCSV(parse(reader, "csv"), writer);
 328  0
         }
 329  
 
 330  
         /**
 331  
          * Parse a {@link String} or other char sequence to a CSV file.
 332  
          * 
 333  
          * @param file
 334  
          *            {@link CharSequence} to parse
 335  
          * @param writer
 336  
          *            {@link AbstractCSVWriter} to write the file to
 337  
          */
 338  
 
 339  
         public void parseToCSV(CharSequence file, AbstractCSVWriter writer) throws ParserConfigurationException, ParserException, IOException {
 340  1
                 convertDOMToCSV(parse(file, "csv"), writer);
 341  1
         }
 342  
 
 343  
         private static void convertDOMToCSV(Document doc, AbstractCSVWriter writer) throws IOException {
 344  1
                 convertDOMToCSV(doc, new AbstractCSVWriter[] { writer });
 345  1
         }
 346  
 
 347  
         /**
 348  
          * Convert a DOM {@link Document} to one or more CSV files. Each child
 349  
          * element of the document element is a row, each child element of a row is
 350  
          * a cell. Rows may have an attribute <code>@file</code> which contains the
 351  
          * zero-based index of the writer to save this row to (zero by default); all
 352  
          * other attributes are ignored.
 353  
          * 
 354  
          * @param doc
 355  
          *            {@link Document} to parse
 356  
          * @param writers
 357  
          *            {@link AbstractCSVWriter}(s) to write the file(s) to
 358  
          */
 359  
         public static void convertDOMToCSV(Document doc, AbstractCSVWriter[] writers) throws IOException {
 360  2
                 XMLCSVReader r = new XMLCSVReader(doc);
 361  
                 String[] record;
 362  2
                 int[] fileIndex = new int[1];
 363  6
                 while ((record = r.read(fileIndex)) != null) {
 364  4
                         writers[fileIndex[0]].write(record);
 365  4
                         fileIndex[0] = 0;
 366  
                 }
 367  2
         }
 368  
 
 369  
         /**
 370  
          * Add a callback function to this parser.
 371  
          * 
 372  
          * @param name
 373  
          *            Name of the function
 374  
          * @param function
 375  
          *            Function to add
 376  
          */
 377  
         public void addCallback(String name, CallbackFunction function) {
 378  1
                 impl.addCallback(name, function);
 379  1
         }
 380  
 
 381  
         /**
 382  
          * Set the debug stream where <code>DEBUGWRITE</code> and
 383  
          * <code>DUMPLINE</code> commands write to.
 384  
          * 
 385  
          * @param debugStream
 386  
          *            New debug stream to use
 387  
          */
 388  
         public void setDebugStream(PrintStream debugStream) {
 389  1
                 impl.setDebugStream(debugStream);
 390  1
         }
 391  
 }