private Element addLinkpool(Element topic, boolean prepend, String linkpoolType, Document doc) { Element relatedLinks = DITAUtil.findChildByClass(topic, "topic/related-links"); if (relatedLinks == null) { relatedLinks = doc.createElementNS(null, "related-links"); relatedLinks.setAttributeNS(null, "class", "- topic/related-links "); topic.insertBefore(relatedLinks, DITAUtil.findChildByClass(topic, "topic/topic")); } Element linkpool = doc.createElementNS(null, "linkpool"); linkpool.setAttributeNS(null, "class", "- topic/linkpool "); if (mapHref != null && linkpoolType != null) { // mapkeyref is a standard DITA 1.2 attribute meant for this use. linkpool.setAttributeNS(null, "mapkeyref", mapHref + " type=" + linkpoolType); } Node before = null; if (prepend) { before = relatedLinks.getFirstChild(); } relatedLinks.insertBefore(linkpool, before); return linkpool; }
private void processColumn( Element reltable, int column, LoadedDocuments loadedDocs, List<Entry> entryList, List<Entry[]> cellList) { Node child = reltable.getFirstChild(); while (child != null) { if (child.getNodeType() == Node.ELEMENT_NODE) { Element childElement = (Element) child; if (DITAUtil.hasClass(childElement, "map/relrow")) { Element relcell = DOMUtil.getNthChildElement(childElement, column); if (relcell != null && DITAUtil.hasClass(relcell, "map/relcell")) { entryList.clear(); processCell(relcell, loadedDocs, entryList); Entry[] entries = new Entry[entryList.size()]; entryList.toArray(entries); cellList.add(entries); } } } child = child.getNextSibling(); } }
private void processHierarchy( Element topicrefOrMap, LoadedDocuments loadedDocs, List<Entry> childList) { CollectionType collectionType = null; String type = DITAUtil.getNonEmptyAttribute(topicrefOrMap, null, "collection-type"); if (type != null) { collectionType = CollectionType.fromString(type); } if (collectionType == null) { collectionType = CollectionType.UNORDERED; } processCollection(topicrefOrMap, collectionType, loadedDocs, childList); // Recurse --- // LIMITATION: @collection-type is ignored inside reltables. Node child = topicrefOrMap.getFirstChild(); while (child != null) { if (child.getNodeType() == Node.ELEMENT_NODE) { Element childElement = (Element) child; if (DITAUtil.hasClass(childElement, "map/topicref") && // Does not make sense inside frontmatter/backmatter. // For example, inside a glossary. !DITAUtil.hasClass(childElement, "bookmap/frontmatter", "bookmap/backmatter")) { processHierarchy(childElement, loadedDocs, childList); } } child = child.getNextSibling(); } }
private void processCell(Element relcell, LoadedDocuments loadedDocs, List<Entry> entryList) { Node child = relcell.getFirstChild(); while (child != null) { if (child.getNodeType() == Node.ELEMENT_NODE) { Element childElement = (Element) child; String href; if (DITAUtil.hasClass(childElement, "map/topicref") && (href = DITAUtil.getNonEmptyAttribute(childElement, null, "href")) != null) { Entry entry = createEntry(childElement, href, loadedDocs); if (entry != null) { entryList.add(entry); } } processCell(childElement, loadedDocs, entryList); } child = child.getNextSibling(); } }
private void processColumns( Element reltable, LoadedDocuments loadedDocs, Map<Element, Entry[]> collected) { Element relheader = DITAUtil.findChildByClass(reltable, "map/relheader"); if (relheader == null) { return; } int column = 0; ArrayList<Entry[]> cellList = new ArrayList<Entry[]>(); ArrayList<Entry> entryList = new ArrayList<Entry>(); Node child = relheader.getFirstChild(); while (child != null) { if (child.getNodeType() == Node.ELEMENT_NODE) { Element childElement = (Element) child; if (DITAUtil.hasClass(childElement, "map/relcolspec")) { cellList.clear(); entryList.clear(); processCell(childElement, loadedDocs, entryList); if (entryList.size() > 0) { Entry[] entries = new Entry[entryList.size()]; entryList.toArray(entries); cellList.add(entries); processColumn(reltable, column, loadedDocs, entryList, cellList); addColumn(cellList, collected); } // Otherwise the relcolspec does not contain topicrefs. ++column; } } child = child.getNextSibling(); } }
private void processRows( Element reltable, LoadedDocuments loadedDocs, Map<Element, Entry[]> collected) { ArrayList<Entry[]> cellList = new ArrayList<Entry[]>(); Node child = reltable.getFirstChild(); while (child != null) { if (child.getNodeType() == Node.ELEMENT_NODE) { Element childElement = (Element) child; if (DITAUtil.hasClass(childElement, "map/relrow")) { cellList.clear(); processRow(childElement, loadedDocs, cellList); addRow(cellList, collected); } } child = child.getNextSibling(); } }
private void processRow(Element relrow, LoadedDocuments loadedDocs, List<Entry[]> cellList) { ArrayList<Entry> entryList = new ArrayList<Entry>(); Node child = relrow.getFirstChild(); while (child != null) { if (child.getNodeType() == Node.ELEMENT_NODE) { Element childElement = (Element) child; if (DITAUtil.hasClass(childElement, "map/relcell")) { entryList.clear(); processCell(childElement, loadedDocs, entryList); Entry[] entries = new Entry[entryList.size()]; entryList.toArray(entries); cellList.add(entries); } } child = child.getNextSibling(); } }
public void processMap(Element map, URL mapURL, LoadedDocuments loadedDocs) { // Process @collection-type (but not inside reltables) --- mapHref = mapURL.toExternalForm(); ArrayList<Entry> childList = new ArrayList<Entry>(); processHierarchy(map, loadedDocs, childList); // Process reltables --- IdentityHashMap<Element, Entry[]> collected = new IdentityHashMap<Element, Entry[]>(); Node child = map.getFirstChild(); while (child != null) { if (child.getNodeType() == Node.ELEMENT_NODE) { Element childElement = (Element) child; if (DITAUtil.hasClass(childElement, "map/reltable")) { processColumns(childElement, loadedDocs, collected); processRows(childElement, loadedDocs, collected); } } child = child.getNextSibling(); } Iterator<Map.Entry<Element, Entry[]>> iter = collected.entrySet().iterator(); while (iter.hasNext()) { Map.Entry<Element, Entry[]> e = iter.next(); Element topic = e.getKey(); Entry[] entries = e.getValue(); addRelatedLinks(topic, entries); } }
private Entry createEntry(Element topicref, String href, LoadedDocuments loadedDocs) { // scope --- String scope = DITAUtil.getNonEmptyAttribute(topicref, null, "scope"); // format --- String format = DITAUtil.getFormat(topicref, href); if (format == null) { console.warning(topicref, Msg.msg("missingAttribute", "format")); return null; } // linking --- Linking linking = Linking.NORMAL; String value = DITAUtil.getNonEmptyAttribute(topicref, null, "linking"); if (value != null) { if ("none".equals(value)) { linking = Linking.NONE; } else if ("sourceonly".equals(value)) { linking = Linking.SOURCE_ONLY; } else if ("targetonly".equals(value)) { linking = Linking.TARGET_ONLY; } else if ("normal".equals(value)) { linking = Linking.NORMAL; } else { console.warning(topicref, Msg.msg("invalidAttribute", value, "linking")); linking = Linking.NONE; } } // linktext, shortdesc --- Element linktext = null; Element shortdesc = null; Element topicmeta = DITAUtil.findChildByClass(topicref, "map/topicmeta"); if (topicmeta != null) { // Notice "map/linktext" and not "topic/linktext". linktext = DITAUtil.findChildByClass(topicmeta, "map/linktext"); // Notice "map/shortdesc" and not "topic/shortdesc". shortdesc = DITAUtil.findChildByClass(topicmeta, "map/shortdesc"); } // topicId, elementId, topic --- String topicId = null; String elementId = null; Element topic = null; if ((scope == null || "local".equals(scope)) && "dita".equals(format)) { // Points to a local topic. URL url; try { url = URLUtil.createURL(href); } catch (MalformedURLException ignored) { console.warning(topicref, Msg.msg("invalidAttribute", href, "href")); return null; } String fragment = URLUtil.getFragment(url); url = URLUtil.setFragment(url, null); // LoadedDocuments.get() is sufficient in production. // We use load() here just to be able to run the test drive below. LoadedDocument loadedDoc = null; try { loadedDoc = loadedDocs.load(url); } catch (Exception shouldNotHappen) { } if (loadedDoc != null) { if (fragment != null) { int pos = fragment.indexOf('/'); if (pos > 0 && pos + 1 < fragment.length()) { topicId = fragment.substring(0, pos); elementId = fragment.substring(pos + 1); } else { topicId = fragment; } } LoadedTopic loadedTopic = null; if (topicId != null) { loadedTopic = loadedDoc.findTopicById(topicId); } else { loadedTopic = loadedDoc.getFirstTopic(); } if (loadedTopic != null) { if (loadedTopic.isExcluded()) { return null; } else { topicId = loadedTopic.topicId; topic = loadedTopic.element; // Normalize href --- StringBuilder buffer = new StringBuilder(url.toExternalForm()); buffer.append('#'); buffer.append(URIComponent.quoteFragment(topicId)); if (elementId != null) { buffer.append('/'); buffer.append(URIComponent.quoteFragment(elementId)); } href = buffer.toString(); } } else { console.warning(topicref, Msg.msg("pointsOutsidePreprocessedTopics", href)); return null; } } else { console.warning(topicref, Msg.msg("pointsOutsidePreprocessedTopics", href)); return null; } } else { // Points to an external resource. if (linking != Linking.NONE) { linking = Linking.TARGET_ONLY; } } return new Entry(href, scope, format, linking, linktext, shortdesc, topicId, elementId, topic); }
private void processCollection( Element topicrefOrMap, CollectionType collectionType, LoadedDocuments loadedDocs, List<Entry> childList) { Entry parent = null; String href = DITAUtil.getNonEmptyAttribute(topicrefOrMap, null, "href"); if (href != null) { parent = createEntry(topicrefOrMap, href, loadedDocs); if (parent != null && parent.topic == null) { parent = null; } } childList.clear(); Node child = topicrefOrMap.getFirstChild(); while (child != null) { if (child.getNodeType() == Node.ELEMENT_NODE) { Element childElement = (Element) child; if (DITAUtil.hasClass(childElement, "map/topicref") && (href = DITAUtil.getNonEmptyAttribute(childElement, null, "href")) != null) { Entry entry = createEntry(childElement, href, loadedDocs); if (entry != null && entry.topic == null) { entry = null; } if (entry != null) { childList.add(entry); } } } child = child.getNextSibling(); } int childCount = childList.size(); if (childCount > 0) { if (parent != null) { linkParentToChildren(parent, childList, childCount, collectionType); } switch (collectionType) { case FAMILY: { for (int i = 0; i < childCount; ++i) { Entry entry = childList.get(i); linkFamilyMembers(entry, parent, childList, childCount, i); } } break; case SEQUENCE: { Entry previous = null; for (int i = 0; i < childCount; ++i) { Entry entry = childList.get(i); Entry next = (i + 1 < childCount) ? childList.get(i + 1) : null; linkSequenceMembers(entry, parent, previous, next); previous = entry; } } break; default: { for (int i = 0; i < childCount; ++i) { Entry entry = childList.get(i); linkMembers(entry, parent, collectionType); } } } } }