diff --git a/src/main/java/com/adobe/epubcheck/messages/DefaultSeverities.java b/src/main/java/com/adobe/epubcheck/messages/DefaultSeverities.java index 4619aece7..7aa750937 100644 --- a/src/main/java/com/adobe/epubcheck/messages/DefaultSeverities.java +++ b/src/main/java/com/adobe/epubcheck/messages/DefaultSeverities.java @@ -254,6 +254,9 @@ private void initialize() severities.put(MessageId.OPF_083, Severity.ERROR); severities.put(MessageId.OPF_084, Severity.ERROR); severities.put(MessageId.OPF_085, Severity.WARNING); + severities.put(MessageId.OPF_086, Severity.WARNING); + severities.put(MessageId.OPF_087, Severity.ERROR); + severities.put(MessageId.OPF_088, Severity.USAGE); // PKG severities.put(MessageId.PKG_001, Severity.WARNING); diff --git a/src/main/java/com/adobe/epubcheck/messages/LocalizedMessages.java b/src/main/java/com/adobe/epubcheck/messages/LocalizedMessages.java index 48c551af5..6e9fe69b4 100644 --- a/src/main/java/com/adobe/epubcheck/messages/LocalizedMessages.java +++ b/src/main/java/com/adobe/epubcheck/messages/LocalizedMessages.java @@ -134,11 +134,42 @@ private String getMessageAsString(MessageId id) return getStringFromBundle(id.name()); } - private String getSuggestion(MessageId id) + /** + * Returns the suggestion message for the given message ID. + * In other words, for a message ID of `XXX_NNN`, + * returns the bundle message named `XXX_NNN_SUG`. + * + * @param id a message ID + * @return the associated suggestion, or the empty string if there's none. + */ + public String getSuggestion(MessageId id) { return getStringFromBundle(id.name() + "_SUG"); } + + /** + * Returns the suggestion message for the given message ID and key. + * In other words, for a message ID of `XXX_NNN`, and a key `key`, + * returns the bundle message named `XXX_NNN_SUG.key`. + * If the suggestion key is not found, returns the bundle message + * named `XXX_NNN_SUG.default`. + * If this latter is not found, returns the bundle message nameed + * `XXX_NNN_SUG`. + * + * @param id a message ID + * @param key the key of a specific suggestion string + * @return the associated suggestion string + */ + public String getSuggestion(MessageId id, String key) + { + String messageKey = id.name() + "_SUG." + key; + String messageDefaultKey = id.name() + "_SUG.default"; + return bundle.containsKey(messageKey) ? getStringFromBundle(messageKey) + : (bundle.containsKey(messageDefaultKey) ? getStringFromBundle(messageDefaultKey) + : getSuggestion(id)); + } + public static class UTF8Control extends ResourceBundle.Control { diff --git a/src/main/java/com/adobe/epubcheck/messages/MessageId.java b/src/main/java/com/adobe/epubcheck/messages/MessageId.java index 6c25447b4..788bfcd56 100644 --- a/src/main/java/com/adobe/epubcheck/messages/MessageId.java +++ b/src/main/java/com/adobe/epubcheck/messages/MessageId.java @@ -247,6 +247,9 @@ public enum MessageId implements Comparable OPF_083("OPF-083"), OPF_084("OPF-084"), OPF_085("OPF-085"), + OPF_086("OPF-086"), + OPF_087("OPF-087"), + OPF_088("OPF-088"), // Messages relating to the entire package PKG_001("PKG-001"), diff --git a/src/main/java/com/adobe/epubcheck/opf/OPFHandler30.java b/src/main/java/com/adobe/epubcheck/opf/OPFHandler30.java index f6fa9e691..51939d330 100644 --- a/src/main/java/com/adobe/epubcheck/opf/OPFHandler30.java +++ b/src/main/java/com/adobe/epubcheck/opf/OPFHandler30.java @@ -453,7 +453,7 @@ private void processLink(XMLElement e) private void processItemrefProperties(OPFItem.Builder builder, String property) { - Set properties = VocabUtil.parsePropertyList(property, itemrefVocabs, report, + Set properties = VocabUtil.parsePropertyList(property, itemrefVocabs, context, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber())); builder.properties(properties); if (properties @@ -489,7 +489,7 @@ private void processItemProperties(OPFItem.Builder builder, String property, Str return; } - Set properties = VocabUtil.parsePropertyList(property, itemVocabs, report, + Set properties = VocabUtil.parsePropertyList(property, itemVocabs, context, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber())); Set itemProps = Property.filter(properties, ITEM_PROPERTIES.class); @@ -508,7 +508,7 @@ private void processItemProperties(OPFItem.Builder builder, String property, Str private Set processLinkRel(String rel) { - return VocabUtil.parsePropertyList(rel, linkrelVocabs, report, + return VocabUtil.parsePropertyList(rel, linkrelVocabs, context, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber())); } @@ -516,7 +516,7 @@ private void processMeta(XMLElement e) { // get the property Optional prop = VocabUtil.parseProperty(e.getAttribute("property"), metaVocabs, - report, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber())); + context, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber())); if (prop.isPresent() && !metadataBuilders.isEmpty()) { @@ -525,7 +525,7 @@ private void processMeta(XMLElement e) } // just parse the scheme for vocab errors - VocabUtil.parseProperty(e.getAttribute("scheme"), metaVocabs, report, + VocabUtil.parseProperty(e.getAttribute("scheme"), metaVocabs, context, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber())); } diff --git a/src/main/java/com/adobe/epubcheck/ops/OPSHandler30.java b/src/main/java/com/adobe/epubcheck/ops/OPSHandler30.java index 6e7ab8292..63a11fcb1 100644 --- a/src/main/java/com/adobe/epubcheck/ops/OPSHandler30.java +++ b/src/main/java/com/adobe/epubcheck/ops/OPSHandler30.java @@ -24,9 +24,10 @@ import com.adobe.epubcheck.vocab.ComicsVocab; import com.adobe.epubcheck.vocab.DataNavVocab; import com.adobe.epubcheck.vocab.DictVocab; -import com.adobe.epubcheck.vocab.EnumVocab; import com.adobe.epubcheck.vocab.EpubCheckVocab; +import com.adobe.epubcheck.vocab.ForeignVocabs; import com.adobe.epubcheck.vocab.IndexVocab; +import com.adobe.epubcheck.vocab.MagazineNavigationVocab; import com.adobe.epubcheck.vocab.PackageVocabs; import com.adobe.epubcheck.vocab.PackageVocabs.ITEM_PROPERTIES; import com.adobe.epubcheck.vocab.Property; @@ -38,10 +39,8 @@ import com.adobe.epubcheck.xml.XMLAttribute; import com.adobe.epubcheck.xml.XMLElement; import com.adobe.epubcheck.xml.XMLParser; -import com.google.common.base.Function; import com.google.common.base.Joiner; import com.google.common.base.Strings; -import com.google.common.collect.Collections2; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; @@ -53,10 +52,13 @@ public class OPSHandler30 extends OPSHandler private static Map RESERVED_VOCABS = ImmutableMap. of("", AggregateVocab.of(StructureVocab.VOCAB, StagingEdupubVocab.VOCAB, DataNavVocab.VOCAB, - DictVocab.VOCAB, IndexVocab.VOCAB, ComicsVocab.VOCAB)); + DictVocab.VOCAB, IndexVocab.VOCAB, ComicsVocab.VOCAB, StructureVocab.UNCHECKED_VOCAB), + MagazineNavigationVocab.PREFIX, MagazineNavigationVocab.VOCAB, ForeignVocabs.PRISM_PREFIX, + ForeignVocabs.PRISM_VOCAB); private static Map ALTCSS_VOCABS = ImmutableMap. of("", AltStylesheetVocab.VOCAB); - private static Map KNOWN_VOCAB_URIS = ImmutableMap.of(); + private static Map KNOWN_VOCAB_URIS = ImmutableMap.of(MagazineNavigationVocab.URI, + MagazineNavigationVocab.VOCAB, ForeignVocabs.PRISM_URI, ForeignVocabs.PRISM_VOCAB); private static Set DEFAULT_VOCAB_URIS = ImmutableSet.of(StructureVocab.URI); private Map vocabs = RESERVED_VOCABS; @@ -138,9 +140,21 @@ protected void checkType(XMLElement e, String type) { return; } - Set propList = VocabUtil.parsePropertyList(type, vocabs, report, + Set propList = VocabUtil.parsePropertyList(type, vocabs, context, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber())); checkTypes(Property.filter(propList, StructureVocab.EPUB_TYPES.class)); + + // Check unrecognized properties from the structure vocab + for (Property property : propList) + { + if (StructureVocab.URI.equals(property.getVocabURI())) try + { + property.toEnum(); + } catch (UnsupportedOperationException ex) + { + report.message(MessageId.OPF_088, parser.getLocation(), property.getName()); + } + } // Check the 'region-based' property (Data Navigation Documents) if (propList.contains(DataNavVocab.VOCAB.get(DataNavVocab.EPUB_TYPES.REGION_BASED))) @@ -322,7 +336,7 @@ protected void processLink(XMLElement e) return; } - Set properties = VocabUtil.parsePropertyList(classAttribute, ALTCSS_VOCABS, report, + Set properties = VocabUtil.parsePropertyList(classAttribute, ALTCSS_VOCABS, context, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber())); Set altClasses = Property.filter(properties, AltStylesheetVocab.PROPERTIES.class); diff --git a/src/main/java/com/adobe/epubcheck/overlay/OverlayHandler.java b/src/main/java/com/adobe/epubcheck/overlay/OverlayHandler.java index b0afba038..106cfed65 100644 --- a/src/main/java/com/adobe/epubcheck/overlay/OverlayHandler.java +++ b/src/main/java/com/adobe/epubcheck/overlay/OverlayHandler.java @@ -85,7 +85,7 @@ else if (name.equals("body") || name.equals("par")) private void checkType(String type) { - VocabUtil.parsePropertyList(type, vocabs, report, + VocabUtil.parsePropertyList(type, vocabs, context, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber())); } diff --git a/src/main/java/com/adobe/epubcheck/util/ThrowingResourceProvider.java b/src/main/java/com/adobe/epubcheck/util/ThrowingResourceProvider.java new file mode 100644 index 000000000..55e9614ba --- /dev/null +++ b/src/main/java/com/adobe/epubcheck/util/ThrowingResourceProvider.java @@ -0,0 +1,16 @@ +package com.adobe.epubcheck.util; + +import java.io.IOException; +import java.io.InputStream; + +public final class ThrowingResourceProvider implements GenericResourceProvider +{ + + @Override + public InputStream getInputStream(String path) + throws IOException + { + throw new IOException(); + } + +} diff --git a/src/main/java/com/adobe/epubcheck/vocab/ForeignVocabs.java b/src/main/java/com/adobe/epubcheck/vocab/ForeignVocabs.java index 095b3c39e..b46fd0179 100644 --- a/src/main/java/com/adobe/epubcheck/vocab/ForeignVocabs.java +++ b/src/main/java/com/adobe/epubcheck/vocab/ForeignVocabs.java @@ -18,6 +18,10 @@ public final class ForeignVocabs public static final String ONIX_URI = "http://www.editeur.org/ONIX/book/codelists/current.html#"; public static final Vocab ONIX_VOCAB = new UncheckedVocab(ONIX_URI, ONIX_PREFIX); + public static final String PRISM_PREFIX = "prism"; + public static final String PRISM_URI = "http://www.prismstandard.org/specifications/3.0/PRISM_CV_Spec_3.0.htm#"; + public static final Vocab PRISM_VOCAB = new UncheckedVocab(PRISM_URI, PRISM_PREFIX); + public static final String SCHEMA_PREFIX = "schema"; public static final String SCHEMA_URI = "http://schema.org/"; public static final Vocab SCHEMA_VOCAB = new UncheckedVocab(SCHEMA_URI, SCHEMA_PREFIX); diff --git a/src/main/java/com/adobe/epubcheck/vocab/MagazineNavigationVocab.java b/src/main/java/com/adobe/epubcheck/vocab/MagazineNavigationVocab.java new file mode 100644 index 000000000..c2eff3b2c --- /dev/null +++ b/src/main/java/com/adobe/epubcheck/vocab/MagazineNavigationVocab.java @@ -0,0 +1,14 @@ +package com.adobe.epubcheck.vocab; + +public final class MagazineNavigationVocab +{ + public static final String PREFIX = "msv"; + public static final String URI = "http://www.idpf.org/epub/vocab/structure/magazine/#"; + public static final Vocab VOCAB = new UncheckedVocab(URI, PREFIX); + + + private MagazineNavigationVocab() + { + } + +} diff --git a/src/main/java/com/adobe/epubcheck/vocab/Property.java b/src/main/java/com/adobe/epubcheck/vocab/Property.java index d1e2f2c56..7048768b5 100644 --- a/src/main/java/com/adobe/epubcheck/vocab/Property.java +++ b/src/main/java/com/adobe/epubcheck/vocab/Property.java @@ -3,6 +3,7 @@ import java.util.EnumSet; import java.util.Set; +import com.adobe.epubcheck.opf.ValidationContext; import com.google.common.base.Function; import com.google.common.base.Preconditions; import com.google.common.base.Predicates; @@ -20,10 +21,12 @@ */ public final class Property { + private final String base; private final String name; private final String prefixedName; private final String fullName; private final Enum enumee; + private final PropertyStatus status; /** * Creates a new instance from a short name, a prefix, and a stem URI. @@ -90,12 +93,15 @@ public E apply(Property input) }), Predicates.notNull())); } - private Property(String name, String base, String prefix, Enum enumee) + private Property(String name, String base, String prefix, final Enum enumee) { this.name = name; + this.base = base; this.fullName = base + name; this.prefixedName = (Strings.isNullOrEmpty(prefix)) ? name : prefix + ':' + name; this.enumee = enumee; + this.status = (enumee instanceof PropertyStatus) ? ((PropertyStatus) enumee) + : PropertyStatus.ALLOWED; } /** @@ -128,6 +134,40 @@ public String getPrefixedName() return prefixedName; } + /** + * Returns the vocab URI of this property. + * + * @return the URI of the vocab where this property is defined + */ + public String getVocabURI() + { + return base; + } + + /** + * Returns whether this property is allowed in the given validation context. + * Disallowed properties are reported as ERRORs. + * + * @param context + * the validation context (locale, path, etc). + * @return true iff the property is allowed in the given context + */ + public boolean isAllowed(ValidationContext context) + { + return status.isAllowed(context); + } + + /** + * Returns whether this property is deprecated. Deprecated properties are + * reported as WARNINGs. + * + * @return true iff the property is deprecated + */ + public boolean isDeprecated() + { + return status.isDeprecated(); + } + /** * Returns the {@link Enum} item that is used to represent this property in * enum-based vocabularies. diff --git a/src/main/java/com/adobe/epubcheck/vocab/PropertyStatus.java b/src/main/java/com/adobe/epubcheck/vocab/PropertyStatus.java new file mode 100644 index 000000000..bb38acad0 --- /dev/null +++ b/src/main/java/com/adobe/epubcheck/vocab/PropertyStatus.java @@ -0,0 +1,91 @@ +package com.adobe.epubcheck.vocab; + +import com.adobe.epubcheck.opf.ValidationContext; +import com.google.common.base.Preconditions; + +/** + * Holds info about an EPUB vocabulary property, specifically whether it's + * disallowed (ERROR) or deprecate (WARNING). + */ +public interface PropertyStatus +{ + public boolean isAllowed(ValidationContext context); + + public boolean isDeprecated(); + + /** + * The 'allowed' status (for properties that are neither disallowed or + * deprecated). + */ + public static final PropertyStatus ALLOWED = new PropertyStatus() + { + @Override + /** + * Always returns false. + */ + public boolean isDeprecated() + { + return false; + } + + /** + * Always returns true. + */ + @Override + public boolean isAllowed(ValidationContext context) + { + return true; + } + }; + + /** + * The 'deprecated' status (for properties that are allowed but deprecated). + */ + public static final PropertyStatus DEPRECATED = new PropertyStatus() + { + @Override + /** + * Always returns true. + */ + public boolean isDeprecated() + { + return true; + } + + @Override + /** + * Always returns true. + */ + public boolean isAllowed(ValidationContext context) + { + return true; + } + }; + + /** + * The status of properties that are disallowed on Content Documents (documents + * of type 'application/xhtml+xml') + */ + public static final PropertyStatus DISALLOWED_ON_CONTENT_DOCS = new PropertyStatus() + { + @Override + /** + * Always returns false. + */ + public boolean isDeprecated() + { + return false; + } + + @Override + /** + * Returns false iff the context is an XHTML document. + */ + public boolean isAllowed(ValidationContext context) + { + return !"application/xhtml+xml".equals(Preconditions.checkNotNull(context).mimeType); + + } + }; + +} diff --git a/src/main/java/com/adobe/epubcheck/vocab/StructureVocab.java b/src/main/java/com/adobe/epubcheck/vocab/StructureVocab.java index 66b1a7a06..8d7c75dd0 100644 --- a/src/main/java/com/adobe/epubcheck/vocab/StructureVocab.java +++ b/src/main/java/com/adobe/epubcheck/vocab/StructureVocab.java @@ -1,16 +1,22 @@ package com.adobe.epubcheck.vocab; +import com.adobe.epubcheck.opf.ValidationContext; +import com.google.common.base.Preconditions;; + public final class StructureVocab { + public static final String URI = "http://www.idpf.org/epub/vocab/structure/#"; - public static final EnumVocab VOCAB = new EnumVocab(EPUB_TYPES.class, URI); + public static final EnumVocab VOCAB = new EnumVocab(EPUB_TYPES.class, + URI); + public static final Vocab UNCHECKED_VOCAB = new UncheckedVocab(URI, ""); - public static enum EPUB_TYPES + public static enum EPUB_TYPES implements PropertyStatus { ACKNOWLEDGMENTS, AFTERWORD, - ANNOREF, - ANNOTATION, + ANNOREF(DEPRECATED), + ANNOTATION(DEPRECATED), APPENDIX, ASSESSMENT, BACKMATTER, @@ -28,10 +34,12 @@ public static enum EPUB_TYPES COVERTITLE, DEDICATION, DIVISION, + ENDNOTE, + ENDNOTES, EPIGRAPH, EPILOGUE, ERRATA, - FIGURE, + FIGURE(DISALLOWED_ON_CONTENT_DOCS), FOOTNOTE, FOOTNOTES, FOREWORD, @@ -42,7 +50,7 @@ public static enum EPUB_TYPES GLOSSTERM, HALFTITLE, HALFTITLEPAGE, - HELP, + HELP(DEPRECATED), IMPRIMATUR, IMPRINT, INDEX, @@ -51,14 +59,14 @@ public static enum EPUB_TYPES LANDMARKS, LEARNING_OBJECTIVE, LEARNING_RESOURCE, - LIST, - LIST_ITEM, + LIST(DISALLOWED_ON_CONTENT_DOCS), + LIST_ITEM(DISALLOWED_ON_CONTENT_DOCS), LOA, LOI, LOT, LOV, - MARGINALIA, - NOTE, + MARGINALIA(DEPRECATED), + NOTE(DEPRECATED), NOTEREF, NOTICE, OTHER_CREDITS, @@ -69,23 +77,50 @@ public static enum EPUB_TYPES PREAMBLE, PREFACE, PROLOGUE, - REARNOTE, - REARNOTES, + REARNOTE(DEPRECATED), + REARNOTES(DEPRECATED), REVISION_HISTORY, - SIDEBAR, - SUBCHAPTER, + SIDEBAR(DEPRECATED), + SUBCHAPTER(DEPRECATED), SUBTITLE, - TABLE, - TABLE_CELL, - TABLE_ROW, + TABLE(DISALLOWED_ON_CONTENT_DOCS), + TABLE_CELL(DISALLOWED_ON_CONTENT_DOCS), + TABLE_ROW(DISALLOWED_ON_CONTENT_DOCS), + TIP, TITLE, TITLEPAGE, TOC, TOPIC_SENTENCE, VOLUME, - WARNING, - QNA + WARNING(DEPRECATED), + QNA; + + private final PropertyStatus status; + + private EPUB_TYPES() + { + this(ALLOWED); + } + + private EPUB_TYPES(PropertyStatus status) + { + this.status = Preconditions.checkNotNull(status); + } + + @Override + public boolean isAllowed(ValidationContext context) + { + return status.isAllowed(context); + } + + @Override + public boolean isDeprecated() + { + return status.isDeprecated(); + } + } + + private StructureVocab() + { } - - private StructureVocab() {} } diff --git a/src/main/java/com/adobe/epubcheck/vocab/VocabUtil.java b/src/main/java/com/adobe/epubcheck/vocab/VocabUtil.java index 1d980c590..fff01f29f 100644 --- a/src/main/java/com/adobe/epubcheck/vocab/VocabUtil.java +++ b/src/main/java/com/adobe/epubcheck/vocab/VocabUtil.java @@ -7,9 +7,10 @@ import java.util.regex.Pattern; import com.adobe.epubcheck.api.EPUBLocation; -import com.adobe.epubcheck.api.QuietReport; import com.adobe.epubcheck.api.Report; +import com.adobe.epubcheck.messages.LocalizedMessages; import com.adobe.epubcheck.messages.MessageId; +import com.adobe.epubcheck.opf.ValidationContext; import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.base.Splitter; @@ -18,7 +19,6 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Maps; -import com.google.common.collect.Sets; /** * Utilities related to property values, vocabularies, and prefix declarations. @@ -44,19 +44,19 @@ private enum EMPTY * the value to parse. * @param vocabs * a map of prefix to vocabularies. - * @param report - * used to report validation errors. + * @param context + * the validation context (report, locale, path, etc). * @param location * the location in the validated file. * @return an {@link Optional} containing the property if it was parsed * successfully or nothing if there was a parsing error */ public static Optional parseProperty(String value, Map vocabs, - Report report, EPUBLocation location) + ValidationContext context, EPUBLocation location) { return Optional.fromNullable( - Iterables.get(parseProperties(value, vocabs, false, report, location), 0, null)); + Iterables.get(parseProperties(value, vocabs, false, context, location), 0, null)); } /** @@ -67,42 +67,23 @@ public static Optional parseProperty(String value, Map * the value to parse. * @param vocabs * a map of prefix to vocabularies. - * @param report - * used to report validation errors. + * @param context + * the validation context (report, locale, path, etc). * @param location * the location in the validated file. * @return */ public static Set parsePropertyList(String value, Map vocabs, - Report report, EPUBLocation location) - { - return parseProperties(value, vocabs, true, report, location); - } - - /** - * Parses a space-separated list of property values silently, and returns a - * set the properties as a set of Enum values. - * - * @param properties - * the properties string to parse - * @param vocabs - * a map of prefix to vocabularies. - * @param clazz - * the class of the Enum holding the returned properties - * @return - */ - public static > Set parsePropertyListAsEnumSet(String properties, - Map vocabs, Class clazz) + ValidationContext context, EPUBLocation location) { - return Sets.newEnumSet(Property.filter(VocabUtil.parsePropertyList(properties, vocabs, - QuietReport.INSTANCE, EPUBLocation.create("")), clazz), clazz); + return parseProperties(value, vocabs, true, context, location); } private static Set parseProperties(String value, Map vocabs, - boolean isList, Report report, EPUBLocation location) + boolean isList, ValidationContext context, EPUBLocation location) { Preconditions.checkNotNull(vocabs); - Preconditions.checkNotNull(report); + Preconditions.checkNotNull(context); Preconditions.checkNotNull(location); if (value == null) { @@ -115,7 +96,7 @@ private static Set parseProperties(String value, Map properties = whitespaceSplitter.split(value); if (!isList && !Iterables.isEmpty(Iterables.skip(properties, 1))) { - report.message(MessageId.OPF_025, location, value); + context.report.message(MessageId.OPF_025, location, value); return ImmutableSet.of(); } @@ -126,7 +107,7 @@ private static Set parseProperties(String value, Map parseProperties(String value, Map found = vocabs.get(prefix).lookup(name); if (found.isPresent()) { + if (found.get().isDeprecated()) + { + // Replacement suggestions for deprecated properties are given + // in message strings of the form OPF_086_SUG.property-name + String suggestion = LocalizedMessages.getInstance(context.locale) + .getSuggestion(MessageId.OPF_086, found.get().getName()); + context.report.message(MessageId.OPF_086, location, property, suggestion); + } + if (!found.get().isAllowed(context)) + { + context.report.message(MessageId.OPF_087, location, property, context.mimeType); + } builder.add(found.get()); } else { - report.message(MessageId.OPF_027, location, property); + context.report.message(MessageId.OPF_027, location, property); continue; } } catch (NullPointerException e) { // vocab not found (i.e. prefix undeclared), report warning - report.message(MessageId.OPF_028, location, prefix); + context.report.message(MessageId.OPF_028, location, prefix); continue; } } diff --git a/src/main/resources/com/adobe/epubcheck/messages/MessageBundle.properties b/src/main/resources/com/adobe/epubcheck/messages/MessageBundle.properties index 1dcac3629..cc40c7208 100644 --- a/src/main/resources/com/adobe/epubcheck/messages/MessageBundle.properties +++ b/src/main/resources/com/adobe/epubcheck/messages/MessageBundle.properties @@ -245,6 +245,19 @@ OPF_082=Found an EPUB Dictionary collection containing more than one Search Key OPF_083=Found an EPUB Dictionary collection containing no Search Key Map Document. OPF_084=Found an EPUB Dictionary collection containing resource '%1$s' which is neither a Search Key Map Document nor an XHTML Content Document. OPF_085='dc:identifier' value '%1$s' is marked as a UUID, but is an invalid UUID. +OPF_086=Property '%1$s' is deprecated. Consider using %2$s instead. +OPF_086_SUG.default=a custom prefixed property +OPF_086_SUG.annoref=open annotations +OPF_086_SUG.annotation=open annotations +OPF_086_SUG.help=the 'tip' property +OPF_086_SUG.marginalia=a bare 'aside' element +OPF_086_SUG.note=a 'footnote' or 'endnote' property +OPF_086_SUG.rearnote=the 'endnote' property +OPF_086_SUG.rearnotes=the 'endnotes' property +OPF_086_SUG.sidebar=a bare 'aside' element +OPF_086_SUG.warning=the 'notice' property +OPF_087=Property '%1$s' is not allowed on documents of type '%2$s'. +OPF_088=Unrecognized property '%1$s'. #Package PKG_001=Validating the EPUB against version %1$s but detected version %2$s. diff --git a/src/test/java/com/adobe/epubcheck/ops/OPSCheckerTest.java b/src/test/java/com/adobe/epubcheck/ops/OPSCheckerTest.java index e4ca04c58..9b1551ae1 100644 --- a/src/test/java/com/adobe/epubcheck/ops/OPSCheckerTest.java +++ b/src/test/java/com/adobe/epubcheck/ops/OPSCheckerTest.java @@ -463,17 +463,55 @@ public void testValidateXHTMLData() } @Test - public void testValidateXHTMLPrefixes001() + public void testEPUBTypeFromSructureVocab() { - testValidateDocument("xhtml/valid/prefixes-001.xhtml", "application/xhtml+xml", + testValidateDocument("xhtml/valid/epubtype.xhtml", "application/xhtml+xml", EPUBVersion.VERSION_3); } @Test - public void testValidateXHTMLInvalidPrefixes001() + public void testEPUBTypeFromReservedVocab() { - Collections.addAll(expectedErrors, MessageId.OPF_028, MessageId.OPF_027); - testValidateDocument("xhtml/invalid/prefixes-001.xhtml", "application/xhtml+xml", + testValidateDocument("xhtml/valid/epubtype-reserved-vocab.xhtml", "application/xhtml+xml", + EPUBVersion.VERSION_3); + } + + @Test + public void testEPUBTypeFromDeclaredVocab() + { + testValidateDocument("xhtml/valid/epubtype-declared-vocab.xhtml", "application/xhtml+xml", + EPUBVersion.VERSION_3); + } + + @Test + public void testEPUBTypeUnknownIsIgnored() + { + expectedUsage.add(MessageId.OPF_088); + testValidateDocument("xhtml/valid/epubtype-unknown.xhtml", "application/xhtml+xml", + EPUBVersion.VERSION_3); + } + + @Test + public void testEPUBTypeDeprecated() + { + expectedWarnings.addAll(Collections.nCopies(10, MessageId.OPF_086)); + testValidateDocument("xhtml/invalid/epubtype-deprecated.xhtml", "application/xhtml+xml", + EPUBVersion.VERSION_3); + } + + @Test + public void testEPUBTypeDisallowed() + { + expectedErrors.addAll(Collections.nCopies(6, MessageId.OPF_087)); + testValidateDocument("xhtml/invalid/epubtype-disallowed.xhtml", "application/xhtml+xml", + EPUBVersion.VERSION_3); + } + + @Test + public void testEPUBTypeWithUndeclaredPrefix() + { + Collections.addAll(expectedErrors, MessageId.OPF_028); + testValidateDocument("xhtml/invalid/epubtype-prefix-undeclared.xhtml", "application/xhtml+xml", EPUBVersion.VERSION_3); } @@ -1202,11 +1240,9 @@ public void testValidTimes() @Test public void testInvalidTimes() { - // tests that one error is raised for each invalid time attribute in the test file - for (int i = 0; i < 25; i++) - { - expectedErrors.add(MessageId.RSC_005); - } + // tests that one error is raised for each invalid time attribute in the test + // file + expectedErrors.addAll(Collections.nCopies(25, MessageId.RSC_005)); testValidateDocument("xhtml/invalid/times.xhtml", "application/xhtml+xml", EPUBVersion.VERSION_3); } diff --git a/src/test/java/com/adobe/epubcheck/vocab/VocabTest.java b/src/test/java/com/adobe/epubcheck/vocab/VocabTest.java index de47da5bf..c8c0bbaf5 100644 --- a/src/test/java/com/adobe/epubcheck/vocab/VocabTest.java +++ b/src/test/java/com/adobe/epubcheck/vocab/VocabTest.java @@ -36,6 +36,9 @@ import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.messages.MessageId; +import com.adobe.epubcheck.opf.ValidationContext; +import com.adobe.epubcheck.opf.ValidationContext.ValidationContextBuilder; +import com.adobe.epubcheck.util.ThrowingResourceProvider; import com.adobe.epubcheck.util.ValidationReport; import com.adobe.epubcheck.util.outWriter; import com.google.common.base.CaseFormat; @@ -77,11 +80,53 @@ private static enum CAMEL private static final Vocab CAMEL_VOCAB = new EnumVocab(CAMEL.class, CaseFormat.LOWER_CAMEL, "http://example.org/camel#", "camel"); + private static enum DEPRECATED implements PropertyStatus + { + PROP; + + @Override + public boolean isAllowed(ValidationContext context) + { + return true; + } + + @Override + public boolean isDeprecated() + { + return true; + } + } + + private static final Vocab DEPRECATED_VOCAB = new EnumVocab(DEPRECATED.class, + "http://example.org/deprecated#", "deprecated"); + + private static enum DISALLOWED implements PropertyStatus + { + PROP; + + @Override + public boolean isAllowed(ValidationContext context) + { + return false; + } + + @Override + public boolean isDeprecated() + { + return false; + } + } + + private static final Vocab DISALLOWED_VOCAB = new EnumVocab(DISALLOWED.class, + "http://example.org/disallowed#", "disallowed"); + private static final Vocab BAZ_UNCHECKED_VOCAB = new UncheckedVocab( "http://example.org/number#baz", "baz"); - private static final Map PREDEF_VOCABS = ImmutableMap.of("", FOOBAR_VOCAB, "num", - NUMBERS_VOCAB, "baz", BAZ_UNCHECKED_VOCAB, "camel", CAMEL_VOCAB); + private static final Map PREDEF_VOCABS = ImmutableMap. builder() + .put("", FOOBAR_VOCAB).put("num", NUMBERS_VOCAB).put("baz", BAZ_UNCHECKED_VOCAB) + .put("camel", CAMEL_VOCAB).put("deprecated", DEPRECATED_VOCAB) + .put("disallowed", DISALLOWED_VOCAB).build(); private static final Map KNOWN_VOCABS = ImmutableMap.of( "http://example.org/foobar#", FOOBAR_VOCAB, "http://example.org/number#", NUMBERS_VOCAB, "http://example.org/number#baz", BAZ_UNCHECKED_VOCAB); @@ -91,6 +136,16 @@ private static enum CAMEL private List expectedErrors = Lists.newLinkedList(); private List expectedWarnings = Lists.newLinkedList(); private List expectedFatals = Lists.newLinkedList(); + private ValidationContext context; + private ValidationReport report; + + @Before + public void before() + { + report = new ValidationReport(VocabTest.class.getSimpleName()); + context = new ValidationContextBuilder().resourceProvider(new ThrowingResourceProvider()) + .report(report).build(); + } private Set testPropertyList(String value, Map vocabs) { @@ -99,19 +154,16 @@ private Set testPropertyList(String value, Map vocabs) private Set testPropertyList(String value, Map vocabs, boolean verbose) { - ValidationReport testReport = new ValidationReport(VocabTest.class.getSimpleName()); - - Set props = VocabUtil.parsePropertyList(value, vocabs, testReport, loc); + Set props = VocabUtil.parsePropertyList(value, vocabs, context, loc); if (verbose) { - outWriter.println(testReport); + outWriter.println(report); } - assertEquals("The error results do not match", expectedErrors, testReport.getErrorIds()); - assertEquals("The warning results do not match", expectedWarnings, testReport.getWarningIds()); - assertEquals("The fatal error results do not match", expectedFatals, - testReport.getFatalErrorIds()); + assertEquals("The error results do not match", expectedErrors, report.getErrorIds()); + assertEquals("The warning results do not match", expectedWarnings, report.getWarningIds()); + assertEquals("The fatal error results do not match", expectedFatals, report.getFatalErrorIds()); return props; } @@ -123,19 +175,17 @@ private Optional testProperty(String value, Map vocabs) private Optional testProperty(String value, Map vocabs, boolean verbose) { - ValidationReport testReport = new ValidationReport(VocabTest.class.getSimpleName()); - Optional prop = VocabUtil.parseProperty(value, vocabs, testReport, loc); + Optional prop = VocabUtil.parseProperty(value, vocabs, context, loc); if (verbose) { - outWriter.println(testReport); + outWriter.println(report); } - assertEquals("The error results do not match", expectedErrors, testReport.getErrorIds()); - assertEquals("The warning results do not match", expectedWarnings, testReport.getWarningIds()); - assertEquals("The fatal error results do not match", expectedFatals, - testReport.getFatalErrorIds()); + assertEquals("The error results do not match", expectedErrors, report.getErrorIds()); + assertEquals("The warning results do not match", expectedWarnings, report.getWarningIds()); + assertEquals("The fatal error results do not match", expectedFatals, report.getFatalErrorIds()); return prop; } @@ -208,6 +258,20 @@ public void testSingleInvalid() assertFalse(prop.isPresent()); } + @Test + public void testDeprecated() + { + expectedWarnings.add(MessageId.OPF_086); + testProperty("deprecated:prop", PREDEF_VOCABS); + } + + @Test + public void testDisallowed() + { + expectedErrors.add(MessageId.OPF_087); + testProperty("disallowed:prop", PREDEF_VOCABS); + } + @Test public void testList() { @@ -224,7 +288,7 @@ public void testMalformed() } @Test - public void testNotAllowed() + public void testUndefined() { expectedErrors.add(MessageId.OPF_027); expectedErrors.add(MessageId.OPF_027); diff --git a/src/test/resources/30/epub/invalid/edupub-pagination-nopagelist.epub b/src/test/resources/30/epub/invalid/edupub-pagination-nopagelist.epub index 4617c601b..814b9d4dc 100644 Binary files a/src/test/resources/30/epub/invalid/edupub-pagination-nopagelist.epub and b/src/test/resources/30/epub/invalid/edupub-pagination-nopagelist.epub differ diff --git a/src/test/resources/30/epub/invalid/edupub-pagination-nosource.epub b/src/test/resources/30/epub/invalid/edupub-pagination-nosource.epub index 95aa9f06c..fb10ee924 100644 Binary files a/src/test/resources/30/epub/invalid/edupub-pagination-nosource.epub and b/src/test/resources/30/epub/invalid/edupub-pagination-nosource.epub differ diff --git a/src/test/resources/30/epub/invalid/edupub-toc-missing-branches.epub b/src/test/resources/30/epub/invalid/edupub-toc-missing-branches.epub index 3b3c78a9a..f7572e105 100644 Binary files a/src/test/resources/30/epub/invalid/edupub-toc-missing-branches.epub and b/src/test/resources/30/epub/invalid/edupub-toc-missing-branches.epub differ diff --git a/src/test/resources/30/epub/valid/edupub-pagination.epub b/src/test/resources/30/epub/valid/edupub-pagination.epub index 04f03c3c3..215569dc7 100644 Binary files a/src/test/resources/30/epub/valid/edupub-pagination.epub and b/src/test/resources/30/epub/valid/edupub-pagination.epub differ diff --git a/src/test/resources/30/epub/valid/georgia-cfi.epub b/src/test/resources/30/epub/valid/georgia-cfi.epub index e2210d8fb..5779c3cff 100644 Binary files a/src/test/resources/30/epub/valid/georgia-cfi.epub and b/src/test/resources/30/epub/valid/georgia-cfi.epub differ diff --git a/src/test/resources/30/expanded/invalid/wasteland-otf/EPUB/wasteland-content.xhtml b/src/test/resources/30/expanded/invalid/wasteland-otf/EPUB/wasteland-content.xhtml index 5413e82c2..b7e555736 100644 --- a/src/test/resources/30/expanded/invalid/wasteland-otf/EPUB/wasteland-content.xhtml +++ b/src/test/resources/30/expanded/invalid/wasteland-otf/EPUB/wasteland-content.xhtml @@ -746,7 +746,7 @@
-
+

