Skip to content

Commit

Permalink
feat: update Package vocabularies and link element checks
Browse files Browse the repository at this point in the history
Fix #883, Fix #884, Fix #885, Fix #886, Fix #887

Vocabulary Changes:

- Declare the Package Document default vocabularies with their unique URIs
  - `meta` element properties: http://idpf.org/epub/vocab/package/meta/#
  - `link` element rel and properties: http://idpf.org/epub/vocab/package/link/#
  - `item` element properties: http://idpf.org/epub/vocab/package/item/#
  - `itemref` element properties: http://idpf.org/epub/vocab/package/itemref/#
- Define 'onix' and 'xmp' as the only valid unprefixed properties on
  `link` elements.
- Recognize 'acquire' and 'alternate' as valid link rel keywords.
- Deprecate the following link rel keywords: 'marc21xml-record',
  'mods-record', 'onix-record', 'xml-signature', and 'xmp-record'.

New messages:

- `OPF-089` (`ERROR`) is reported when the 'alternate' link rel keyword
  is not the only keyword in a `link` element `rel` attribute.
- Add replacement suggestions for deprecated link rel keywords (`OPF-086`).

Tests:

- add more tests on 'record' links.
- minimize various existing `link`-related tests.
  • Loading branch information
rdeltour committed Feb 8, 2019
1 parent 9965c19 commit 99f882a
Show file tree
Hide file tree
Showing 29 changed files with 409 additions and 159 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ private void initialize()
severities.put(MessageId.OPF_086, Severity.WARNING);
severities.put(MessageId.OPF_087, Severity.ERROR);
severities.put(MessageId.OPF_088, Severity.USAGE);
severities.put(MessageId.OPF_089, Severity.ERROR);

// PKG
severities.put(MessageId.PKG_001, Severity.WARNING);
Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/adobe/epubcheck/messages/MessageId.java
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ public enum MessageId implements Comparable<MessageId>
OPF_086("OPF-086"),
OPF_087("OPF-087"),
OPF_088("OPF-088"),
OPF_089("OPF-089"),

// Messages relating to the entire package
PKG_001("PKG-001"),
Expand Down
55 changes: 44 additions & 11 deletions src/main/java/com/adobe/epubcheck/opf/OPFHandler30.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,14 @@
import static com.adobe.epubcheck.vocab.ForeignVocabs.XSD_URI;
import static com.adobe.epubcheck.vocab.ForeignVocabs.XSD_VOCAB;
import static com.adobe.epubcheck.vocab.PackageVocabs.ITEMREF_VOCAB;
import static com.adobe.epubcheck.vocab.PackageVocabs.ITEMREF_VOCAB_URI;
import static com.adobe.epubcheck.vocab.PackageVocabs.ITEM_VOCAB;
import static com.adobe.epubcheck.vocab.PackageVocabs.ITEM_VOCAB_URI;
import static com.adobe.epubcheck.vocab.PackageVocabs.LINKREL_VOCAB;
import static com.adobe.epubcheck.vocab.PackageVocabs.LINKREL_VOCAB_URI;
import static com.adobe.epubcheck.vocab.PackageVocabs.LINK_VOCAB;
import static com.adobe.epubcheck.vocab.PackageVocabs.LINK_VOCAB_URI;
import static com.adobe.epubcheck.vocab.PackageVocabs.META_VOCAB;
import static com.adobe.epubcheck.vocab.PackageVocabs.PACKAGE_VOCAB_URI;
import static com.adobe.epubcheck.vocab.PackageVocabs.META_VOCAB_URI;

