### Question:
HtmlTidy implements NodeListProcessor, ExportingNodeListProcessor { @Override public NodeList process(NodeList nodes) throws InvalidMarkupException, IOException { for (Node n : nodes.filterRecursive(new ElementFilter()).list()) { if (!n.matches("table|tr|td|th|a|img|br|p|span|div")) { provider.getNamedStream("tidy_invalid_elements").append(n.toXmlString(true)).append("\n"); } List<Map.Entry<String, String>> attrs = new ArrayList<Map.Entry<String, String>>(); for (Map.Entry<String,String> e : n.getAttributes().entrySet()) { attrs.add(new java.util.AbstractMap.SimpleEntry<String, String>(e)); } for (Map.Entry<String, String> pair : attrs) { if (!validAttributes.contains(pair.getKey()) && !invalidAttributes.contains(pair.getKey())) { provider.getNamedStream("tidy_invalid_attributes").append("\n").append(pair.getKey()).append("\n").append(n.toXmlString(true)).append("\n"); invalidAttributes.add(pair.getKey()); } } for (Map.Entry<String, String> pair : attrs) { if (!validAttributes.contains(pair.getKey())) { n.removeAttr(pair.getKey()).set("data-" + pair.getKey(), pair.getValue()); } } } return nodes; }  @Override NodeList process(NodeList nodes); @Override void setFileNode(FileNode fn); @Override void setLogProvider(LogStreamProvider provider); @Override void setExportLocations(ExportLocations el);  }### Answer:
@Test public void TestInvalidAttributesAreRenamed() throws IOException, InvalidMarkupException { XmlRecord record = new XmlRecord("<div folioId=\"1\" groups=\"2017,public\" id=\"r1\" level=\"Year\" uri=\"2017#ar1\">"); htmlTidy.process(new NodeList(singletonList(record))); assertEquals("<div data-folioId=\"1\" data-groups=\"2017,public\" data-level=\"Year\" data-uri=\"2017#ar1\" id=\"r1\"></div>", record.toXmlString(false)); }