NOTES ON "THE WASTE LAND"

Not only the title, but the plan and a good deal of the incidental symbolism of the poem were suggested by Miss Jessie L. Weston's book on the Grail legend: @@ -761,19 +761,19 @@ certain references to vegetation ceremonies.

I. THE BURIAL OF THE DEAD

-
+

Line 20. Cf. Ezekiel 2:1.

-
+

23. Cf. Ecclesiastes 12:5.

-
+

31. V. Tristan und Isolde, i, verses 5-8.

-
+

42. Id. iii, verse 24.

-
+

46. I am not familiar with the exact constitution of the Tarot pack of cards, from which I have obviously departed to suit my own convenience. The Hanged Man, a member of the traditional pack, fits my purpose in two @@ -785,86 +785,86 @@ the Tarot pack) I associate, quite arbitrarily, with the Fisher King himself.

-
+

60. Cf. Baudelaire:

"Fourmillante cite;, cite; pleine de reves,
Ou le spectre en plein jour raccroche le passant."

-
+

63. Cf. Inferno, iii. 55-7.

"si lunga tratta
di gente, ch'io non avrei mai creduto
che morte tanta n'avesse disfatta."

-
+

64. Cf. Inferno, iv. 25-7:

"Quivi, secondo che per ascoltahre,
"non avea pianto, ma' che di sospiri,
"che l'aura eterna facevan tremare."