import java.net.URI;
import java.net.URISyntaxException;
Expand All @@ -64,6 +67,7 @@
import com.adobe.epubcheck.vocab.EpubCheckVocab;
import com.adobe.epubcheck.vocab.MediaOverlaysVocab;
import com.adobe.epubcheck.vocab.PackageVocabs.ITEM_PROPERTIES;
import com.adobe.epubcheck.vocab.PackageVocabs.LINKREL_PROPERTIES;
import com.adobe.epubcheck.vocab.Property;
import com.adobe.epubcheck.vocab.RenditionVocabs;
import com.adobe.epubcheck.vocab.ScriptedCompVocab;
Expand All @@ -88,8 +92,7 @@ public class OPFHandler30 extends OPFHandler
private static final Map<String, Vocab> RESERVED_META_VOCABS = new ImmutableMap.Builder<String, Vocab>()
.put("", META_VOCAB).put(AccessibilityVocab.PREFIX, AccessibilityVocab.META_VOCAB)
.put(MediaOverlaysVocab.PREFIX, MediaOverlaysVocab.VOCAB)
.put(RenditionVocabs.PREFIX, RenditionVocabs.META_VOCAB)
.putAll(RESERVED_VOCABS).build();
.put(RenditionVocabs.PREFIX, RenditionVocabs.META_VOCAB).putAll(RESERVED_VOCABS).build();
private static final Map<String, Vocab> RESERVED_ITEM_VOCABS = new ImmutableMap.Builder<String, Vocab>()
.put("", ITEM_VOCAB).put(MediaOverlaysVocab.PREFIX, VocabUtil.EMPTY_VOCAB)
.put(RenditionVocabs.PREFIX, VocabUtil.EMPTY_VOCAB).putAll(RESERVED_VOCABS).build();
Expand All @@ -100,6 +103,10 @@ public class OPFHandler30 extends OPFHandler
.put("", LINKREL_VOCAB).put(AccessibilityVocab.PREFIX, AccessibilityVocab.LINKREL_VOCAB)
.put(MediaOverlaysVocab.PREFIX, VocabUtil.EMPTY_VOCAB)
.put(RenditionVocabs.PREFIX, VocabUtil.EMPTY_VOCAB).putAll(RESERVED_VOCABS).build();
private static final Map<String, Vocab> RESERVED_LINK_VOCABS = new ImmutableMap.Builder<String, Vocab>()
.put("", LINK_VOCAB).put(AccessibilityVocab.PREFIX, VocabUtil.EMPTY_VOCAB)
.put(MediaOverlaysVocab.PREFIX, VocabUtil.EMPTY_VOCAB)
.put(RenditionVocabs.PREFIX, VocabUtil.EMPTY_VOCAB).putAll(RESERVED_VOCABS).build();

private static final Map<String, Vocab> KNOWN_VOCAB_URIS = new ImmutableMap.Builder<String, Vocab>()
.put(DCTERMS_URI, DCTERMS_VOCAB).put(MARC_URI, MARC_VOCAB).put(ONIX_URI, ONIX_VOCAB)
Expand All @@ -110,24 +117,34 @@ public class OPFHandler30 extends OPFHandler
.put(RenditionVocabs.URI, RenditionVocabs.META_VOCAB)
.put(ScriptedCompVocab.URI, ScriptedCompVocab.VOCAB).build();
private static final Map<String, Vocab> KNOWN_ITEM_VOCAB_URIS = new ImmutableMap.Builder<String, Vocab>()
.putAll(KNOWN_VOCAB_URIS).put(MediaOverlaysVocab.URI, VocabUtil.EMPTY_VOCAB)
.put(RenditionVocabs.URI, VocabUtil.EMPTY_VOCAB).build();
.putAll(KNOWN_VOCAB_URIS).put(AccessibilityVocab.URI, VocabUtil.EMPTY_VOCAB)
.put(MediaOverlaysVocab.URI, VocabUtil.EMPTY_VOCAB)
.put(RenditionVocabs.URI, VocabUtil.EMPTY_VOCAB)
.put(ScriptedCompVocab.URI, VocabUtil.EMPTY_VOCAB).build();
private static final Map<String, Vocab> KNOWN_ITEMREF_VOCAB_URIS = new ImmutableMap.Builder<String, Vocab>()
.putAll(KNOWN_VOCAB_URIS).put(MediaOverlaysVocab.URI, VocabUtil.EMPTY_VOCAB)
.putAll(KNOWN_VOCAB_URIS).put(AccessibilityVocab.URI, VocabUtil.EMPTY_VOCAB)
.put(MediaOverlaysVocab.URI, VocabUtil.EMPTY_VOCAB)
.put(RenditionVocabs.URI, RenditionVocabs.ITEMREF_VOCAB).build();
private static final Map<String, Vocab> KNOWN_LINK_VOCAB_URIS = new ImmutableMap.Builder<String, Vocab>()
.putAll(KNOWN_VOCAB_URIS).put(AccessibilityVocab.URI, VocabUtil.EMPTY_VOCAB)
.put(MediaOverlaysVocab.URI, VocabUtil.EMPTY_VOCAB)
.put(RenditionVocabs.URI, VocabUtil.EMPTY_VOCAB)
.put(ScriptedCompVocab.URI, VocabUtil.EMPTY_VOCAB).build();
private static final Map<String, Vocab> KNOWN_LINKREL_VOCAB_URIS = new ImmutableMap.Builder<String, Vocab>()
.putAll(KNOWN_VOCAB_URIS).put(AccessibilityVocab.URI, AccessibilityVocab.LINKREL_VOCAB)
.put(MediaOverlaysVocab.URI, VocabUtil.EMPTY_VOCAB)
.put(RenditionVocabs.URI, VocabUtil.EMPTY_VOCAB).build();
.put(RenditionVocabs.URI, VocabUtil.EMPTY_VOCAB)
.put(ScriptedCompVocab.URI, VocabUtil.EMPTY_VOCAB).build();

