| /******************************************************************************* |
| * Copyright (c) 2011-2014 Torkild U. Resheim. |
| * |
| * All rights reserved. This program and the accompanying materials are made |
| * available under the terms of the Eclipse Public License v1.0 which |
| * accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Torkild U. Resheim - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.mylyn.internal.docs.epub.core; |
| |
| import java.io.IOException; |
| |
| import javax.xml.parsers.ParserConfigurationException; |
| import javax.xml.parsers.SAXParser; |
| import javax.xml.parsers.SAXParserFactory; |
| |
| import org.eclipse.emf.ecore.util.FeatureMapUtil; |
| import org.eclipse.mylyn.docs.epub.ncx.Content; |
| import org.eclipse.mylyn.docs.epub.ncx.NCXFactory; |
| import org.eclipse.mylyn.docs.epub.ncx.NavLabel; |
| import org.eclipse.mylyn.docs.epub.ncx.NavPoint; |
| import org.eclipse.mylyn.docs.epub.ncx.Ncx; |
| import org.eclipse.mylyn.docs.epub.ncx.Text; |
| import org.xml.sax.Attributes; |
| import org.xml.sax.InputSource; |
| import org.xml.sax.SAXException; |
| |
| /** |
| * This type is a SAX parser that will read a XHTML file, locate header text (<b>H1</b> trough <b>H6</b>) and create NCX |
| * items for the EPUB table of contents. |
| * |
| * @author Torkild U. Resheim |
| */ |
| public class TOCGenerator extends AbstractXHTMLScanner { |
| |
| private String currentId = null; |
| |
| private NavPoint[] headers = null; |
| |
| private final Ncx ncx; |
| |
| private int playOrder; |
| |
| public int getPlayOrder() { |
| return playOrder; |
| } |
| |
| public TOCGenerator(String href, Ncx ncx, int playOrder) { |
| super(); |
| buffer = new StringBuilder(); |
| currentHref = href; |
| headers = new NavPoint[6]; |
| this.ncx = ncx; |
| this.playOrder = playOrder; |
| } |
| |
| @Override |
| public void endElement(String uri, String localName, String qName) throws SAXException { |
| int level = isHeader(qName); |
| if (level > 0) { |
| recording = false; |
| NavPoint np = createNavPoint(buffer.toString()); |
| // Determine the parent header |
| NavPoint h = headers[level - 1]; |
| while (level > 1 && h == null) { |
| level--; |
| if (level == 1) { |
| h = headers[0]; |
| break; |
| } |
| h = headers[level - 1]; |
| } |
| // Add to the parent header or to the root |
| if (level > 1) { |
| h.getNavPoints().add(np); |
| } else { |
| ncx.getNavMap().getNavPoints().add(np); |
| } |
| headers[level] = np; |
| buffer.setLength(0); |
| } |
| } |
| |
| private NavPoint createNavPoint(String title) { |
| NavPoint np = NCXFactory.eINSTANCE.createNavPoint(); |
| NavLabel nl = NCXFactory.eINSTANCE.createNavLabel(); |
| Content c = NCXFactory.eINSTANCE.createContent(); |
| c.setSrc(currentId == null ? currentHref : currentHref + "#" + currentId); //$NON-NLS-1$ |
| Text text = NCXFactory.eINSTANCE.createText(); |
| FeatureMapUtil.addText(text.getMixed(), title); |
| nl.setText(text); |
| np.getNavLabels().add(nl); |
| np.setPlayOrder(++playOrder); |
| np.setId("navpoint" + playOrder); //$NON-NLS-1$ |
| np.setContent(c); |
| return np; |
| } |
| |
| @Override |
| public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { |
| if (isHeader(qName) > 0) { |
| recording = true; |
| if (attributes.getValue("id") != null) { //$NON-NLS-1$ |
| currentId = attributes.getValue("id"); //$NON-NLS-1$ |
| } else { |
| currentId = null; |
| } |
| } |
| } |
| |
| /** |
| * Parses an XHTML file, representing a publication chapter, and generates a table of contents for this chapter. |
| * |
| * @param file |
| * the XHTML file to parse |
| * @param href |
| * the XHTML file referencing this file |
| * @param ncx |
| * the NCX to add headers to |
| * @param playOrder |
| * initial play order |
| * @return |
| * @throws ParserConfigurationException |
| * @throws SAXException |
| * @throws IOException |
| */ |
| public static int parse(InputSource file, String href, Ncx ncx, int playOrder) throws ParserConfigurationException, |
| SAXException, IOException { |
| SAXParserFactory factory = SAXParserFactory.newInstance(); |
| factory.setFeature("http://xml.org/sax/features/validation", false); //$NON-NLS-1$ |
| factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); //$NON-NLS-1$ |
| SAXParser parser = factory.newSAXParser(); |
| TOCGenerator tocGenerator = new TOCGenerator(href, ncx, playOrder); |
| try { |
| parser.parse(file, tocGenerator); |
| } catch (SAXException e) { |
| System.err.println("Could not parse " + href); //$NON-NLS-1$ |
| e.printStackTrace(); |
| } |
| return tocGenerator.getPlayOrder(); |
| } |
| |
| } |