-
+

68. A phenomenon which I have often noticed.

-
+

74. Cf. the Dirge in Webster's White Devil .

-
+

76. V. Baudelaire, Preface to Fleurs du Mal.

II. A GAME OF CHESS

-
+

77. Cf. Antony and Cleopatra, II. ii., l. 190.

-
+

92. Laquearia. V. Aeneid, I. 726:

dependent lychni laquearibus aureis incensi, et noctem flammis
funalia vincunt.

-
+

98. Sylvan scene. V. Milton, Paradise Lost, iv. 140.

-
+

99. V. Ovid, Metamorphoses, vi, Philomela.

-
+

100. Cf. Part III, l. 204.

-
+

115. Cf. Part III, l. 195.

-
+

118. Cf. Webster:

"Is the wind in that door still?"

-
+

126. Cf. Part I, l. 37, 48.

-
+

138. Cf. the game of chess in Middleton's Women beware Women.

III. THE FIRE SERMON

-
+

176. V. Spenser, Prothalamion.

-
+

192. Cf. The Tempest, I. ii.

-
+

196. Cf. Marvell, To His Coy Mistress.

-
+

197. Cf. Day, Parliament of Bees:

@@ -877,19 +877,19 @@
-
+

199. I do not know the origin of the ballad from which these lines are taken: it was reported to me from Sydney, Australia.

