Skip to content

Commit

Permalink
Add index generation
Browse files Browse the repository at this point in the history
By specifying the MULTIPLE_FILE_INDEX_ONLY stylesheet, the xhtml command
can now generate an XML index that maps document identifiers to locations
in output files.

Fix: #29
  • Loading branch information
io7m committed Sep 15, 2024
1 parent ae55bf0 commit 651e97d
Show file tree
Hide file tree
Showing 15 changed files with 436 additions and 24 deletions.
9 changes: 7 additions & 2 deletions README-CHANGES.xml
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@
<c:change date="2024-05-08T00:00:00+00:00" summary="Update org.junit.jupiter:junit-jupiter-engine:5.10.1 → 5.10.2"/>
</c:changes>
</c:release>
<c:release date="2024-09-14T15:23:41+00:00" is-open="true" ticket-system="com.github.io7m.xstructural" version="1.9.0">
<c:release date="2024-09-15T10:21:32+00:00" is-open="true" ticket-system="com.github.io7m.xstructural" version="1.9.0">
<c:changes>
<c:change date="2024-09-14T00:00:00+00:00" summary="Change CSS to a form that scales with screen sizes.">
<c:tickets>
Expand All @@ -126,11 +126,16 @@
<c:ticket id="26"/>
</c:tickets>
</c:change>
<c:change date="2024-09-14T15:23:41+00:00" summary="Use normalize-space() on link targets.">
<c:change date="2024-09-14T00:00:00+00:00" summary="Use normalize-space() on link targets.">
<c:tickets>
<c:ticket id="30"/>
</c:tickets>
</c:change>
<c:change date="2024-09-15T10:21:32+00:00" summary="Add MULTIPLE_FILE_INDEX_ONLY index generation.">
<c:tickets>
<c:ticket id="29"/>
</c:tickets>
</c:change>
</c:changes>
</c:release>
</c:releases>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,21 @@ enum Stylesheet
* use in an EPUB file.
*/

EPUB
EPUB,

/**
* <p>The multiple file index stylesheet. Produces a single index file
* that contains references to elements as they would appear had they
* been handled by the {@link #MULTIPLE_FILE} stylesheet.</p>
*
* <p>Essentially, the index answers the question "Given an element in my
* source document, in which file does that element appear in the output
* document?".</p>
*
* @since 1.9.0
*/

MULTIPLE_FILE_INDEX_ONLY
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ public static Set<URI> namespaces()
{
return Set.of(
namespace7p0(),
namespace8p0()
namespace8p0(),
namespace8Index()
);
}

Expand Down Expand Up @@ -69,6 +70,15 @@ public static URI namespace8p0()
return URI.create("urn:com.io7m.structural:8:0");
}

/**
* @return The structural 8.0 index schema
*/

public static URI namespace8Index()
{
return URI.create("urn:com.io7m.structural.index:1:0");
}

/**
* @return The structural 8.0 schema
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
*/

@Export
@Version("1.1.0")
@Version("1.2.0")
package com.io7m.xstructural.api;

import org.osgi.annotation.bundle.Export;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -570,11 +570,12 @@ public void testSchema()
.map(Path::toString)
.collect(Collectors.toList());

Assertions.assertEquals(4L, (long) files.size());
Assertions.assertEquals(5L, (long) files.size());
Assertions.assertTrue(files.contains("xml.xsd"));
Assertions.assertTrue(files.contains("dc.xsd"));
Assertions.assertTrue(files.contains("xstructural-7.xsd"));
Assertions.assertTrue(files.contains("xstructural-8.xsd"));
Assertions.assertTrue(files.contains("xstructural-8-index.xsd"));
}

@Test
Expand All @@ -591,7 +592,7 @@ public void testSchemaNoReplace()
XSOutputCaptured.capture(main::run);

Assertions.assertEquals(0, main.exitCode());
Assertions.assertEquals(4L, Files.list(this.outputDirectory).count());
Assertions.assertEquals(5L, Files.list(this.outputDirectory).count());

Files.list(this.outputDirectory)
.forEach(path -> {
Expand All @@ -609,7 +610,7 @@ public void testSchemaNoReplace()
});
mainAgain.run();
Assertions.assertEquals(0, mainAgain.exitCode());
Assertions.assertEquals(4L, Files.list(this.outputDirectory).count());
Assertions.assertEquals(5L, Files.list(this.outputDirectory).count());