private static final Set<String> DEFAULT_VOCAB_URIS = ImmutableSet.of(PACKAGE_VOCAB_URI,
LINKREL_VOCAB_URI);
private static final Set<String> DEFAULT_VOCAB_URIS = ImmutableSet.of(ITEM_VOCAB_URI,
ITEMREF_VOCAB_URI, META_VOCAB_URI, LINK_VOCAB_URI);

private static final Splitter TOKENIZER = Splitter.onPattern("\\s+");

private Map<String, Vocab> itemrefVocabs;
private Map<String, Vocab> itemVocabs;
private Map<String, Vocab> metaVocabs;
private Map<String, Vocab> linkVocabs;
private Map<String, Vocab> linkrelVocabs;
private final Deque<MetadataSet.Builder> metadataBuilders = Lists.newLinkedList();
private MetadataSet metadata = null;
Expand Down Expand Up @@ -174,6 +191,8 @@ public void startElement()
KNOWN_ITEMREF_VOCAB_URIS, DEFAULT_VOCAB_URIS, QuietReport.INSTANCE, loc);
linkrelVocabs = VocabUtil.parsePrefixDeclaration(prefixDecl, RESERVED_LINKREL_VOCABS,
KNOWN_LINKREL_VOCAB_URIS, DEFAULT_VOCAB_URIS, QuietReport.INSTANCE, loc);
linkVocabs = VocabUtil.parsePrefixDeclaration(prefixDecl, RESERVED_LINK_VOCABS,
KNOWN_LINK_VOCAB_URIS, DEFAULT_VOCAB_URIS, QuietReport.INSTANCE, loc);
}
else if (name.equals("metadata"))
{
Expand Down Expand Up @@ -444,6 +463,7 @@ private void processLink(XMLElement e)

if (!linkedResourcesBuilders.isEmpty())
{
processLinkProperties(e.getAttribute("properties"));
LinkedResource resource = new LinkedResource.Builder(href).id(e.getAttribute("id"))
.rel(processLinkRel(e.getAttribute("rel"))).mimetype(e.getAttribute("media-type"))
.refines(e.getAttribute("refines")).build();
Expand Down Expand Up @@ -506,10 +526,23 @@ private void processItemProperties(OPFItem.Builder builder, String property, Str
builder.properties(properties);
}

private Set<Property> processLinkProperties(String properties)
{
return VocabUtil.parsePropertyList(properties, linkVocabs, context,
EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber()));
}

private Set<Property> processLinkRel(String rel)
{
return VocabUtil.parsePropertyList(rel, linkrelVocabs, context,
Set<Property> linkRelProperties = VocabUtil.parsePropertyList(rel, linkrelVocabs, context,
EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber()));
if (Property.filter(linkRelProperties, LINKREL_PROPERTIES.class)
.contains(LINKREL_PROPERTIES.ALTERNATE) && linkRelProperties.size() > 1)
{
report.message(MessageId.OPF_089,
EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber()));
}
return linkRelProperties;
}

private void processMeta(XMLElement e)
Expand Down
63 changes: 50 additions & 13 deletions src/main/java/com/adobe/epubcheck/vocab/PackageVocabs.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,20 @@

import java.util.Set;

import com.adobe.epubcheck.opf.ValidationContext;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;