-
+

202. V. Verlaine, Parsifal.

-
+

210. The currants were quoted at a price "cost insurance and freight to London"; and the Bill of Lading etc. were to be handed to the buyer upon payment of the sight draft.

-
+

218. Tiresias, although a mere spectator and not indeed a "character," is yet the most important personage in the poem, uniting all the rest. Just as the one-eyed merchant, seller of currants, melts into the Phoenician @@ -916,27 +916,27 @@

-
+

221. This may not appear as exact as Sappho's lines, but I had in mind the "longshore" or "dory" fisherman, who returns at nightfall.

-
+

253. V. Goldsmith, the song in The Vicar of Wakefield.

-
+

257. V. The Tempest, as above.

-
+

264. The interior of St. Magnus Martyr is to my mind one of the finest among Wren's interiors. See The Proposed Demolition of Nineteen City Churches (P. S. King & Son, Ltd.).

-
+

266. The Song of the (three) Thames-daughters begins here. From line 292 to 306 inclusive they speak in turn. V. Gutterdsammerung, III. i: the Rhine-daughters.

-
+

279. V. Froude, Elizabeth, Vol. I, ch. iv, letter of De Quadra to Philip of Spain:

@@ -953,25 +953,25 @@
-
+

293. Cf. Purgatorio, v. 133:

