Skip to content

Commit

Permalink
Initial EPUB infrastructure
Browse files Browse the repository at this point in the history
This adds a new EPUB stylesheet and the various bits of machinery
needed to produce a basic EPUB file. Currently, the code is very
incomplete and the resulting EPUB is unpleasant to look at due to
CSS (or lack of).

Affects: #13
  • Loading branch information
io7m committed Jun 21, 2021
1 parent b81f9e1 commit 94ca1a8
Show file tree
Hide file tree
Showing 23 changed files with 1,925 additions and 6 deletions.
Expand Up @@ -116,7 +116,14 @@ enum Stylesheet
* per section.
*/

MULTIPLE_FILE
MULTIPLE_FILE,

/**
* The EPUB stylesheet. Produces a set of output files suitable for
* use in an EPUB file.
*/

EPUB
}

/**
Expand All @@ -136,7 +143,13 @@ enum Task
* The input document will be transformed to XHTML.
*/

TRANSFORM_XHTML
TRANSFORM_XHTML,

/**
* The input document will be transformed to an EPUB.
*/

TRANSFORM_EPUB
}

/**
Expand Down
Expand Up @@ -54,18 +54,21 @@ public Main(
final XSCommandRoot r = new XSCommandRoot();
final var validate = new XSCommandValidate();
final var xhtml = new XSCommandTransformXHTML();
final var epub = new XSCommandTransformEPUB();
final var schema = new XSCommandSchema();

this.commands = new HashMap<>(8);
this.commands.put("epub", epub);
this.commands.put("schema", schema);
this.commands.put("validate", validate);
this.commands.put("xhtml", xhtml);
this.commands.put("schema", schema);

this.commander = new JCommander(r);
this.commander.setProgramName("xstructural");
this.commander.addCommand("epub", epub);
this.commander.addCommand("schema", schema);
this.commander.addCommand("validate", validate);
this.commander.addCommand("xhtml", xhtml);
this.commander.addCommand("schema", schema);
}

/**
Expand Down
@@ -0,0 +1,94 @@
/*
* Copyright © 2020 Mark Raynsford <code@io7m.com> http://io7m.com
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

package com.io7m.xstructural.cmdline;

import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.io7m.xstructural.api.XSProcessorRequest;
import com.io7m.xstructural.cmdline.internal.XSServices;

import java.nio.file.Path;

import static com.io7m.xstructural.api.XSProcessorRequestType.Stylesheet;
import static com.io7m.xstructural.api.XSProcessorRequestType.Task;

@Parameters(commandDescription = "Transform a structural document to an EPUB")
final class XSCommandTransformEPUB extends XSCommandRoot
{
@Parameter(
required = true,
description = "The source document",
names = "--sourceFile"
)
private Path sourceFile;

@Parameter(
required = true,
description = "The output directory",
names = "--outputDirectory"
)
private Path outputDirectory;

@Parameter(
required = false,
description = "The output file for trace messages",
names = "--traceFile"
)
private Path traceFile;

@Parameter(
required = false,
description = "The output file for XSLT messages",
names = "--messagesFile"
)
private Path messagesFile;

XSCommandTransformEPUB()
{

}

@Override
public Status execute()
throws Exception
{
if (super.execute() == Status.FAILURE) {
return Status.FAILURE;
}

final var requestBuilder = XSProcessorRequest.builder();
requestBuilder.setOutputDirectory(this.outputDirectory.toAbsolutePath());
requestBuilder.setSourceFile(this.sourceFile.toAbsolutePath());
requestBuilder.setStylesheet(Stylesheet.EPUB);
requestBuilder.setTask(Task.TRANSFORM_EPUB);
requestBuilder.setWriteResources(false);

if (this.traceFile != null) {
requestBuilder.setTraceFile(this.traceFile.toAbsolutePath());
}
if (this.messagesFile != null) {
requestBuilder.setMessageFile(this.messagesFile.toAbsolutePath());
}

final var request = requestBuilder.build();
final var processors = XSServices.findProcessors();
final var processor = processors.create(request);
processor.execute();
return Status.SUCCESS;
}

}
Expand Up @@ -403,4 +403,166 @@ public void testSchemaReplace()
}
);
}

@Test
public void testTransformXHTMLEPUBOKExample0()
throws Exception
{
XSTestDirectories.resourceOf(
XSCommandLineTest.class,
this.sourceDirectory,
"poppy.jpg"
);
XSTestDirectories.resourceOf(
XSCommandLineTest.class,
this.sourceDirectory,
"missing.jpg"
);
XSTestDirectories.resourceOf(
XSCommandLineTest.class,
this.sourceDirectory,
"woods.jpg"
);

final var main = new Main(new String[]{
"epub",
"--sourceFile",
XSTestDirectories.resourceOf(
XSCommandLineTest.class,
this.sourceDirectory,
"example0.xml")
.toString(),
"--outputDirectory",
this.outputDirectory.toString(),
"--traceFile",
this.directory.resolve("trace.xml").toString(),
"--messagesFile",
this.directory.resolve("messages.log").toString(),
"--verbose",
"trace"
});
main.run();
Assertions.assertEquals(0, main.exitCode());

Assertions.assertTrue(
Files.isRegularFile(this.directory.resolve("trace.xml")),
"Trace file exists"
);
Assertions.assertTrue(
Files.isRegularFile(this.directory.resolve("messages.log")),
"Messages file exists"
);
Assertions.assertTrue(
Files.isRegularFile(this.outputDirectory.resolve("output.epub")),
"EPUB file exists"
);
}

@Test
public void testTransformXHTMLEPUBOKExample1()
throws Exception
{
XSTestDirectories.resourceOf(
XSCommandLineTest.class,
this.sourceDirectory,
"poppy.jpg"
);
XSTestDirectories.resourceOf(
XSCommandLineTest.class,
this.sourceDirectory,
"missing.jpg"
);
XSTestDirectories.resourceOf(
XSCommandLineTest.class,
this.sourceDirectory,
"woods.jpg"
);

final var main = new Main(new String[]{
"epub",
"--sourceFile",
XSTestDirectories.resourceOf(
XSCommandLineTest.class,
this.sourceDirectory,
"example1.xml")
.toString(),
"--outputDirectory",
this.outputDirectory.toString(),
"--traceFile",
this.directory.resolve("trace.xml").toString(),
"--messagesFile",
this.directory.resolve("messages.log").toString(),
"--verbose",
"trace"
});
main.run();
Assertions.assertEquals(0, main.exitCode());

Assertions.assertTrue(
Files.isRegularFile(this.directory.resolve("trace.xml")),
"Trace file exists"
);
Assertions.assertTrue(
Files.isRegularFile(this.directory.resolve("messages.log")),
"Messages file exists"
);
Assertions.assertTrue(
Files.isRegularFile(this.outputDirectory.resolve("output.epub")),
"EPUB file exists"
);
}

@Test
public void testTransformXHTMLEPUBOKExample2()
throws Exception
{
XSTestDirectories.resourceOf(
XSCommandLineTest.class,
this.sourceDirectory,
"poppy.jpg"
);
XSTestDirectories.resourceOf(
XSCommandLineTest.class,
this.sourceDirectory,
"missing.jpg"
);
XSTestDirectories.resourceOf(
XSCommandLineTest.class,
this.sourceDirectory,
"woods.jpg"
);

final var main = new Main(new String[]{
"epub",
"--sourceFile",
XSTestDirectories.resourceOf(
XSCommandLineTest.class,
this.sourceDirectory,
"example2.xml")
.toString(),
"--outputDirectory",
this.outputDirectory.toString(),
"--traceFile",
this.directory.resolve("trace.xml").toString(),
"--messagesFile",
this.directory.resolve("messages.log").toString(),
"--verbose",
"trace"
});
main.run();
Assertions.assertEquals(0, main.exitCode());

Assertions.assertTrue(
Files.isRegularFile(this.directory.resolve("trace.xml")),
"Trace file exists"
);
Assertions.assertTrue(
Files.isRegularFile(this.directory.resolve("messages.log")),
"Messages file exists"
);
Assertions.assertTrue(
Files.isRegularFile(this.outputDirectory.resolve("output.epub")),
"EPUB file exists"
);
}
}
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8" ?>

<Document xmlns="urn:com.io7m.structural:7:0"
xmlns:dc="http://purl.org/dc/elements/1.1/"
tableOfContentsDepth="3"
tableOfContents="true">

<Metadata>
<dc:contributor>A Contributor</dc:contributor>
<dc:creator>A Creator</dc:creator>
<dc:description>An example article.</dc:description>
<dc:identifier>7486b85a-30de-4007-8b32-679b8a851b91</dc:identifier>
<dc:language>English</dc:language>
<dc:publisher>A Publisher</dc:publisher>
<dc:relation>A Relation</dc:relation>
<dc:rights>CC-0</dc:rights>
<dc:source>A Source</dc:source>
<dc:title>Example Document</dc:title>
</Metadata>

<Section title="08eb2001-58ef-44be-acce-5eecee051515">
<Paragraph>
No bagel.
</Paragraph>
<Paragraph>
No bagel.
</Paragraph>
<Paragraph>
No bagel.
</Paragraph>
<Paragraph>
No bagel.
</Paragraph>
</Section>

</Document>
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions com.io7m.xstructural.vanilla/pom.xml
Expand Up @@ -38,6 +38,18 @@
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<dependency>
<groupId>org.w3c</groupId>
<artifactId>epubcheck</artifactId>
</dependency>

<dependency>
<groupId>org.osgi</groupId>
Expand Down

0 comments on commit 94ca1a8

Please sign in to comment.