The sample validation hook used in this tutorial:
checks that the src
attribute of the img
element is not an absolute file path;
checks that the value of the name
attribute of a a
element is not already in use;
checks that for each href
attribute of a a
element starting with '#
' (local reference), there is an element with such name
or id
.
This sample validation hook just needs to implement the documentChecked
method, therefore it extends adapter class ValidateHookBase
rather than implement the above interface.
Excerpts from CheckLinks.java
:
public class CheckLinks extends ValidateHookBase { private static final Name SRC = Name.get("src"); private static final Name NAME = Name.get("name"); private static final Name ID = Name.get("id"); private static final Name HREF = Name.get("href"); @Override public Diagnostic[] documentChecked(Document doc, boolean canceled, Diagnostic[] diagnostics) { if (canceled) {return diagnostics; } final ArrayList<DiagnosticImpl> warnings = new ArrayList<DiagnosticImpl>(); final ArrayList<Element> links = new ArrayList<Element>(); final HashMap<String,List<Element>> anchors = new HashMap<String,List<Element>>(); Traversal.traverse(doc.getRootElement(), new Traversal.HandlerBase() {
public Object enterElement(Element element) { String localName = element.getLocalName(); String anchorName = null; if ("img".equals(localName)) {
String src = element.getAttribute(SRC); if (src != null) { if (src.startsWith("file:/") || src.startsWith("/") || src.startsWith("\\\\") || (src.length() >= 3 && Character.isLetter(src.charAt(0)) && src.regionMatches(1, ":\\", 0, 2))) { warnings.add(new DiagnosticImpl( element, "src attribute looks like an absolute file path", Diagnostic.Severity.SEMANTIC_WARNING)); } } } else if ("a".equals(localName)) { String href = element.getAttribute(HREF); if (href != null) { if (href.startsWith("#")) {
links.add(element); } } else { anchorName = element.getAttribute(NAME);
if (anchorName != null) { List<Element> elements = anchors.get(anchorName); if (elements == null) { elements = new ArrayList<Element>(); anchors.put(anchorName, elements); } elements.add(element); } } } String id = element.getAttribute(ID);
if (id != null && !id.equals(anchorName)) { List<Element> elements = anchors.get(id); if (elements == null) { elements = new ArrayList<Element>(); anchors.put(id, elements); } elements.add(element); } return null; } }); int count = links.size(); for (int i = 0; i < count; ++i) {
Element element = links.get(i); String id = element.getAttribute(HREF).substring(1); if (!anchors.containsKey(id)) { warnings.add(new DiagnosticImpl( element, "reference to non-existent name or id '" + id + "'", Diagnostic.Severity.SEMANTIC_WARNING)); } } Iterator<Map.Entry<String,List<Element>>> iter = anchors.entrySet().iterator();
while (iter.hasNext()) { Map.Entry<String,List<Element>> entry = iter.next(); String id = entry.getKey(); List<Element> elements = entry.getValue(); count = elements.size(); for (int i = 1; i < count; ++i) { warnings.add(new DiagnosticImpl( elements.get(i), "name or id '" + id + "' already defined", Diagnostic.Severity.SEMANTIC_WARNING)); } } int warningCount = warnings.size();
if (warningCount > 0) { int diagnosticCount = diagnostics.length; Diagnostic[] diagnostics2 = new Diagnostic[diagnosticCount + warningCount]; System.arraycopy(diagnostics, 0, diagnostics2, 0, diagnosticCount); for (int i = 0; i < warningCount; ++i) { diagnostics2[diagnosticCount+i] = warnings.get(i); } diagnostics = diagnostics2; } return diagnostics; } }
If the | |
| |
If the value of the | |
Elements | |
Elements | |
Elements having an Note that a | |
Elements contained in | |
Elements contained in | |
If semantic warnings have been found for the document, they are added to the list of |