}
/**
- * Load the parts of the archive if it has not been done yet The
- * relationships of each part are not loaded
+ * Load the parts of the archive if it has not been done yet. The
+ * relationships of each part are not loaded.
+ *
+ * Note - Rule M4.1 states that there may only ever be one Core
+ * Properties Part, but Office produced files will sometimes
+ * have multiple! As Office ignores all but the first, we relax
+ * Compliance with Rule M4.1, and ignore all others silently too.
*
* @return All this package's parts.
*/
if (partList == null) {
/* Variables use to validate OPC Compliance */
- // Ensure rule M4.1 -> A format consumer shall consider more than
+ // Check rule M4.1 -> A format consumer shall consider more than
// one core properties relationship for a package to be an error
+ // (We just log it and move on, as real files break this!)
boolean hasCorePropertiesPart = false;
+ boolean needCorePropertiesPart = true;
PackagePart[] parts = this.getPartsImpl();
this.partList = new PackagePartCollection();
for (PackagePart part : parts) {
if (partList.containsKey(part._partName))
throw new InvalidFormatException(
- "A part with the name '"
- + part._partName
- + "' already exist : Packages shall not contain equivalent part names and package implementers shall neither create nor recognize packages with equivalent part names. [M1.12]");
+ "A part with the name '" +
+ part._partName +
+ "' already exist : Packages shall not contain equivalent " +
+ "part names and package implementers shall neither create " +
+ "nor recognize packages with equivalent part names. [M1.12]");
// Check OPC compliance rule M4.1
if (part.getContentType().equals(
ContentTypes.CORE_PROPERTIES_PART)) {
- if (!hasCorePropertiesPart)
+ if (!hasCorePropertiesPart) {
hasCorePropertiesPart = true;
- else
- throw new InvalidFormatException(
- "OPC Compliance error [M4.1]: there is more than one core properties relationship in the package !");
+ } else {
+ logger.log(POILogger.WARN, "OPC Compliance error [M4.1]: " +
+ "there is more than one core properties relationship in the package! " +
+ "POI will use only the first, but other software may reject this file.");
+ }
}
- PartUnmarshaller partUnmarshaller = partUnmarshallers
- .get(part._contentType);
+ PartUnmarshaller partUnmarshaller = partUnmarshallers.get(part._contentType);
if (partUnmarshaller != null) {
UnmarshallContext context = new UnmarshallContext(this,
.unmarshall(context, part.getInputStream());
partList.put(unmarshallPart._partName, unmarshallPart);
- // Core properties case
- if (unmarshallPart instanceof PackagePropertiesPart)
+ // Core properties case-- use first CoreProperties part we come across
+ // and ignore any subsequent ones
+ if (unmarshallPart instanceof PackagePropertiesPart &&
+ hasCorePropertiesPart &&
+ needCorePropertiesPart) {
this.packageProperties = (PackagePropertiesPart) unmarshallPart;
+ needCorePropertiesPart = false;
+ }
} catch (IOException ioe) {
logger.log(POILogger.WARN, "Unmarshall operation : IOException for "
+ part._partName);
if (partList.containsKey(partName)
&& !partList.get(partName).isDeleted()) {
throw new PartAlreadyExistsException(
- "A part with the name '"
- + partName.getName()
- + "' already exists : Packages shall not contain equivalent part names and package implementers shall neither create nor recognize packages with equivalent part names. [M1.12]");
+ "A part with the name '" + partName.getName() + "'" +
+ " already exists : Packages shall not contain equivalent part names and package" +
+ " implementers shall neither create nor recognize packages with equivalent part names. [M1.12]");
}
/* Check OPC compliance */
- // Rule [M4.1]: The format designer shall specify and the format
- // producer
+ // Rule [M4.1]: The format designer shall specify and the format producer
// shall create at most one core properties relationship for a package.
// A format consumer shall consider more than one core properties
// relationship for a package to be an error. If present, the
// relationship shall target the Core Properties part.
+ // Note - POI will read files with more than one Core Properties, which
+ // Office sometimes produces, but is strict on generation
if (contentType.equals(ContentTypes.CORE_PROPERTIES_PART)) {
if (this.packageProperties != null)
throw new InvalidOperationException(
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
+import org.apache.poi.POIDataSamples;
import org.apache.poi.openxml4j.OpenXML4JTestDataSamples;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.exceptions.InvalidOperationException;
import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;
import org.apache.poi.openxml4j.opc.PackagingURIHelper;
import org.apache.poi.openxml4j.opc.TargetMode;
-import org.apache.poi.POIDataSamples;
/**
* Test core properties Open Packaging Convention compliance.
* at most one core properties relationship for a package. A format consumer
* shall consider more than one core properties relationship for a package to be
* an error. If present, the relationship shall target the Core Properties part.
+ * (POI relaxes this on reading, as Office sometimes breaks this)
*
* M4.2: The format designer shall not specify and the format producer shall not
* create Core Properties that use the Markup Compatibility namespace as defined
}
private static String extractInvalidFormatMessage(String sampleNameSuffix) {
-
InputStream is = OpenXML4JTestDataSamples.openComplianceSampleStream("OPCCompliance_CoreProperties_" + sampleNameSuffix);
OPCPackage pkg;
try {
pkg = OPCPackage.open(is);
} catch (InvalidFormatException e) {
- // expected during successful test
+ // no longer required for successful test
return e.getMessage();
} catch (IOException e) {
throw new RuntimeException(e);
}
pkg.revert();
- // Normally must thrown an InvalidFormatException exception.
throw new AssertionFailedError("expected OPC compliance exception was not thrown");
}
/**
* Test M4.1 rule.
*/
- public void testOnlyOneCorePropertiesPart() {
- String msg = extractInvalidFormatMessage("OnlyOneCorePropertiesPartFAIL.docx");
- assertEquals("OPC Compliance error [M4.1]: there is more than one core properties relationship in the package !", msg);
+ public void testOnlyOneCorePropertiesPart() throws Exception {
+ // We have relaxed this check, so we can read the file anyway
+ try {
+ extractInvalidFormatMessage("OnlyOneCorePropertiesPartFAIL.docx");
+ fail("M4.1 should be being relaxed");
+ } catch (AssertionFailedError e) {}
+
+ // We will use the first core properties, and ignore the others
+ InputStream is = OpenXML4JTestDataSamples.openSampleStream("MultipleCoreProperties.docx");
+ OPCPackage pkg = OPCPackage.open(is);
+
+ // We can see 2 by type
+ assertEquals(2, pkg.getPartsByContentType(ContentTypes.CORE_PROPERTIES_PART).size());
+ // But only the first one by relationship
+ assertEquals(1, pkg.getPartsByRelationshipType(PackageRelationshipTypes.CORE_PROPERTIES).size());
+ // It should be core.xml not the older core1.xml
+ assertEquals(
+ "/docProps/core.xml",
+ pkg.getPartsByRelationshipType(PackageRelationshipTypes.CORE_PROPERTIES).get(0).getPartName().toString()
+ );
}
private static URI createURI(String text) {
try {
pkg.addRelationship(PackagingURIHelper.createPartName(partUri), TargetMode.INTERNAL,
PackageRelationshipTypes.CORE_PROPERTIES);
- fail("expected OPC compliance exception was not thrown");
+ // no longer fail on compliance error
+ //fail("expected OPC compliance exception was not thrown");
} catch (InvalidFormatException e) {
throw new RuntimeException(e);
} catch (InvalidOperationException e) {
try {
pkg.createPart(PackagingURIHelper.createPartName(partUri),
ContentTypes.CORE_PROPERTIES_PART);
- fail("expected OPC compliance exception was not thrown");
+ // no longer fail on compliance error
+ //fail("expected OPC compliance exception was not thrown");
} catch (InvalidFormatException e) {
throw new RuntimeException(e);
} catch (InvalidOperationException e) {