1   package nl.dedicon.pipeline.braille.step;
2   
3   import java.util.HashMap;
4   import java.util.Map;
5   import java.util.function.UnaryOperator;
6   import org.w3c.dom.Document;
7   import org.w3c.dom.Element;
8   import org.w3c.dom.Node;
9   import org.w3c.dom.NodeList;
10  
11  /**
12   * Move notes right after the parent node of their corresponding noteref
13   * 
14   * @author Paul Rambags
15   */
16  public class NotesMover {
17      
18      private static final String NOTE = "note";
19      private static final String NOTEREF = "noteref";
20      private static final String ID = "id";
21      private static final String IDREF = "idref";
22      
23      private final Map<String, Element> notes = new HashMap<>();      // id -> Element(note)
24      private final Map<String, Element> noterefs = new HashMap<>();   // idref -> Element(noteref)
25      
26      public void collectNotesAndNoterefs(Document document) {
27          collect(document, notes, NOTE, ID, s -> s);
28          collect(document, noterefs, NOTEREF, IDREF, s -> s.replaceFirst("^#", ""));
29      }
30  
31      private static void collect(Document document, Map map, String nodeName, String attributeName, UnaryOperator<String> attributeFormatter) {
32          String namespace = document.getDocumentElement().getNamespaceURI();
33          NodeList nodeList = document.getElementsByTagNameNS(namespace, nodeName);
34          for (int i = 0; i < nodeList.getLength(); ++i) {
35              Element element = (Element)nodeList.item(i);
36              String attributeValue = element.getAttribute(attributeName);
37              if (attributeValue != null && attributeValue.length() > 0) {
38                  map.put(attributeFormatter.apply(attributeValue), element);
39              }
40          }
41      }
42      
43      public void moveNotes() {
44          notes.entrySet().stream().forEach(e -> {
45              String id = e.getKey();
46              Element note = e.getValue();
47  
48              Element noteref = noterefs.get(id);
49              if (noteref == null) {
50                  // note without noteref
51                  return;
52              }
53              Node parent = noteref.getParentNode();
54              if (parent == null) {
55                  return;
56              }
57              Node grandParent = parent.getParentNode();
58              if (grandParent == null) {
59                  return;
60              }
61              
62              grandParent.insertBefore(note, parent.getNextSibling());
63          });    
64      }
65  }