Files.list(this.outputDirectory)
.forEach(path -> {
Expand All @@ -636,7 +637,7 @@ public void testSchemaReplace()
XSOutputCaptured.capture(main::run);

Assertions.assertEquals(0, main.exitCode());
Assertions.assertEquals(4L, Files.list(this.outputDirectory).count());
Assertions.assertEquals(5L, Files.list(this.outputDirectory).count());

Files.list(this.outputDirectory)
.forEach(path -> {
Expand All @@ -656,7 +657,7 @@ public void testSchemaReplace()
});
mainAgain.run();
Assertions.assertEquals(0, mainAgain.exitCode());
Assertions.assertEquals(4L, Files.list(this.outputDirectory).count());
Assertions.assertEquals(5L, Files.list(this.outputDirectory).count());

Files.list(this.outputDirectory)
.forEach(path -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,27 @@
import com.github.marschall.memoryfilesystem.MemoryFileSystemBuilder;
import com.io7m.xstructural.api.XSProcessorRequest;
import com.io7m.xstructural.api.XSProcessorRequestType;
import com.io7m.xstructural.api.XSTransformException;
import com.io7m.xstructural.api.XSValidationException;
import com.io7m.xstructural.vanilla.XSProcessors;
import com.io7m.xstructural.vanilla.internal.XSValidator;
import com.io7m.xstructural.xml.SXMLResources;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.w3c.dom.Element;

import javax.xml.parsers.DocumentBuilderFactory;
import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

public final class XSProcessorTest
{
private static final Duration TIMEOUT = Duration.ofSeconds(15L);
Expand Down Expand Up @@ -344,4 +352,137 @@ public void testCompileSingleExampleWindows0_70()
final var processor = this.processors.create(request);
Assertions.assertTimeout(TIMEOUT, processor::execute);
}

@Test
public void testCompileMultipleIndex0_70()
throws Exception
{
final var request =
XSProcessorRequest.builder()
.setOutputDirectory(this.outputDirectory)
.setSourceFile(XSTestDirectories.resourceOf(
XSProcessorTest.class,
this.sourceDirectory,
"example1_70.xml"))
.setTraceFile(this.directory.resolve("trace.xml"))
.setMessageFile(this.directory.resolve("messages.txt"))
.setStylesheet(XSProcessorRequestType.Stylesheet.MULTIPLE_FILE_INDEX_ONLY)
.build();

final var processor =
this.processors.create(request);
final var x =
Assertions.assertThrows(XSTransformException.class, processor::execute);
assertTrue(x.getMessage().contains("Unsupported configuration"));
}

@Test
public void testCompileMultipleIndex0_80()
throws Exception
{
final var request =
XSProcessorRequest.builder()
.setOutputDirectory(this.outputDirectory)
.setSourceFile(XSTestDirectories.resourceOf(
XSProcessorTest.class,
this.sourceDirectory,
"example1_index_80.xml"))
.setTraceFile(this.directory.resolve("trace.xml"))
.setMessageFile(this.directory.resolve("messages.txt"))
.setStylesheet(XSProcessorRequestType.Stylesheet.MULTIPLE_FILE_INDEX_ONLY)
.build();

final var processor = this.processors.create(request);
Assertions.assertTimeout(TIMEOUT, processor::execute);

final var indexFile =
this.outputDirectory.resolve("xstructural-index.xml");

assertTrue(Files.isRegularFile(indexFile));

final var validator =
new XSValidator(
new SXMLResources(),
XSProcessorRequest.builder()
.setTask(XSProcessorRequestType.Task.VALIDATE)
.setOutputDirectory(this.outputDirectory)
.setSourceFile(indexFile)
.setStylesheet(XSProcessorRequestType.Stylesheet.MULTIPLE_FILE_INDEX_ONLY)
.build()
);

validator.execute();

{
final var d =
DocumentBuilderFactory.newNSInstance()
.newDocumentBuilder()
.parse(indexFile.toFile());

final var items = d.getElementsByTagNameNS("urn:com.io7m.structural.index:1:0", "Item");
assertEquals(8, items.getLength());

{
final var i = (Element) items.item(0);
assertEquals("d0e32.xhtml", i.getAttribute("File"));
assertEquals("59259ed7-a88d-4411-b397-b9aa20aec3a0", i.getAttribute("ID"));
assertEquals("Section", i.getAttribute("Type"));
assertEquals("Section-A", i.getAttribute("Title"));
}

{
final var i = (Element) items.item(1);
assertEquals("d0e32.xhtml", i.getAttribute("File"));
assertEquals("27174ab0-0c36-43c9-9f7e-1e140ade8510", i.getAttribute("ID"));
assertEquals("Subsection", i.getAttribute("Type"));
assertEquals("Subsection-A", i.getAttribute("Title"));
}

{
final var i = (Element) items.item(2);
assertEquals("d0e32.xhtml", i.getAttribute("File"));
assertEquals("24cafbdf-cfb6-4fee-a8d6-496d98b4def7", i.getAttribute("ID"));
assertEquals("Paragraph", i.getAttribute("Type"));
}

{
final var i = (Element) items.item(3);
assertEquals("d0e32.xhtml", i.getAttribute("File"));
assertEquals("cdbeb82b-ba49-4504-9c7f-86fe5186184d", i.getAttribute("ID"));
assertEquals("FormalItem", i.getAttribute("Type"));
assertEquals("Formal-A", i.getAttribute("Title"));
}

{
final var i = (Element) items.item(4);
assertEquals("d0e46.xhtml", i.getAttribute("File"));
assertEquals("1b3fed5d-31dd-42bd-98c1-30bfaa873de4", i.getAttribute("ID"));
assertEquals("Section", i.getAttribute("Type"));
assertEquals("Section-B", i.getAttribute("Title"));
}

{
final var i = (Element) items.item(5);
assertEquals("d0e46.xhtml", i.getAttribute("File"));
assertEquals("5455c2c4-5468-4dc3-8f0f-27d8da7331cd", i.getAttribute("ID"));
assertEquals("Subsection", i.getAttribute("Type"));
assertEquals("Subsection-B", i.getAttribute("Title"));
}

{
final var i = (Element) items.item(6);
assertEquals("d0e46.xhtml", i.getAttribute("File"));
assertEquals("ee1f2ec7-d958-4a31-8773-36235e63c9ab", i.getAttribute("ID"));
assertEquals("Paragraph", i.getAttribute("Type"));
}

{
final var i = (Element) items.item(7);
assertEquals("d0e46.xhtml", i.getAttribute("File"));
assertEquals("b8bc55d6-3f1e-491e-a3f1-8e6c40461a51", i.getAttribute("ID"));
assertEquals("FormalItem", i.getAttribute("Type"));
assertEquals("Formal-B", i.getAttribute("Title"));
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8" ?>

<!-- Comments! -->

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

<!-- Comments! -->

<Metadata>
<dc:contributor>A Contributor</dc:contributor>
<dc:creator>A Creator</dc:creator>
<dc:date>2020-04-23T10:19:25+00:00</dc:date>
<dc:description>An example article.</dc:description>
<dc:identifier>c65fa00d-0870-405e-8f13-258e5cf4992d</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="Section-A" id="59259ed7-a88d-4411-b397-b9aa20aec3a0">
<Subsection title="Subsection-A" id="27174ab0-0c36-43c9-9f7e-1e140ade8510">
<Paragraph id="24cafbdf-cfb6-4fee-a8d6-496d98b4def7">
Paragraphy.
</Paragraph>
<FormalItem title="Formal-A" id="cdbeb82b-ba49-4504-9c7f-86fe5186184d">
<Verbatim>Hello!</Verbatim>
</FormalItem>
</Subsection>
</Section>

<Section title="Section-B" id="1b3fed5d-31dd-42bd-98c1-30bfaa873de4">
<Subsection title="Subsection-B" id="5455c2c4-5468-4dc3-8f0f-27d8da7331cd">
<Paragraph id="ee1f2ec7-d958-4a31-8773-36235e63c9ab">
Paragraphy.
</Paragraph>
<FormalItem title="Formal-B" id="b8bc55d6-3f1e-491e-a3f1-8e6c40461a51">
<Verbatim>Hello!</Verbatim>
</FormalItem>
</Subsection>
</Section>

</Document>
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ public InputSource resolveEntity(

case "xstructural-8.xsd":
case "xstructural-7.xsd":
case "xstructural-8-index.xsd":
case "xml.xsd":
case "dc.xsd": {
final var source = new InputSource(systemId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ public XMLReader createXMLReader(

schemas.put(XSSchemas.namespace7p0(), "xstructural-7.xsd");
schemas.put(XSSchemas.namespace8p0(), "xstructural-8.xsd");
schemas.put(XSSchemas.namespace8Index(), "xstructural-8-index.xsd");
schemas.forEach((key, value) -> {
locations.append(key);
locations.append(' ');
Expand Down
Loading

0 comments on commit 651e97d

Please sign in to comment.