| /** |
| ******************************************************************************** |
| * Copyright (c) 2018-2022 Robert Bosch GmbH and others. |
| * |
| * This program and the accompanying materials are made |
| * available under the terms of the Eclipse Public License 2.0 |
| * which is available at https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Robert Bosch GmbH - initial API and implementation |
| ******************************************************************************** |
| */ |
| |
| package org.eclipse.app4mc.help.modifier; |
| |
| import java.io.BufferedReader; |
| import java.io.BufferedWriter; |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.InputStreamReader; |
| import java.io.OutputStreamWriter; |
| import java.io.PrintStream; |
| import java.nio.charset.StandardCharsets; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Scanner; |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| |
| import org.eclipse.app4mc.help.modifier.util.Heading; |
| import org.eclipse.app4mc.help.modifier.util.HeadingIterator; |
| |
| public class APP4MC_Help_Step_1_UpdateTOC { |
| |
| public static void main(final String[] args) { |
| |
| String inputFilePath = ""; |
| |
| try (Scanner scanner = new Scanner(System.in)) { |
| System.out.println("Provide the location of input HTML file :"); |
| inputFilePath = scanner.nextLine(); // ".../help/advanced/printc223.html"; |
| } |
| |
| execute(inputFilePath); |
| |
| } |
| |
| |
| public static File execute(final String inputFilePath) { |
| final File inputFile = new File(inputFilePath); |
| |
| if (inputFile.exists() == false) { |
| System.err.println("provide a valid input HTML location"); |
| System.exit(-1); |
| } |
| |
| System.out.println("Reading input file : " + inputFilePath); |
| |
| |
| final List<Heading> toc = new ArrayList<Heading>(); |
| final StringBuffer sb = new StringBuffer(); |
| |
| try (BufferedReader br = new BufferedReader( |
| new InputStreamReader(new FileInputStream(inputFile), StandardCharsets.UTF_8))) { |
| |
| boolean isInToc = false; |
| boolean isAfterToc = false; |
| int tocLevel = 0; |
| |
| final HeadingIterator headings = new HeadingIterator(toc); |
| |
| while (br.ready()) { |
| |
| final String readLine = br.readLine(); |
| |
| /*- |
| * ======================================================================= |
| * STEP 1 : Copy lines before table of contents |
| * ====================================================================== |
| */ |
| |
| if (readLine.trim().startsWith("<div id=\"toc_content\">")) { |
| isInToc = true; |
| |
| appendln(sb, readLine); |
| continue; |
| } |
| |
| if (!(isInToc || isAfterToc)) { |
| appendln(sb, readLine); |
| continue; |
| } |
| |
| /*- |
| * ======================================================================= |
| * STEP 2 : Extract table of contents |
| * ====================================================================== |
| */ |
| |
| if (isInToc) { |
| |
| if (readLine.startsWith("<div class=\"toc_")) { // entry or sub_entry |
| tocLevel++; |
| |
| } |
| else if (readLine.contains("<a href=\"#")) { |
| final Heading entry = new Heading(); |
| entry.level = tocLevel; |
| entry.number = readLine.substring(0, readLine.indexOf(". ")); |
| entry.text = readLine.substring(readLine.indexOf("\">")+2, readLine.indexOf("</a>")); |
| toc.add(entry); |
| |
| } |
| else if (readLine.startsWith("</div>")) { |
| tocLevel--; |
| if(tocLevel < 0) { |
| isInToc = false; |
| isAfterToc = true; |
| } |
| } |
| |
| appendln(sb, readLine); |
| continue; |
| } |
| |
| /*- |
| * ======================================================================= |
| * STEP 3 : Modify headings |
| * ====================================================================== |
| */ |
| |
| if (isAfterToc) { |
| |
| if (readLine.matches(".*<h\\d.*")) { |
| // heading line found |
| while (!readLine.replaceAll("\\W", "") |
| .contains(headings.current().text.replaceAll("\\W", ""))) { |
| // *** insert missing heading |
| |
| // System.out.println("found: >" + readLine + "<"); |
| // System.out.println("inserted: >" + headings.current() + "<"); |
| appendlnHeading(sb, headings.current()); |
| headings.next(); |
| } |
| // *** modify existing heading |
| |
| // include user defined id but ignore generic ones |
| String hID = extractHeadingId(readLine); |
| if (! hID.contains("-")) hID = null; |
| |
| appendlnHeading(sb, headings.current(), hID); |
| headings.next(); |
| |
| // debug info: original line |
| // appendln(sb, "<!-- " + readLine.trim() + " -->"); |
| } |
| else { |
| // other lines |
| appendln(sb, readLine); |
| } |
| continue; |
| } |
| |
| } |
| |
| } |
| catch (final Exception e) { |
| |
| e.printStackTrace(); |
| System.err.println("Error reading HTML file : " + inputFilePath); |
| } |
| |
| |
| |
| /*- |
| * ======================================================================= |
| * STEP 3 : generating output HTML file |
| * ====================================================================== |
| */ |
| |
| final File htmlFile = new File(inputFile.getParentFile(), "app4mc-help_1_updated_headings.html"); |
| |
| try (BufferedWriter bw = new BufferedWriter( |
| new OutputStreamWriter(new FileOutputStream(htmlFile), StandardCharsets.UTF_8))) { |
| bw.write(sb.toString()); |
| bw.close(); |
| |
| System.out.println("Generated modified HTML file at : " + htmlFile.getAbsolutePath()); |
| |
| } catch (final IOException e) { |
| e.printStackTrace(); |
| System.err.println("Error writing file : " + htmlFile.getAbsolutePath()); |
| } |
| |
| |
| /*- |
| * ======================================================================= |
| * STEP 4 : generating toc file |
| * ====================================================================== |
| */ |
| |
| HeadingIterator nodes = new HeadingIterator(toc); |
| |
| final File tocFile = new File(inputFile.getParentFile(), "app4mc-help_toc.html"); |
| |
| try (PrintStream out = new PrintStream(new FileOutputStream(tocFile))) { |
| |
| out.println("<!DOCTYPE html>"); |
| out.println("<html lang=\"en-US\">"); |
| out.println(" <head>"); |
| out.println(" <meta charset=\"utf-8\" />"); |
| out.println(" <link rel=\"stylesheet\" href=\"css/toc-style.css\" type=\"text/css\">"); |
| out.println(" </head>"); |
| out.println(" <body>"); |
| out.println(" <h1>Contents</h1>"); |
| out.println(" <div class=\"toc-tree\">"); |
| writeNodeList(out, nodes); |
| out.println(" </div>"); |
| out.println(" </body>"); |
| out.println("</html>"); |
| |
| } catch (final IOException e) { |
| e.printStackTrace(); |
| System.err.println("Error writing file : " + tocFile.getAbsolutePath()); |
| } |
| |
| return htmlFile; // for further processing |
| } |
| |
| |
| // ========== Functions for TOC export ========== |
| |
| private static void writeNodeList(PrintStream out, HeadingIterator headings) { |
| int listLevel = headings.current().level; |
| |
| out.println("<ul>"); |
| while (headings.current().level == listLevel) { |
| if (hasSubElements(headings)) { |
| writeExpandableNode(out, headings); |
| } else { |
| writeLeafNode(out, headings); |
| } |
| } |
| out.println("</ul>"); |
| } |
| |
| private static void writeExpandableNode(PrintStream out, HeadingIterator headings) { |
| final Heading h = headings.current(); |
| // output pattern: <li> <input type="checkbox" id="toc1.2.3" /> |
| // <label for="toc1.2.3"><a href="#section1.2.3">Text</a></label> |
| // ... |
| // </li> |
| out.println("<li>" + getInput(h) + getLabel(h, getLink(h))); |
| headings.next(); |
| writeNodeList(out, headings); |
| out.println("</li>"); |
| } |
| |
| private static void writeLeafNode(PrintStream out, HeadingIterator headings) { |
| final Heading h = headings.current(); |
| //output pattern: <li><label class="leaf"><a href="#section1.2.3">Text</a></label></li> |
| out.println("<li><label class=\"leaf\">" + getLink(h) + "</label></li>"); |
| headings.next(); |
| } |
| |
| private static boolean hasSubElements(HeadingIterator headings) { |
| return headings.current().level < headings.preview().level; |
| } |
| |
| |
| private static String getInput(Heading h) { |
| // pattern: <input type="checkbox" id="toc1.2.3" /> |
| return "<input type=\"checkbox\" id=\"toc" + h.number + "\" />"; |
| } |
| |
| private static String getLabel(Heading h, String text) { |
| // pattern: <label for="toc1.2.3">text</label> |
| return "<label for=\"toc" + h.number + "\">" + text + "</label>"; |
| } |
| |
| private static String getLink(Heading h) { |
| // pattern: <a href="#section1.2.3">Text</a> |
| return "<a href=\"#section" + h.number + "\">" + h.text + "</a>"; |
| } |
| |
| // ========== Functions for Headings modification ========== |
| |
| private static void appendlnHeading(final StringBuffer sb, final Heading heading) { |
| appendlnHeading(sb, heading, null); |
| } |
| |
| private static void appendlnHeading(final StringBuffer sb, final Heading heading, final String id) { |
| sb.append(System.getProperty("line.separator")); |
| sb.append(System.getProperty("line.separator")); |
| sb.append("<h" + heading.level); |
| if (id != null && id != "") { |
| sb.append(" id=\"" + id + "\""); |
| } |
| sb.append(">"); |
| sb.append("<a id=\"section" + heading.number + "\">"); |
| if (heading.level <= 3) { |
| sb.append(heading.number + " "); |
| } |
| sb.append("</a>"); |
| sb.append(heading.text); |
| sb.append("</h" + heading.level + ">"); |
| sb.append(System.getProperty("line.separator")); |
| } |
| |
| private static void appendln(final StringBuffer sb, final String line) { |
| sb.append(line); |
| sb.append(System.getProperty("line.separator")); |
| } |
| |
| private static String extractHeadingId(String input) { |
| String result = null; |
| |
| final Pattern idPattern = Pattern.compile(".*<h\\d\\s+id\\=\"(?<anchorDef>.*?)\">.*"); |
| final Matcher mID = idPattern.matcher(input); |
| while (mID.find()) { |
| result = mID.group("anchorDef"); |
| // System.out.println("AnchorDef : >" + result + "<"); |
| } |
| |
| return result; |
| } |
| |
| } |