+import org.apache.log4j.Logger;
+import org.junit.Before;
+import org.xml.sax.Attributes;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+ * Created by wac26 on 29/04/2016.
+abstract class AbstractTemplateTest {
+ private SAXParser saxParser;
+ abstract List<String> getNamespaces();
+ abstract List<String> getIgnoredTags();
+ abstract List<String> getExtraTags();
+ public void spinUp() throws ParserConfigurationException, SAXException {
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+ saxParser = factory.newSAXParser();
+ int testFiles(String path) throws Exception {
+ return Files.walk(Paths.get(path))
+ .filter(Files::isRegularFile)
+ .filter(f -> f.getAbsolutePath().endsWith(".xhtml"))
+ .mapToInt(this::testFile)
+ private int testFile(File file) {
+ IdCheckingHandler handler = new IdCheckingHandler(getNamespaces(), getIgnoredTags(), getExtraTags());
+ saxParser.parse(file, handler);
+ } catch (SAXException | IOException e) {
+ throw new RuntimeException(e);
+ return handler.getCount();
+class IdCheckingHandler extends DefaultHandler {
+ private List<String> namespaces;
+ private List<String> ignoredTags;
+ private List<String> extraTags;
+ IdCheckingHandler(List<String> namespaces, List<String> ignoredTags, List<String> extraTags) {
+ this.namespaces = namespaces;
+ this.ignoredTags = ignoredTags;
+ this.extraTags = extraTags;
+ private Locator locator;
+ private static final Logger log = Logger.getLogger(AbstractTemplateTest.class);
+ public void setDocumentLocator(Locator locator) {
+ this.locator = locator;
+ public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
+ if (this.extraTags.contains(qName) || (!this.ignoredTags.contains(qName) && this.namespaces.stream().map(s -> s + ":").map(qName::startsWith).reduce(Boolean.FALSE, Boolean::logicalOr))) {
+ if (attributes.getValue("id") == null) {
+ log.warn("Element " + qName + " missing ID. " + locator.getSystemId().substring(locator.getSystemId().indexOf("./")) + ":" + locator.getLineNumber());