package de.ito.gradle.plugin.androidstringextractor.internal; import java.util.ArrayList; import java.util.List; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; class LayoutParser { private boolean ignoreMissingId = true; void setIgnoreMissingId(boolean ignoreMissingId) { this.ignoreMissingId = ignoreMissingId; } List<StringOccurrence> parse(Document document) { List<StringOccurrence> stringOccurrences = new ArrayList<>(); processNodes(stringOccurrences, document.getChildNodes()); return stringOccurrences; } private void processNodes(List<StringOccurrence> stringOccurrences, NodeList nodes) throws IllegalStateException { for (int i = 0; i < nodes.getLength(); i++) { processNode(stringOccurrences, nodes.item(i)); } } private void processNode(List<StringOccurrence> stringOccurrences, Node node) { if (node.hasChildNodes()) processNodes(stringOccurrences, node.getChildNodes()); if (!node.hasAttributes()) return; NamedNodeMap attributes = node.getAttributes(); Node idAttribute = attributes.getNamedItem("android:id"); Node textAttribute = attributes.getNamedItem("android:text"); Node hintAttribute = attributes.getNamedItem("android:hint"); if (!ignoreMissingId) validateNode(idAttribute, textAttribute, hintAttribute); if (idAttribute == null || (textAttribute == null && hintAttribute == null)) return; String id = stripIdPrefix(idAttribute.getNodeValue()); if (textAttribute != null) { if (!isDataBinding(textAttribute.getNodeValue())) { stringOccurrences.add( new StringOccurrence(id, "text", textAttribute.getNodeValue())); } } if (hintAttribute != null) { if (!isDataBinding(hintAttribute.getNodeValue())) { stringOccurrences.add( new StringOccurrence(id, "hint", hintAttribute.getNodeValue())); } } } private void validateNode(Node idAttribute, Node textAttribute, Node hintAttribute) { if (idAttribute == null || idAttribute.getNodeValue() == null) { if (textAttribute != null) { throw new IllegalStateException( String.format("No id specified for %s", textAttribute.getNodeValue())); } else { throw new IllegalStateException( String.format("No id specified for %s", hintAttribute.getNodeValue())); } } } private String stripIdPrefix(String id) { if (id.startsWith("@+id/")) return id.substring(5); return id; } private boolean isDataBinding(String value) { boolean oneWayDataBinding = value.startsWith("@{"); boolean twoWayDataBinding = value.startsWith("@={"); return oneWayDataBinding || twoWayDataBinding; } }