"Ricorditi di me, che son la Pia;
Siena mi fe', disfecemi Maremma."

-
+

307. V. St. Augustine's Confessions: "to Carthage then I came, where a cauldron of unholy loves sang all about mine ears."

-
+

308. The complete text of the Buddha's Fire Sermon (which corresponds in importance to the Sermon on the Mount) from which these words are taken, will be found translated in the late Henry Clarke Warren's Buddhism in Translation (Harvard Oriental Series). Mr. Warren was one of the great pioneers of Buddhist studies in the Occident.

-
+

309. From St. Augustine's Confessions again. The collocation of these two representatives of eastern and western asceticism, as the culmination of this part of the poem, is not an accident.

@@ -982,7 +982,7 @@

In the first part of Part V three themes are employed: the journey to Emmaus, the approach to the Chapel Perilous (see Miss Weston's book) and the present decay of eastern Europe.

-
+

357. This is Turdus aonalaschkae pallasii, the hermit-thrush which I have heard in Quebec County. Chapman says (Handbook of Birds of Eastern North America) "it is most at home in secluded woodland and thickety retreats. @@ -990,14 +990,14 @@ and sweetness of tone and exquisite modulation they are unequalled." Its "water-dripping song" is justly celebrated.

-
+

360. The following lines were stimulated by the account of one of the Antarctic expeditions (I forget which, but I think one of Shackleton's): it was related that the party of explorers, at the extremity of their strength, had the constant delusion that there was one more member than could actually be counted.

-
+

367-77. Cf. Hermann Hesse, Blick ins Chaos:

"Schon ist halb Europa, schon ist zumindest der halbe Osten Europas @@ -1008,20 +1008,20 @@ Trvnen."

-
+

402. "Datta, dayadhvam, damyata" (Give, sympathize, control). The fable of the meaning of the Thunder is found in the Brihadaranyaka-Upanishad, 5, 1. A translation is found in Deussen's Sechzig Upanishads des Veda, p. 489.

-
+

408. Cf. Webster, The White Devil, v. vi:

". . . they'll remarry
Ere the worm pierce your winding-sheet, ere the spider
Make a thin curtain for your epitaphs."

-
+

412. Cf. Inferno, xxxiii. 46:

"ed io sentii chiavar l'uscio di sotto
all'orribile torre."

@@ -1037,10 +1037,10 @@ soul."

-
+

425. V. Weston, From Ritual to Romance; chapter on the Fisher King.

-
+

428. V. Purgatorio, xxvi. 148.

"'Ara vos prec per aquella valor
'que vos guida al som de @@ -1048,16 +1048,16 @@ s'ascose nel foco che gli affina."

-
+

429. V. Pervigilium Veneris. Cf. Philomela in Parts II and III.

-
+

430. V. Gerard de Nerval, Sonnet El Desdichado.

-
+

432. V. Kyd's Spanish Tragedy.

-
+

434. Shantih. Repeated as here, a formal ending to an Upanishad. 'The Peace which passeth understanding' is a feeble translation of the content of this word.

diff --git a/src/test/resources/30/expanded/invalid/wasteland-otf/EPUB/wasteland-nav.xhtml b/src/test/resources/30/expanded/invalid/wasteland-otf/EPUB/wasteland-nav.xhtml index b45f2398b..66f120a0f 100644 --- a/src/test/resources/30/expanded/invalid/wasteland-otf/EPUB/wasteland-nav.xhtml +++ b/src/test/resources/30/expanded/invalid/wasteland-otf/EPUB/wasteland-nav.xhtml @@ -15,7 +15,7 @@
  • III. THE FIRE SERMON
  • IV. DEATH BY WATER
  • V. WHAT THE THUNDER SAID
  • -
  • NOTES ON "THE WASTE LAND"
  • +
  • NOTES ON "THE WASTE LAND"
  • -
    +

    NOTES ON "THE WASTE LAND"

    Not only the title, but the plan and a good deal of the incidental symbolism of the poem were suggested by Miss Jessie L. Weston's book on the Grail legend: @@ -774,19 +774,19 @@ certain references to vegetation ceremonies.

    I. THE BURIAL OF THE DEAD

    -
    +

    Line 20. Cf. Ezekiel 2:1.

    -
    +

    23. Cf. Ecclesiastes 12:5.

    -
    +

    31. V. Tristan und Isolde, i, verses 5-8.

    -
    +

    42. Id. iii, verse 24.

    -
    +

    46. I am not familiar with the exact constitution of the Tarot pack of cards, from which I have obviously departed to suit my own convenience. The Hanged Man, a member of the traditional pack, fits my purpose in two @@ -798,86 +798,86 @@ the Tarot pack) I associate, quite arbitrarily, with the Fisher King himself.

    -
    +

    60. Cf. Baudelaire:

    "Fourmillante cite;, cite; pleine de reves,
    Ou le spectre en plein jour raccroche le passant."

    -
    +

    63. Cf. Inferno, iii. 55-7.

    "si lunga tratta
    di gente, ch'io non avrei mai creduto
    che morte tanta n'avesse disfatta."

    -
    +

    64. Cf. Inferno, iv. 25-7:

    "Quivi, secondo che per ascoltahre,
    "non avea pianto, ma' che di sospiri,
    "che l'aura eterna facevan tremare."

    -
    +

    68. A phenomenon which I have often noticed.

    -
    +

    74. Cf. the Dirge in Webster's White Devil .

    -
    +

    76. V. Baudelaire, Preface to Fleurs du Mal.

    II. A GAME OF CHESS

    -
    +

    77. Cf. Antony and Cleopatra, II. ii., l. 190.

    -
    +

    92. Laquearia. V. Aeneid, I. 726:

    dependent lychni laquearibus aureis incensi, et noctem flammis
    funalia vincunt.

    -
    +

    98. Sylvan scene. V. Milton, Paradise Lost, iv. 140.

    -
    +

    99. V. Ovid, Metamorphoses, vi, Philomela.

    -
    +

    100. Cf. Part III, l. 204.

    -
    +

    115. Cf. Part III, l. 195.

    -
    +

    118. Cf. Webster:

    "Is the wind in that door still?"

    -
    +

    126. Cf. Part I, l. 37, 48.

    -
    +

    138. Cf. the game of chess in Middleton's Women beware Women.

    III. THE FIRE SERMON

    -
    +

    176. V. Spenser, Prothalamion.

    -
    +

    192. Cf. The Tempest, I. ii.

    -
    +

    196. Cf. Marvell, To His Coy Mistress.

    -
    +

    197. Cf. Day, Parliament of Bees:

    @@ -890,19 +890,19 @@
    -
    +

    199. I do not know the origin of the ballad from which these lines are taken: it was reported to me from Sydney, Australia.

    -
    +

    202. V. Verlaine, Parsifal.

    -
    +

    210. The currants were quoted at a price "cost insurance and freight to London"; and the Bill of Lading etc. were to be handed to the buyer upon payment of the sight draft.

    -
    +

    218. Tiresias, although a mere spectator and not indeed a "character," is yet the most important personage in the poem, uniting all the rest. Just as the one-eyed merchant, seller of currants, melts into the Phoenician @@ -929,27 +929,27 @@

    -
    +

    221. This may not appear as exact as Sappho's lines, but I had in mind the "longshore" or "dory" fisherman, who returns at nightfall.

    -
    +

    253. V. Goldsmith, the song in The Vicar of Wakefield.

    -
    +

    257. V. The Tempest, as above.

    -
    +

    264. The interior of St. Magnus Martyr is to my mind one of the finest among Wren's interiors. See The Proposed Demolition of Nineteen City Churches (P. S. King & Son, Ltd.).

    -
    +

    266. The Song of the (three) Thames-daughters begins here. From line 292 to 306 inclusive they speak in turn. V. Gutterdsammerung, III. i: the Rhine-daughters.

    -
    +

    279. V. Froude, Elizabeth, Vol. I, ch. iv, letter of De Quadra to Philip of Spain:

    @@ -966,25 +966,25 @@
    -
    +

    293. Cf. Purgatorio, v. 133:

    "Ricorditi di me, che son la Pia;
    Siena mi fe', disfecemi Maremma."

    -
    +

    307. V. St. Augustine's Confessions: "to Carthage then I came, where a cauldron of unholy loves sang all about mine ears."

    -
    +

    308. The complete text of the Buddha's Fire Sermon (which corresponds in importance to the Sermon on the Mount) from which these words are taken, will be found translated in the late Henry Clarke Warren's Buddhism in Translation (Harvard Oriental Series). Mr. Warren was one of the great pioneers of Buddhist studies in the Occident.

    -
    +

    309. From St. Augustine's Confessions again. The collocation of these two representatives of eastern and western asceticism, as the culmination of this part of the poem, is not an accident.

    @@ -995,7 +995,7 @@

    In the first part of Part V three themes are employed: the journey to Emmaus, the approach to the Chapel Perilous (see Miss Weston's book) and the present decay of eastern Europe.

    -
    +

    357. This is Turdus aonalaschkae pallasii, the hermit-thrush which I have heard in Quebec County. Chapman says (Handbook of Birds of Eastern North America) "it is most at home in secluded woodland and thickety retreats. @@ -1003,14 +1003,14 @@ and sweetness of tone and exquisite modulation they are unequalled." Its "water-dripping song" is justly celebrated.

    -
    +

    360. The following lines were stimulated by the account of one of the Antarctic expeditions (I forget which, but I think one of Shackleton's): it was related that the party of explorers, at the extremity of their strength, had the constant delusion that there was one more member than could actually be counted.

    -
    +

    367-77. Cf. Hermann Hesse, Blick ins Chaos:

    "Schon ist halb Europa, schon ist zumindest der halbe Osten Europas @@ -1021,20 +1021,20 @@ Trvnen."

    -
    +

    402. "Datta, dayadhvam, damyata" (Give, sympathize, control). The fable of the meaning of the Thunder is found in the Brihadaranyaka-Upanishad, 5, 1. A translation is found in Deussen's Sechzig Upanishads des Veda, p. 489.

    -
    +

    408. Cf. Webster, The White Devil, v. vi:

    ". . . they'll remarry
    Ere the worm pierce your winding-sheet, ere the spider
    Make a thin curtain for your epitaphs."

    -
    +

    412. Cf. Inferno, xxxiii. 46:

    "ed io sentii chiavar l'uscio di sotto
    all'orribile torre."

    @@ -1050,10 +1050,10 @@ soul."

    -
    +

    425. V. Weston, From Ritual to Romance; chapter on the Fisher King.

    -
    +

    428. V. Purgatorio, xxvi. 148.

    "'Ara vos prec per aquella valor
    'que vos guida al som de @@ -1061,16 +1061,16 @@ s'ascose nel foco che gli affina."

    -
    +

    429. V. Pervigilium Veneris. Cf. Philomela in Parts II and III.

    -
    +

    430. V. Gerard de Nerval, Sonnet El Desdichado.

    -
    +

    432. V. Kyd's Spanish Tragedy.

    -
    +

    434. Shantih. Repeated as here, a formal ending to an Upanishad. 'The Peace which passeth understanding' is a feeble translation of the content of this word.

    diff --git a/src/test/resources/30/expanded/valid/wasteland-basic/EPUB/wasteland-content.xhtml b/src/test/resources/30/expanded/valid/wasteland-basic/EPUB/wasteland-content.xhtml index f46dbe3a7..5ef2c7d0e 100644 --- a/src/test/resources/30/expanded/valid/wasteland-basic/EPUB/wasteland-content.xhtml +++ b/src/test/resources/30/expanded/valid/wasteland-basic/EPUB/wasteland-content.xhtml @@ -744,7 +744,7 @@
    -
    +

    NOTES ON "THE WASTE LAND"

    Not only the title, but the plan and a good deal of the incidental symbolism of the poem were suggested by Miss Jessie L. Weston's book on the Grail legend: @@ -759,19 +759,19 @@ certain references to vegetation ceremonies.

    I. THE BURIAL OF THE DEAD

    -
    +

    Line 20. Cf. Ezekiel 2:1.

    -
    +

    23. Cf. Ecclesiastes 12:5.

    -
    +

    31. V. Tristan und Isolde, i, verses 5-8.

    -
    +

    42. Id. iii, verse 24.

    -
    +

    46. I am not familiar with the exact constitution of the Tarot pack of cards, from which I have obviously departed to suit my own convenience. The Hanged Man, a member of the traditional pack, fits my purpose in two @@ -783,86 +783,86 @@ the Tarot pack) I associate, quite arbitrarily, with the Fisher King himself.

    -
    +

    60. Cf. Baudelaire:

    "Fourmillante cite;, cite; pleine de reves,
    Ou le spectre en plein jour raccroche le passant."

    -
    +

    63. Cf. Inferno, iii. 55-7.

    "si lunga tratta
    di gente, ch'io non avrei mai creduto
    che morte tanta n'avesse disfatta."

    -
    +

    64. Cf. Inferno, iv. 25-7:

    "Quivi, secondo che per ascoltahre,
    "non avea pianto, ma' che di sospiri,
    "che l'aura eterna facevan tremare."

    -
    +

    68. A phenomenon which I have often noticed.

    -
    +

    74. Cf. the Dirge in Webster's White Devil .

    -
    +

    76. V. Baudelaire, Preface to Fleurs du Mal.

    II. A GAME OF CHESS

    -
    +

    77. Cf. Antony and Cleopatra, II. ii., l. 190.

    -
    +

    92. Laquearia. V. Aeneid, I. 726:

    dependent lychni laquearibus aureis incensi, et noctem flammis
    funalia vincunt.

    -
    +

    98. Sylvan scene. V. Milton, Paradise Lost, iv. 140.

    -
    +

    99. V. Ovid, Metamorphoses, vi, Philomela.

    -
    +

    100. Cf. Part III, l. 204.

    -
    +

    115. Cf. Part III, l. 195.

    -
    +

    118. Cf. Webster:

    "Is the wind in that door still?"

    -
    +

    126. Cf. Part I, l. 37, 48.

    -
    +

    138. Cf. the game of chess in Middleton's Women beware Women.

    III. THE FIRE SERMON

    -
    +

    176. V. Spenser, Prothalamion.

    -
    +

    192. Cf. The Tempest, I. ii.

    -
    +

    196. Cf. Marvell, To His Coy Mistress.

    -
    +

    197. Cf. Day, Parliament of Bees:

    @@ -875,19 +875,19 @@
    -
    +

    199. I do not know the origin of the ballad from which these lines are taken: it was reported to me from Sydney, Australia.

    -
    +

    202. V. Verlaine, Parsifal.

    -
    +

    210. The currants were quoted at a price "cost insurance and freight to London"; and the Bill of Lading etc. were to be handed to the buyer upon payment of the sight draft.

    -
    +

    218. Tiresias, although a mere spectator and not indeed a "character," is yet the most important personage in the poem, uniting all the rest. Just as the one-eyed merchant, seller of currants, melts into the Phoenician @@ -914,27 +914,27 @@

    -
    +

    221. This may not appear as exact as Sappho's lines, but I had in mind the "longshore" or "dory" fisherman, who returns at nightfall.

    -
    +

    253. V. Goldsmith, the song in The Vicar of Wakefield.

    -
    +

    257. V. The Tempest, as above.

    -
    +

    264. The interior of St. Magnus Martyr is to my mind one of the finest among Wren's interiors. See The Proposed Demolition of Nineteen City Churches (P. S. King & Son, Ltd.).

    -
    +

    266. The Song of the (three) Thames-daughters begins here. From line 292 to 306 inclusive they speak in turn. V. Gutterdsammerung, III. i: the Rhine-daughters.

    -
    +

    279. V. Froude, Elizabeth, Vol. I, ch. iv, letter of De Quadra to Philip of Spain:

    @@ -951,25 +951,25 @@
    -
    +

    293. Cf. Purgatorio, v. 133:

    "Ricorditi di me, che son la Pia;
    Siena mi fe', disfecemi Maremma."

    -
    +

    307. V. St. Augustine's Confessions: "to Carthage then I came, where a cauldron of unholy loves sang all about mine ears."

    -
    +

    308. The complete text of the Buddha's Fire Sermon (which corresponds in importance to the Sermon on the Mount) from which these words are taken, will be found translated in the late Henry Clarke Warren's Buddhism in Translation (Harvard Oriental Series). Mr. Warren was one of the great pioneers of Buddhist studies in the Occident.

    -
    +

    309. From St. Augustine's Confessions again. The collocation of these two representatives of eastern and western asceticism, as the culmination of this part of the poem, is not an accident.

    @@ -980,7 +980,7 @@

    In the first part of Part V three themes are employed: the journey to Emmaus, the approach to the Chapel Perilous (see Miss Weston's book) and the present decay of eastern Europe.

    -
    +

    357. This is Turdus aonalaschkae pallasii, the hermit-thrush which I have heard in Quebec County. Chapman says (Handbook of Birds of Eastern North America) "it is most at home in secluded woodland and thickety retreats. @@ -988,14 +988,14 @@ and sweetness of tone and exquisite modulation they are unequalled." Its "water-dripping song" is justly celebrated.

    -
    +

    360. The following lines were stimulated by the account of one of the Antarctic expeditions (I forget which, but I think one of Shackleton's): it was related that the party of explorers, at the extremity of their strength, had the constant delusion that there was one more member than could actually be counted.

    -
    +

    367-77. Cf. Hermann Hesse, Blick ins Chaos:

    "Schon ist halb Europa, schon ist zumindest der halbe Osten Europas @@ -1006,20 +1006,20 @@ Trvnen."

    -
    +

    402. "Datta, dayadhvam, damyata" (Give, sympathize, control). The fable of the meaning of the Thunder is found in the Brihadaranyaka-Upanishad, 5, 1. A translation is found in Deussen's Sechzig Upanishads des Veda, p. 489.

    -
    +

    408. Cf. Webster, The White Devil, v. vi:

    ". . . they'll remarry
    Ere the worm pierce your winding-sheet, ere the spider
    Make a thin curtain for your epitaphs."

    -
    +

    412. Cf. Inferno, xxxiii. 46:

    "ed io sentii chiavar l'uscio di sotto
    all'orribile torre."

    @@ -1035,10 +1035,10 @@ soul."

    -
    +

    425. V. Weston, From Ritual to Romance; chapter on the Fisher King.

    -
    +

    428. V. Purgatorio, xxvi. 148.

    "'Ara vos prec per aquella valor
    'que vos guida al som de @@ -1046,16 +1046,16 @@ s'ascose nel foco che gli affina."

    -
    +

    429. V. Pervigilium Veneris. Cf. Philomela in Parts II and III.

    -
    +

    430. V. Gerard de Nerval, Sonnet El Desdichado.

    -
    +

    432. V. Kyd's Spanish Tragedy.

    -
    +

    434. Shantih. Repeated as here, a formal ending to an Upanishad. 'The Peace which passeth understanding' is a feeble translation of the content of this word.

    diff --git a/src/test/resources/30/expanded/valid/wasteland-otf/EPUB/wasteland-content.xhtml b/src/test/resources/30/expanded/valid/wasteland-otf/EPUB/wasteland-content.xhtml index 5413e82c2..b7e555736 100644 --- a/src/test/resources/30/expanded/valid/wasteland-otf/EPUB/wasteland-content.xhtml +++ b/src/test/resources/30/expanded/valid/wasteland-otf/EPUB/wasteland-content.xhtml @@ -746,7 +746,7 @@
    -
    +

    NOTES ON "THE WASTE LAND"

    Not only the title, but the plan and a good deal of the incidental symbolism of the poem were suggested by Miss Jessie L. Weston's book on the Grail legend: @@ -761,19 +761,19 @@ certain references to vegetation ceremonies.

    I. THE BURIAL OF THE DEAD

    -
    +

    Line 20. Cf. Ezekiel 2:1.

    -
    +

    23. Cf. Ecclesiastes 12:5.

    -
    +

    31. V. Tristan und Isolde, i, verses 5-8.

    -
    +

    42. Id. iii, verse 24.

    -
    +

    46. I am not familiar with the exact constitution of the Tarot pack of cards, from which I have obviously departed to suit my own convenience. The Hanged Man, a member of the traditional pack, fits my purpose in two @@ -785,86 +785,86 @@ the Tarot pack) I associate, quite arbitrarily, with the Fisher King himself.

    -
    +

    60. Cf. Baudelaire:

    "Fourmillante cite;, cite; pleine de reves,
    Ou le spectre en plein jour raccroche le passant."

    -
    +

    63. Cf. Inferno, iii. 55-7.

    "si lunga tratta
    di gente, ch'io non avrei mai creduto
    che morte tanta n'avesse disfatta."

    -
    +

    64. Cf. Inferno, iv. 25-7:

    "Quivi, secondo che per ascoltahre,
    "non avea pianto, ma' che di sospiri,
    "che l'aura eterna facevan tremare."

    -
    +

    68. A phenomenon which I have often noticed.

    -
    +

    74. Cf. the Dirge in Webster's White Devil .

    -
    +

    76. V. Baudelaire, Preface to Fleurs du Mal.

    II. A GAME OF CHESS

    -
    +

    77. Cf. Antony and Cleopatra, II. ii., l. 190.

    -
    +

    92. Laquearia. V. Aeneid, I. 726:

    dependent lychni laquearibus aureis incensi, et noctem flammis
    funalia vincunt.

    -
    +

    98. Sylvan scene. V. Milton, Paradise Lost, iv. 140.

    -
    +

    99. V. Ovid, Metamorphoses, vi, Philomela.

    -
    +

    100. Cf. Part III, l. 204.

    -
    +

    115. Cf. Part III, l. 195.

    -
    +

    118. Cf. Webster:

    "Is the wind in that door still?"

    -
    +

    126. Cf. Part I, l. 37, 48.

    -
    +

    138. Cf. the game of chess in Middleton's Women beware Women.

    III. THE FIRE SERMON

    -
    +

    176. V. Spenser, Prothalamion.

    -
    +

    192. Cf. The Tempest, I. ii.

    -
    +

    196. Cf. Marvell, To His Coy Mistress.

    -
    +

    197. Cf. Day, Parliament of Bees:

    @@ -877,19 +877,19 @@
    -
    +

    199. I do not know the origin of the ballad from which these lines are taken: it was reported to me from Sydney, Australia.

    -
    +

    202. V. Verlaine, Parsifal.

    -
    +

    210. The currants were quoted at a price "cost insurance and freight to London"; and the Bill of Lading etc. were to be handed to the buyer upon payment of the sight draft.

    -
    +

    218. Tiresias, although a mere spectator and not indeed a "character," is yet the most important personage in the poem, uniting all the rest. Just as the one-eyed merchant, seller of currants, melts into the Phoenician @@ -916,27 +916,27 @@

    -
    +

    221. This may not appear as exact as Sappho's lines, but I had in mind the "longshore" or "dory" fisherman, who returns at nightfall.

    -
    +

    253. V. Goldsmith, the song in The Vicar of Wakefield.

    -
    +

    257. V. The Tempest, as above.

    -
    +

    264. The interior of St. Magnus Martyr is to my mind one of the finest among Wren's interiors. See The Proposed Demolition of Nineteen City Churches (P. S. King & Son, Ltd.).

    -
    +

    266. The Song of the (three) Thames-daughters begins here. From line 292 to 306 inclusive they speak in turn. V. Gutterdsammerung, III. i: the Rhine-daughters.

    -
    +

    279. V. Froude, Elizabeth, Vol. I, ch. iv, letter of De Quadra to Philip of Spain:

    @@ -953,25 +953,25 @@
    -
    +

    293. Cf. Purgatorio, v. 133:

    "Ricorditi di me, che son la Pia;
    Siena mi fe', disfecemi Maremma."

    -
    +

    307. V. St. Augustine's Confessions: "to Carthage then I came, where a cauldron of unholy loves sang all about mine ears."

    -
    +

    308. The complete text of the Buddha's Fire Sermon (which corresponds in importance to the Sermon on the Mount) from which these words are taken, will be found translated in the late Henry Clarke Warren's Buddhism in Translation (Harvard Oriental Series). Mr. Warren was one of the great pioneers of Buddhist studies in the Occident.

    -
    +

    309. From St. Augustine's Confessions again. The collocation of these two representatives of eastern and western asceticism, as the culmination of this part of the poem, is not an accident.

    @@ -982,7 +982,7 @@

    In the first part of Part V three themes are employed: the journey to Emmaus, the approach to the Chapel Perilous (see Miss Weston's book) and the present decay of eastern Europe.

    -
    +

    357. This is Turdus aonalaschkae pallasii, the hermit-thrush which I have heard in Quebec County. Chapman says (Handbook of Birds of Eastern North America) "it is most at home in secluded woodland and thickety retreats. @@ -990,14 +990,14 @@ and sweetness of tone and exquisite modulation they are unequalled." Its "water-dripping song" is justly celebrated.

    -
    +

    360. The following lines were stimulated by the account of one of the Antarctic expeditions (I forget which, but I think one of Shackleton's): it was related that the party of explorers, at the extremity of their strength, had the constant delusion that there was one more member than could actually be counted.

    -
    +

    367-77. Cf. Hermann Hesse, Blick ins Chaos:

    "Schon ist halb Europa, schon ist zumindest der halbe Osten Europas @@ -1008,20 +1008,20 @@ Trvnen."

    -
    +

    402. "Datta, dayadhvam, damyata" (Give, sympathize, control). The fable of the meaning of the Thunder is found in the Brihadaranyaka-Upanishad, 5, 1. A translation is found in Deussen's Sechzig Upanishads des Veda, p. 489.

    -
    +

    408. Cf. Webster, The White Devil, v. vi:

    ". . . they'll remarry
    Ere the worm pierce your winding-sheet, ere the spider
    Make a thin curtain for your epitaphs."

    -
    +

    412. Cf. Inferno, xxxiii. 46:

    "ed io sentii chiavar l'uscio di sotto
    all'orribile torre."

    @@ -1037,10 +1037,10 @@ soul."

    -
    +

    425. V. Weston, From Ritual to Romance; chapter on the Fisher King.

    -
    +

    428. V. Purgatorio, xxvi. 148.

    "'Ara vos prec per aquella valor
    'que vos guida al som de @@ -1048,16 +1048,16 @@ s'ascose nel foco che gli affina."

    -
    +

    429. V. Pervigilium Veneris. Cf. Philomela in Parts II and III.

    -
    +

    430. V. Gerard de Nerval, Sonnet El Desdichado.

    -
    +

    432. V. Kyd's Spanish Tragedy.

    -
    +

    434. Shantih. Repeated as here, a formal ending to an Upanishad. 'The Peace which passeth understanding' is a feeble translation of the content of this word.

    diff --git a/src/test/resources/30/expanded/valid/wasteland-otf/EPUB/wasteland-nav.xhtml b/src/test/resources/30/expanded/valid/wasteland-otf/EPUB/wasteland-nav.xhtml index b45f2398b..66f120a0f 100644 --- a/src/test/resources/30/expanded/valid/wasteland-otf/EPUB/wasteland-nav.xhtml +++ b/src/test/resources/30/expanded/valid/wasteland-otf/EPUB/wasteland-nav.xhtml @@ -15,7 +15,7 @@
  • III. THE FIRE SERMON
  • IV. DEATH BY WATER
  • V. WHAT THE THUNDER SAID
  • -
  • NOTES ON "THE WASTE LAND"
  • +
  • NOTES ON "THE WASTE LAND"