From 3199b8146b9b5c51d2bd5d46ec7d0b3cb1012dda Mon Sep 17 00:00:00 2001 From: Romain Deltour Date: Fri, 18 Nov 2022 01:45:05 +0100 Subject: [PATCH] feat: new requirements of package link 'media-type' attribute This commit implements the new requirements of the `media-type` attribute of the package document `link` element. - new `OPF-093` error is reported when the `media-type` attribute is missing on linked resources located inside the EPUB container - new `OPF-094` error is reported when the `media-type` attribute is missing on a link where the `rel` keyword requires it (this was previously checked with Schematron) - new `OPF-095` error is reported when the media type of a "voicing" linked resource is not an audio type (this was previously checked with Schematron) These new checks are implemented in Java, and the old schematron logic is removed. Fixes #1307 --- .../epubcheck/messages/DefaultSeverities.java | 3 + .../adobe/epubcheck/messages/MessageId.java | 3 + .../com/adobe/epubcheck/opf/OPFHandler30.java | 57 ++++++++++++++++--- .../messages/MessageBundle.properties | 3 + .../adobe/epubcheck/schema/30/package-30.sch | 5 +- .../file-url-in-package-document-error.opf | 2 +- .../link-to-publication-resource-error.opf | 2 +- .../EPUB/book.xml} | 0 .../EPUB/content_001.xhtml | 0 .../EPUB/nav.xhtml | 0 .../EPUB/package.opf | 18 ++++++ .../META-INF/container.xml | 0 .../mimetype | 0 .../EPUB/content_001.xhtml | 11 ++++ .../EPUB/nav.xhtml | 14 +++++ .../EPUB/package.opf | 18 ++++++ .../META-INF/container.xml | 6 ++ .../mimetype | 1 + .../EPUB/package.opf | 17 ------ .../package-document.feature | 15 +++-- ...ink-rel-record-mediatype-missing-error.opf | 2 +- ...nk-rel-voicing-mediatype-missing-error.opf | 2 +- .../D-vocabularies/metadata-link.feature | 19 ++++--- 23 files changed, 150 insertions(+), 48 deletions(-) rename src/test/resources/epub3/05-package-document/files/{package-link-missing-media-type-error/EPUB/book.opds => package-link-media-type-missing-local-error/EPUB/book.xml} (100%) rename src/test/resources/epub3/05-package-document/files/{package-link-missing-media-type-error => package-link-media-type-missing-local-error}/EPUB/content_001.xhtml (100%) rename src/test/resources/epub3/05-package-document/files/{package-link-missing-media-type-error => package-link-media-type-missing-local-error}/EPUB/nav.xhtml (100%) create mode 100644 src/test/resources/epub3/05-package-document/files/package-link-media-type-missing-local-error/EPUB/package.opf rename src/test/resources/epub3/05-package-document/files/{package-link-missing-media-type-error => package-link-media-type-missing-local-error}/META-INF/container.xml (100%) rename src/test/resources/epub3/05-package-document/files/{package-link-missing-media-type-error => package-link-media-type-missing-local-error}/mimetype (100%) create mode 100644 src/test/resources/epub3/05-package-document/files/package-link-media-type-missing-remote-valid/EPUB/content_001.xhtml create mode 100644 src/test/resources/epub3/05-package-document/files/package-link-media-type-missing-remote-valid/EPUB/nav.xhtml create mode 100644 src/test/resources/epub3/05-package-document/files/package-link-media-type-missing-remote-valid/EPUB/package.opf create mode 100644 src/test/resources/epub3/05-package-document/files/package-link-media-type-missing-remote-valid/META-INF/container.xml create mode 100644 src/test/resources/epub3/05-package-document/files/package-link-media-type-missing-remote-valid/mimetype delete mode 100644 src/test/resources/epub3/05-package-document/files/package-link-missing-media-type-error/EPUB/package.opf diff --git a/src/main/java/com/adobe/epubcheck/messages/DefaultSeverities.java b/src/main/java/com/adobe/epubcheck/messages/DefaultSeverities.java index 0383b3e67..613b8c5b4 100644 --- a/src/main/java/com/adobe/epubcheck/messages/DefaultSeverities.java +++ b/src/main/java/com/adobe/epubcheck/messages/DefaultSeverities.java @@ -283,6 +283,9 @@ private void initialize() severities.put(MessageId.OPF_090, Severity.USAGE); severities.put(MessageId.OPF_091, Severity.ERROR); severities.put(MessageId.OPF_092, Severity.ERROR); + severities.put(MessageId.OPF_093, Severity.ERROR); + severities.put(MessageId.OPF_094, Severity.ERROR); + severities.put(MessageId.OPF_095, Severity.ERROR); // PKG severities.put(MessageId.PKG_001, Severity.WARNING); diff --git a/src/main/java/com/adobe/epubcheck/messages/MessageId.java b/src/main/java/com/adobe/epubcheck/messages/MessageId.java index 480cf6536..c1f2a6135 100644 --- a/src/main/java/com/adobe/epubcheck/messages/MessageId.java +++ b/src/main/java/com/adobe/epubcheck/messages/MessageId.java @@ -277,6 +277,9 @@ public enum MessageId implements Comparable OPF_090("OPF-090"), OPF_091("OPF-091"), OPF_092("OPF-092"), + OPF_093("OPF-093"), + OPF_094("OPF-094"), + OPF_095("OPF-095"), // 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 86f004c59..c214f0592 100644 --- a/src/main/java/com/adobe/epubcheck/opf/OPFHandler30.java +++ b/src/main/java/com/adobe/epubcheck/opf/OPFHandler30.java @@ -336,7 +336,7 @@ else if (EpubConstants.DCElements.equals(e.getNamespace())) * Document. Must be called after the parsing. * * @return the metadata for the Rendition represented by the current Package - * Document + * Document */ public MetadataSet getMetadata() { @@ -350,7 +350,7 @@ public MetadataSet getMetadata() * called after the parsing. * * @return the linked resources for the Rendition represented by the current - * Package Document + * Package Document */ public LinkedResources getLinkedResources() { @@ -363,7 +363,7 @@ public LinkedResources getLinkedResources() * the parsing. * * @return the linked resources for the Rendition represented by the current - * Package Document + * Package Document */ public ResourceCollections getCollections() { @@ -446,28 +446,67 @@ private void processLink() String href = e.getAttribute("href"); if (href != null) - { // check by schema + { // href presence is checked by schema + // check the 'href' URL URL url = checkURL(href); - if (context.isRemote(url)) { + if (context.isRemote(url)) + { report.info(path, FeatureEnum.REFERENCE, href); } - if (context.xrefChecker.isPresent()) { context.xrefChecker.get().registerReference(url, Type.LINK, location()); } + // check the 'rel' attribute + String rel = e.getAttribute("rel"); + Set relSet = processLinkRel(rel); + Set relEnum = Property.filter(relSet, LINKREL_PROPERTIES.class); + + // check the 'media-type' attribute + String mediatype = e.getAttribute("media-type"); + if (mediatype == null) + { + // media-type is required for in-container URLs + // NOTE: as legacy EPUB 3.2 collections made heavy use + // of local links with no media type, we only check this + // for metadata links, which may be a violation of EPUB. + if (!context.isRemote(url) && !metadataBuilders.isEmpty()) + { + if (linkedResourcesBuilders.size() == 1) + report.message(MessageId.OPF_093, location()); + } + // media-type is required by some keywords + else if (relEnum.stream().anyMatch( + keyword -> keyword == LINKREL_PROPERTIES.RECORD + || keyword == LINKREL_PROPERTIES.VOICING)) + { + report.message(MessageId.OPF_094, location(), rel); + } + } + else + { + // 'voicing' links require an audio media type + if (relEnum.contains(LINKREL_PROPERTIES.VOICING) && !OPFChecker30.isAudioType(mediatype)) + { + report.message(MessageId.OPF_095, location(), mediatype); + } + } + + // check the 'properties' attribute + processLinkProperties(e.getAttribute("properties")); + + // build the data model if (!linkedResourcesBuilders.isEmpty()) { - processLinkProperties(e.getAttribute("properties")); LinkedResource resource = new LinkedResource.Builder(url).id(e.getAttribute("id")) - .rel(processLinkRel(e.getAttribute("rel"))).mimetype(e.getAttribute("media-type")) - .refines(e.getAttribute("refines")).build(); + .rel(relSet).mimetype(mediatype).refines(e.getAttribute("refines")).build(); linkedResourcesBuilders.peekFirst().add(resource); } } + // check hreflang attribute String hreflang = e.getAttribute("hreflang"); if (hreflang != null && !hreflang.isEmpty()) { diff --git a/src/main/resources/com/adobe/epubcheck/messages/MessageBundle.properties b/src/main/resources/com/adobe/epubcheck/messages/MessageBundle.properties index 5024c9189..462b671af 100644 --- a/src/main/resources/com/adobe/epubcheck/messages/MessageBundle.properties +++ b/src/main/resources/com/adobe/epubcheck/messages/MessageBundle.properties @@ -289,6 +289,9 @@ OPF_089=The "alternate" link rel keyword cannot be paired with other keywords. OPF_090=It is encouraged to use MIME media type "%1$s" instead of "%2$s". OPF_091=The item href URL must not have a fragment identifier. OPF_092=Language tag "%1$s" is not well-formed: %2$s +OPF_093=The "media-type" attribute is required for linked resources located in the EPUB container +OPF_094=The "media-type" attribute is required for "%1$s" links. +OPF_095=The "media-type" attribute of "voicing" links must be an audio MIME type, but found "%1$s". #Package PKG_001=Validating the EPUB against version %1$s but detected version %2$s. diff --git a/src/main/resources/com/adobe/epubcheck/schema/30/package-30.sch b/src/main/resources/com/adobe/epubcheck/schema/30/package-30.sch index 033049c5e..c444c5a52 100644 --- a/src/main/resources/com/adobe/epubcheck/schema/30/package-30.sch +++ b/src/main/resources/com/adobe/epubcheck/schema/30/package-30.sch @@ -34,8 +34,7 @@ - The type of "record" references must be identifiable - from the link element’s "media-type" attribute. + "record" links only applies to the Publication (must not have a "refines" attribute). @@ -43,7 +42,7 @@ - "voicing" links must have a "media-type" attribute identifying an audio MIME type. + "voicing" links must have a "refines" attribute. diff --git a/src/test/resources/epub3/03-resources/files/file-url-in-package-document-error.opf b/src/test/resources/epub3/03-resources/files/file-url-in-package-document-error.opf index b6b3732f7..ff5cb8f92 100644 --- a/src/test/resources/epub3/03-resources/files/file-url-in-package-document-error.opf +++ b/src/test/resources/epub3/03-resources/files/file-url-in-package-document-error.opf @@ -5,7 +5,7 @@ en NOID 2017-06-14T00:00:01Z - + diff --git a/src/test/resources/epub3/05-package-document/files/link-to-publication-resource-error.opf b/src/test/resources/epub3/05-package-document/files/link-to-publication-resource-error.opf index 908b0216f..0430ba6cf 100644 --- a/src/test/resources/epub3/05-package-document/files/link-to-publication-resource-error.opf +++ b/src/test/resources/epub3/05-package-document/files/link-to-publication-resource-error.opf @@ -8,7 +8,7 @@ NOID 2019-01-01T12:00:00Z - + diff --git a/src/test/resources/epub3/05-package-document/files/package-link-missing-media-type-error/EPUB/book.opds b/src/test/resources/epub3/05-package-document/files/package-link-media-type-missing-local-error/EPUB/book.xml similarity index 100% rename from src/test/resources/epub3/05-package-document/files/package-link-missing-media-type-error/EPUB/book.opds rename to src/test/resources/epub3/05-package-document/files/package-link-media-type-missing-local-error/EPUB/book.xml diff --git a/src/test/resources/epub3/05-package-document/files/package-link-missing-media-type-error/EPUB/content_001.xhtml b/src/test/resources/epub3/05-package-document/files/package-link-media-type-missing-local-error/EPUB/content_001.xhtml similarity index 100% rename from src/test/resources/epub3/05-package-document/files/package-link-missing-media-type-error/EPUB/content_001.xhtml rename to src/test/resources/epub3/05-package-document/files/package-link-media-type-missing-local-error/EPUB/content_001.xhtml diff --git a/src/test/resources/epub3/05-package-document/files/package-link-missing-media-type-error/EPUB/nav.xhtml b/src/test/resources/epub3/05-package-document/files/package-link-media-type-missing-local-error/EPUB/nav.xhtml similarity index 100% rename from src/test/resources/epub3/05-package-document/files/package-link-missing-media-type-error/EPUB/nav.xhtml rename to src/test/resources/epub3/05-package-document/files/package-link-media-type-missing-local-error/EPUB/nav.xhtml diff --git a/src/test/resources/epub3/05-package-document/files/package-link-media-type-missing-local-error/EPUB/package.opf b/src/test/resources/epub3/05-package-document/files/package-link-media-type-missing-local-error/EPUB/package.opf new file mode 100644 index 000000000..b80ce2495 --- /dev/null +++ b/src/test/resources/epub3/05-package-document/files/package-link-media-type-missing-local-error/EPUB/package.opf @@ -0,0 +1,18 @@ + + + + Minimal EPUB 3.0 + en + NOID + 2017-06-14T00:00:01Z + + + + + + + + + + diff --git a/src/test/resources/epub3/05-package-document/files/package-link-missing-media-type-error/META-INF/container.xml b/src/test/resources/epub3/05-package-document/files/package-link-media-type-missing-local-error/META-INF/container.xml similarity index 100% rename from src/test/resources/epub3/05-package-document/files/package-link-missing-media-type-error/META-INF/container.xml rename to src/test/resources/epub3/05-package-document/files/package-link-media-type-missing-local-error/META-INF/container.xml diff --git a/src/test/resources/epub3/05-package-document/files/package-link-missing-media-type-error/mimetype b/src/test/resources/epub3/05-package-document/files/package-link-media-type-missing-local-error/mimetype similarity index 100% rename from src/test/resources/epub3/05-package-document/files/package-link-missing-media-type-error/mimetype rename to src/test/resources/epub3/05-package-document/files/package-link-media-type-missing-local-error/mimetype diff --git a/src/test/resources/epub3/05-package-document/files/package-link-media-type-missing-remote-valid/EPUB/content_001.xhtml b/src/test/resources/epub3/05-package-document/files/package-link-media-type-missing-remote-valid/EPUB/content_001.xhtml new file mode 100644 index 000000000..96ea27c7e --- /dev/null +++ b/src/test/resources/epub3/05-package-document/files/package-link-media-type-missing-remote-valid/EPUB/content_001.xhtml @@ -0,0 +1,11 @@ + + + + + Minimal EPUB + + +

