package coverage; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; public class XMLReader implements XMLCoverage { public XMLReader() { } public Coverage readFromFile(File file) throws ParserConfigurationException, TransformerException, IOException, SAXException, UnsupportedCoverageException { String fileName = file.getPath(); InputStream inputStream = null; inputStream = new FileInputStream(fileName); return readXML(inputStream); } public Coverage readXML(InputStream xmlContent) throws ParserConfigurationException, TransformerException, IOException, SAXException, UnsupportedCoverageException { Document doc = parse(xmlContent); return getCoverage(doc); } public Coverage readXML(String xmlContent) throws ParserConfigurationException, TransformerException, IOException, SAXException, UnsupportedCoverageException { Document doc = parse(xmlContent); return getCoverage(doc); } private Coverage getCoverage(Document doc) throws NumberFormatException, UnsupportedCoverageException { Coverage coverage = new Coverage(); for (Element rootNode : getElements(doc.getElementsByTagName(ROOT))) { coverage.setType(rootNode.getAttribute(TYPE)); coverage.setBaseValue(Integer.valueOf(rootNode.getAttribute(BASE))); break; } for (Element fileNode : getElements(doc.getElementsByTagName(FILE))) { getCoverage(coverage, fileNode); } return coverage; } private void getCoverage(Coverage coverage, Element fileNode) throws UnsupportedCoverageException { String fileName = fileNode.getAttribute(FILE_NAME); Element coverageNode = getElements(fileNode.getElementsByTagName(COVERAGE_KEY)).get(0); for (Element line : getElements(coverageNode.getElementsByTagName(COVERED_LINE))) { try { if (line.hasAttribute(THIS)) { coverage.setLineCovered(fileName, Integer.valueOf(line.getAttribute(THIS)), Integer.valueOf(line.getAttribute(INTERACTION)), line.getAttribute(TEXT)); } else { throwError("Unknown attribute " + line.getNodeName(), line); } } catch (Exception e) { throwError("Parse error occured " + e.getMessage(), line); } } } private Document parse(String input) throws IOException, SAXException, ParserConfigurationException { InputStream stream = new ByteArrayInputStream(input.getBytes(StandardCharsets.UTF_8)); return parse(stream); } private Document parse(InputStream stream) throws IOException, SAXException, ParserConfigurationException { Document doc = PositionalXMLReader.readXML(stream); doc.getDocumentElement().normalize(); return doc; } /** * @param nodeList * @return The child nodes from type Element of the given NodeList. */ private ArrayList<Element> getElements(NodeList nodeList) { ArrayList<Element> elements = new ArrayList<Element>(nodeList.getLength()); for (int temp = 0; temp < nodeList.getLength(); temp++) { org.w3c.dom.Node nNode = nodeList.item(temp); if (nNode.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) { Element eElement = (Element) nNode; elements.add(eElement); } } return elements; } /** * Throws an error that will be used for error markers * @param message The error message * @param tempNode The node that causes the error. this node is used for positioning. * @throws UnsupportedCoverageException * @throws NumberFormatException */ private void throwError(String message, org.w3c.dom.Node node) throws NumberFormatException, UnsupportedCoverageException { throw new UnsupportedCoverageException(message, Integer.parseInt (node.getUserData(PositionalXMLReader.LINE_NUMBER_KEY_NAME).toString())); } }