blob: 48ebbfbc512d0b89ce9210f2432b528904f70ae3 [file] [log] [blame]
/*******************************************************************************
* 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();
}
}