Loomings

+

Call me Ishmael.

+ + diff --git a/src/test/resources/epub3/05-package-document/files/package-link-media-type-missing-remote-valid/EPUB/nav.xhtml b/src/test/resources/epub3/05-package-document/files/package-link-media-type-missing-remote-valid/EPUB/nav.xhtml new file mode 100644 index 000000000..240745e63 --- /dev/null +++ b/src/test/resources/epub3/05-package-document/files/package-link-media-type-missing-remote-valid/EPUB/nav.xhtml @@ -0,0 +1,14 @@ + + + + + Minimal Nav + + + + + diff --git a/src/test/resources/epub3/05-package-document/files/package-link-media-type-missing-remote-valid/EPUB/package.opf b/src/test/resources/epub3/05-package-document/files/package-link-media-type-missing-remote-valid/EPUB/package.opf new file mode 100644 index 000000000..83c9c36b0 --- /dev/null +++ b/src/test/resources/epub3/05-package-document/files/package-link-media-type-missing-remote-valid/EPUB/package.opf @@ -0,0 +1,18 @@ + + + + Minimal EPUB 3.0 + en + NOID + 2017-06-14T00:00:01Z + + + + + + + + + + diff --git a/src/test/resources/epub3/05-package-document/files/package-link-media-type-missing-remote-valid/META-INF/container.xml b/src/test/resources/epub3/05-package-document/files/package-link-media-type-missing-remote-valid/META-INF/container.xml new file mode 100644 index 000000000..2ca12eff7 --- /dev/null +++ b/src/test/resources/epub3/05-package-document/files/package-link-media-type-missing-remote-valid/META-INF/container.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/test/resources/epub3/05-package-document/files/package-link-media-type-missing-remote-valid/mimetype b/src/test/resources/epub3/05-package-document/files/package-link-media-type-missing-remote-valid/mimetype new file mode 100644 index 000000000..57ef03f24 --- /dev/null +++ b/src/test/resources/epub3/05-package-document/files/package-link-media-type-missing-remote-valid/mimetype @@ -0,0 +1 @@ +application/epub+zip \ No newline at end of file diff --git a/src/test/resources/epub3/05-package-document/files/package-link-missing-media-type-error/EPUB/package.opf b/src/test/resources/epub3/05-package-document/files/package-link-missing-media-type-error/EPUB/package.opf deleted file mode 100644 index b55821e0c..000000000 --- a/src/test/resources/epub3/05-package-document/files/package-link-missing-media-type-error/EPUB/package.opf +++ /dev/null @@ -1,17 +0,0 @@ - - - - Minimal EPUB 3.0 - en - NOID - 2017-06-14T00:00:01Z - - - - - - - - - - \ No newline at end of file diff --git a/src/test/resources/epub3/05-package-document/package-document.feature b/src/test/resources/epub3/05-package-document/package-document.feature index 09e356667..84917f95c 100644 --- a/src/test/resources/epub3/05-package-document/package-document.feature +++ b/src/test/resources/epub3/05-package-document/package-document.feature @@ -334,12 +334,15 @@ Feature: EPUB 3 — Package document And no other errors or warnings are reported @spec @xref:sec-link-elem - Scenario: A link to a local resource must declare a media type - When checking file 'package-link-missing-media-type-error' - # Then error RSC-005 is reported - # And the message contains 'missing required attribute "media-type"' - # And no other errors or warnings are reported - Then no other errors or warnings are reported + Scenario: Report a missing 'media-type' attribute on links to container resources + When checking file 'package-link-media-type-missing-local-error' + Then error OPF-093 is reported + And no other errors or warnings are reported + + @spec @xref:sec-link-elem + Scenario: Allow a missing 'media-type' attribute on links to remote resources + When checking file 'package-link-media-type-missing-remote-valid' + Then no errors or warnings are reported @spec @xref:sec-link-elem Scenario: the link 'rel' attribute can have multiple properties diff --git a/src/test/resources/epub3/D-vocabularies/files/link-rel-record-mediatype-missing-error.opf b/src/test/resources/epub3/D-vocabularies/files/link-rel-record-mediatype-missing-error.opf index 049eb676e..93949b610 100644 --- a/src/test/resources/epub3/D-vocabularies/files/link-rel-record-mediatype-missing-error.opf +++ b/src/test/resources/epub3/D-vocabularies/files/link-rel-record-mediatype-missing-error.opf @@ -6,7 +6,7 @@ en NOID 2019-01-01T12:00:00Z - + diff --git a/src/test/resources/epub3/D-vocabularies/files/link-rel-voicing-mediatype-missing-error.opf b/src/test/resources/epub3/D-vocabularies/files/link-rel-voicing-mediatype-missing-error.opf index d654c2604..c421d8aab 100644 --- a/src/test/resources/epub3/D-vocabularies/files/link-rel-voicing-mediatype-missing-error.opf +++ b/src/test/resources/epub3/D-vocabularies/files/link-rel-voicing-mediatype-missing-error.opf @@ -6,7 +6,7 @@ en NOID 2019-01-01T12:00:00Z - + diff --git a/src/test/resources/epub3/D-vocabularies/metadata-link.feature b/src/test/resources/epub3/D-vocabularies/metadata-link.feature index 4eae22abe..5ebd025ce 100644 --- a/src/test/resources/epub3/D-vocabularies/metadata-link.feature +++ b/src/test/resources/epub3/D-vocabularies/metadata-link.feature @@ -33,7 +33,7 @@ Feature: EPUB 3 — Vocabularies — Metadata link vocabulary When checking file 'link-rel-alternate-with-other-keyword-error.opf' Then error OPF-089 is reported And no other errors or warnings are reported - + #### D.4.1.3, D.4.1.4, D.4.1.5, D.4.1.9 *-record @@ -44,6 +44,8 @@ Feature: EPUB 3 — Vocabularies — Metadata link vocabulary | OPF-086 | "mods-record" is deprecated | | OPF-086 | "onix-record" is deprecated | | OPF-086 | "xmp-record" is deprecated | + And error OPF-093 is reported 4 times + # note: 'media-type' is now required, even on deprecated properties And no other errors or warnings are reported @@ -62,10 +64,9 @@ Feature: EPUB 3 — Vocabularies — Metadata link vocabulary Then no errors or warnings are reported @spec @xref:sec-record - Scenario: a 'record' link must have a 'media-type' attribute + Scenario: a 'record' link must have a 'media-type' attribute even when remote When checking file 'link-rel-record-mediatype-missing-error.opf' - Then error RSC-005 is reported - And the message contains "media-type" + Then error OPF-094 is reported And no other errors or warnings are reported Scenario: a 'record' link type can be further identified with a 'properties' attribute @@ -95,17 +96,15 @@ Feature: EPUB 3 — Vocabularies — Metadata link vocabulary And no other errors or warnings are reported @spec @xref:sec-voicing - Scenario: a 'voicing' link must have a 'media-type' attribute + Scenario: a 'voicing' link must have a 'media-type' attribute even when remote When checking file 'link-rel-voicing-mediatype-missing-error.opf' - Then error RSC-005 is reported - And the message contains 'must have a "media-type" attribute' + Then error OPF-094 is reported And no other errors or warnings are reported @spec @xref:sec-voicing Scenario: a 'voicing' link resource must have an audio media type When checking file 'link-rel-voicing-mediatype-not-audio-error.opf' - Then error RSC-005 is reported - And the message contains 'must have a "media-type" attribute identifying an audio MIME type' + Then error OPF-095 is reported And no other errors or warnings are reported @@ -115,4 +114,6 @@ Feature: EPUB 3 — Vocabularies — Metadata link vocabulary When checking file 'link-rel-xml-signature-deprecated-warning.opf' Then warning OPF-086 is reported And the message contains '"xml-signature" is deprecated' + And error OPF-093 is reported + # note: 'media-type' is now required, even on deprecated properties And no other errors or warnings are reported