public final class PackageVocabs
{

public static final String PACKAGE_VOCAB_URI = "http://idpf.org/epub/vocab/package/#";
public static final String ITEM_VOCAB_URI = "http://idpf.org/epub/vocab/package/item/#";
public static final String ITEMREF_VOCAB_URI = "http://idpf.org/epub/vocab/package/itemref/#";
public static final String LINK_VOCAB_URI = "http://idpf.org/epub/vocab/package/link/#";
public static final String META_VOCAB_URI = "http://idpf.org/epub/vocab/package/meta/#";

public static EnumVocab<META_PROPERTIES> META_VOCAB = new EnumVocab<META_PROPERTIES>(
META_PROPERTIES.class, PACKAGE_VOCAB_URI);
META_PROPERTIES.class, META_VOCAB_URI);

public static enum META_PROPERTIES
{
Expand All @@ -33,7 +38,7 @@ public static enum META_PROPERTIES
}

public static EnumVocab<ITEM_PROPERTIES> ITEM_VOCAB = new EnumVocab<ITEM_PROPERTIES>(
ITEM_PROPERTIES.class, PACKAGE_VOCAB_URI);
ITEM_PROPERTIES.class, ITEM_VOCAB_URI);

public static enum ITEM_PROPERTIES
{
Expand Down Expand Up @@ -64,28 +69,60 @@ public Set<String> allowedOnTypes()
}

public static EnumVocab<ITEMREF_PROPERTIES> ITEMREF_VOCAB = new EnumVocab<ITEMREF_PROPERTIES>(
ITEMREF_PROPERTIES.class, PACKAGE_VOCAB_URI);
ITEMREF_PROPERTIES.class, ITEMREF_VOCAB_URI);

public static enum ITEMREF_PROPERTIES
{
PAGE_SPREAD_RIGHT,
PAGE_SPREAD_LEFT
}

public static final String LINKREL_VOCAB_URI = "http://idpf.org/epub/vocab/package/link/#";

public static EnumVocab<LINKREL_PROPERTIES> LINKREL_VOCAB = new EnumVocab<LINKREL_PROPERTIES>(
LINKREL_PROPERTIES.class, LINKREL_VOCAB_URI);
LINKREL_PROPERTIES.class, LINK_VOCAB_URI);

public static enum LINKREL_PROPERTIES
public static enum LINKREL_PROPERTIES implements PropertyStatus
{
ACQUIRE,
MARC21XML_RECORD,
MODS_RECORD,
ONIX_RECORD,
ALTERNATE,
MARC21XML_RECORD(DEPRECATED),
MODS_RECORD(DEPRECATED),
ONIX_RECORD(DEPRECATED),
RECORD,
XML_SIGNATURE,
XMP_RECORD
XML_SIGNATURE(DEPRECATED),
XMP_RECORD(DEPRECATED);

private final PropertyStatus status;

private LINKREL_PROPERTIES()
{
this(ALLOWED);
}

private LINKREL_PROPERTIES(PropertyStatus status)
{
this.status = Preconditions.checkNotNull(status);
}

@Override
public boolean isAllowed(ValidationContext context)
{
return status.isAllowed(context);
}

@Override
public boolean isDeprecated()
{
return status.isDeprecated();
}
}

public static EnumVocab<LINK_PROPERTIES> LINK_VOCAB = new EnumVocab<LINK_PROPERTIES>(
LINK_PROPERTIES.class, LINK_VOCAB_URI);

public static enum LINK_PROPERTIES
{
ONIX,
XMP;
}

private PackageVocabs()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,14 +250,20 @@ 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.marc21xml-record=the 'record' keyword and the media-type "application/marcxml+xml"
OPF_086_SUG.marginalia=a bare 'aside' element
OPF_086_SUG.mods-record=the 'record' keyword and the media-type "application/mods+xml"
OPF_086_SUG.note=a 'footnote' or 'endnote' property
OPF_086_SUG.onix-record=the 'record' keyword with the properties attribute value 'onix'
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_086_SUG.xml-signature=no signature-identifying link
OPF_086_SUG.xmp-record=the 'record' keyword with the properties attribute value 'xmp'
OPF_087=Property '%1$s' is not allowed on documents of type '%2$s'.
OPF_088=Unrecognized property '%1$s'.
OPF_089=The 'alternate' link rel keyword cannot be paired with other keywords.

#Package
PKG_001=Validating the EPUB against version %1$s but detected version %2$s.
Expand Down
Loading

0 comments on commit 99f882a

Please sign in to comment.