@@ -23,6 +23,7 @@ import java.util.Collections; | |||
import java.util.LinkedHashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Objects; | |||
import java.util.Set; | |||
import org.apache.logging.log4j.LogManager; | |||
@@ -641,38 +642,42 @@ public class POIXMLDocumentPart { | |||
// scan breadth-first, so parent-relations are hopefully the shallowest element | |||
for (PackageRelationship rel : rels) { | |||
if (rel.getTargetMode() == TargetMode.INTERNAL) { | |||
URI uri = rel.getTargetURI(); | |||
// check for internal references (e.g. '#Sheet1!A1') | |||
PackagePartName relName; | |||
if (uri.getRawFragment() != null) { | |||
relName = PackagingURIHelper.createPartName(uri.getPath()); | |||
} else { | |||
relName = PackagingURIHelper.createPartName(uri); | |||
} | |||
if (Objects.equals(rel.getRelationshipType(), HyperlinkRelationship.RELATIONSHIP_TYPE_CONST)) { | |||
referenceRelationships.put(rel.getId(), new HyperlinkRelationship(this, rel.getTargetURI(), rel.getTargetMode() == TargetMode.EXTERNAL, rel.getId())); | |||
} else { | |||
if (rel.getTargetMode() == TargetMode.INTERNAL) { | |||
URI uri = rel.getTargetURI(); | |||
// check for internal references (e.g. '#Sheet1!A1') | |||
PackagePartName relName; | |||
if (uri.getRawFragment() != null) { | |||
relName = PackagingURIHelper.createPartName(uri.getPath()); | |||
} else { | |||
relName = PackagingURIHelper.createPartName(uri); | |||
} | |||
final PackagePart p = packagePart.getPackage().getPart(relName); | |||
if (p == null) { | |||
LOG.atError().log("Skipped invalid entry {}", rel.getTargetURI()); | |||
continue; | |||
} | |||
final PackagePart p = packagePart.getPackage().getPart(relName); | |||
if (p == null) { | |||
LOG.atError().log("Skipped invalid entry {}", rel.getTargetURI()); | |||
continue; | |||
} | |||
POIXMLDocumentPart childPart = context.get(p); | |||
if (childPart == null) { | |||
childPart = factory.createDocumentPart(this, p); | |||
//here we are checking if part if embedded and excel then set it to chart class | |||
//so that at the time to writing we can also write updated embedded part | |||
if (this instanceof XDDFChart && childPart instanceof XSSFWorkbook) { | |||
((XDDFChart) this).setWorkbook((XSSFWorkbook) childPart); | |||
POIXMLDocumentPart childPart = context.get(p); | |||
if (childPart == null) { | |||
childPart = factory.createDocumentPart(this, p); | |||
//here we are checking if part if embedded and excel then set it to chart class | |||
//so that at the time to writing we can also write updated embedded part | |||
if (this instanceof XDDFChart && childPart instanceof XSSFWorkbook) { | |||
((XDDFChart) this).setWorkbook((XSSFWorkbook) childPart); | |||
} | |||
childPart.parent = this; | |||
// already add child to context, so other children can reference it | |||
context.put(p, childPart); | |||
readLater.add(childPart); | |||
} | |||
childPart.parent = this; | |||
// already add child to context, so other children can reference it | |||
context.put(p, childPart); | |||
readLater.add(childPart); | |||
} | |||
addRelation(rel, childPart); | |||
addRelation(rel, childPart); | |||
} | |||
} | |||
} | |||
@@ -186,6 +186,12 @@ public final class PackageRelationship { | |||
return targetUri; | |||
} | |||
// If it's an internal hyperlink target, we don't | |||
// need to apply our normal validation rules | |||
if (PackageRelationshipTypes.HYPERLINK_PART.equals(relationshipType)) { | |||
return targetUri; | |||
} | |||
// Internal target | |||
// If it isn't absolute, resolve it relative | |||
// to ourselves |
@@ -21,6 +21,7 @@ import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.io.OutputStream; | |||
import java.net.URI; | |||
import java.util.Objects; | |||
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; | |||
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; | |||
@@ -32,6 +33,7 @@ import org.apache.poi.openxml4j.opc.PackagePart; | |||
import org.apache.poi.openxml4j.opc.PackagePartName; | |||
import org.apache.poi.openxml4j.opc.PackageRelationship; | |||
import org.apache.poi.openxml4j.opc.PackageRelationshipCollection; | |||
import org.apache.poi.openxml4j.opc.PackageRelationshipTypes; | |||
import org.apache.poi.openxml4j.opc.PackagingURIHelper; | |||
import org.apache.poi.openxml4j.opc.StreamHelper; | |||
import org.apache.poi.openxml4j.opc.TargetMode; | |||
@@ -154,7 +156,14 @@ public final class ZipPartMarshaller implements PartMarshaller { | |||
// the relationship Target | |||
String targetValue; | |||
URI uri = rel.getTargetURI(); | |||
if (rel.getTargetMode() == TargetMode.EXTERNAL) { | |||
if (Objects.equals(rel.getRelationshipType(), PackageRelationshipTypes.HYPERLINK_PART)) { | |||
// Save the target as-is - we don't need to validate it, | |||
targetValue = uri.toString(); | |||
if (rel.getTargetMode() == TargetMode.EXTERNAL) { | |||
// add TargetMode attribute (as it is external link external) | |||
relElem.setAttribute(PackageRelationship.TARGET_MODE_ATTRIBUTE_NAME, "External"); | |||
} | |||
} else if (rel.getTargetMode() == TargetMode.EXTERNAL) { | |||
// Save the target as-is - we don't need to validate it, | |||
// alter it etc | |||
targetValue = uri.toString(); |
@@ -284,7 +284,7 @@ public final class TestPackage { | |||
assertEquals(1, rels.size()); | |||
PackageRelationship rel = rels.getRelationship(0); | |||
assertNotNull(rel); | |||
assertEquals("Sheet1!A1", rel.getTargetURI().getRawFragment()); | |||
assertEquals("#Sheet1!A1", rel.getTargetURI().toString()); | |||
assertMSCompatibility(pkg); | |||
} |
@@ -323,10 +323,11 @@ class TestRelationships { | |||
PackageRelationship rId1 = drawingPart.getRelationship("rId1"); | |||
URI parent = drawingPart.getPartName().getURI(); | |||
URI rel1 = parent.relativize(rId1.getTargetURI()); | |||
URI rel11 = PackagingURIHelper.relativizeURI(drawingPart.getPartName().getURI(), rId1.getTargetURI()); | |||
assertEquals("'Another Sheet'!A1", rel1.getFragment()); | |||
assertEquals("'Another Sheet'!A1", rel11.getFragment()); | |||
// Hyperlink is not a target of relativize() because it is not resolved based on sourceURI in getTargetURI() | |||
// URI rel1 = parent.relativize(rId1.getTargetURI()); | |||
// URI rel11 = PackagingURIHelper.relativizeURI(drawingPart.getPartName().getURI(), rId1.getTargetURI()); | |||
// assertEquals("'Another Sheet'!A1", rel1.getFragment()); | |||
// assertEquals("'Another Sheet'!A1", rel11.getFragment()); | |||
PackageRelationship rId2 = drawingPart.getRelationship("rId2"); | |||
URI rel2 = PackagingURIHelper.relativizeURI(drawingPart.getPartName().getURI(), rId2.getTargetURI()); |
@@ -53,8 +53,10 @@ import org.apache.commons.io.output.NullPrintStream; | |||
import org.apache.poi.POIDataSamples; | |||
import org.apache.poi.common.usermodel.HyperlinkType; | |||
import org.apache.poi.extractor.ExtractorFactory; | |||
import org.apache.poi.ooxml.HyperlinkRelationship; | |||
import org.apache.poi.ooxml.POIXMLDocumentPart; | |||
import org.apache.poi.ooxml.POIXMLDocumentPart.RelationPart; | |||
import org.apache.poi.ooxml.ReferenceRelationship; | |||
import org.apache.poi.openxml4j.exceptions.InvalidFormatException; | |||
import org.apache.poi.openxml4j.opc.OPCPackage; | |||
import org.apache.poi.openxml4j.opc.PackagePartName; | |||
@@ -384,23 +386,31 @@ class TestXSLFBugs { | |||
// Check the relations from this | |||
Collection<RelationPart> rels = slide.getRelationParts(); | |||
Collection<ReferenceRelationship> referenceRelationships = slide.getReferenceRelationships(); | |||
// Should have 6 relations: | |||
// 1 external hyperlink (skipped from list) | |||
// 4 internal hyperlinks | |||
// 1 slide layout | |||
assertEquals(5, rels.size()); | |||
assertEquals(1, rels.size()); | |||
assertEquals(5, referenceRelationships.size()); | |||
int layouts = 0; | |||
int hyperlinks = 0; | |||
int extHyperLinks = 0; | |||
for (RelationPart p : rels) { | |||
if (p.getRelationship().getRelationshipType().equals(XSLFRelation.HYPERLINK.getRelation())) { | |||
hyperlinks++; | |||
} else if (p.getDocumentPart() instanceof XSLFSlideLayout) { | |||
if (p.getDocumentPart() instanceof XSLFSlideLayout) { | |||
layouts++; | |||
} | |||
} | |||
for (ReferenceRelationship ref : referenceRelationships) { | |||
if (ref instanceof HyperlinkRelationship) { | |||
if (ref.isExternal()) extHyperLinks++; | |||
else hyperlinks++; | |||
} | |||
} | |||
assertEquals(1, layouts); | |||
assertEquals(4, hyperlinks); | |||
assertEquals(1, extHyperLinks); | |||
// Hyperlinks should all be to #_ftn1 or #ftnref1 | |||
for (RelationPart p : rels) { |
@@ -60,6 +60,7 @@ import org.apache.poi.ooxml.POIXMLDocumentPart; | |||
import org.apache.poi.ooxml.POIXMLDocumentPart.RelationPart; | |||
import org.apache.poi.ooxml.POIXMLException; | |||
import org.apache.poi.ooxml.POIXMLProperties; | |||
import org.apache.poi.ooxml.ReferenceRelationship; | |||
import org.apache.poi.ooxml.util.DocumentHelper; | |||
import org.apache.poi.openxml4j.exceptions.InvalidFormatException; | |||
import org.apache.poi.openxml4j.exceptions.InvalidOperationException; | |||
@@ -234,18 +235,18 @@ public final class TestXSSFBugs extends BaseTestBugzillaIssues { | |||
assertEquals(1, wb1.getNumberOfSheets()); | |||
XSSFSheet sh = wb1.getSheetAt(0); | |||
XSSFDrawing drawing = sh.createDrawingPatriarch(); | |||
List<RelationPart> rels = drawing.getRelationParts(); | |||
assertEquals(1, rels.size()); | |||
assertEquals("Sheet1!A1", rels.get(0).getRelationship().getTargetURI().getFragment()); | |||
List<ReferenceRelationship> referenceRelationships = drawing.getReferenceRelationships(); | |||
assertEquals(1, referenceRelationships.size()); | |||
assertEquals("#Sheet1!A1", referenceRelationships.get(0).getUri().toString()); | |||
// And again, just to be sure | |||
try (XSSFWorkbook wb2 = writeOutAndReadBack(wb1)) { | |||
assertEquals(1, wb2.getNumberOfSheets()); | |||
sh = wb2.getSheetAt(0); | |||
drawing = sh.createDrawingPatriarch(); | |||
rels = drawing.getRelationParts(); | |||
assertEquals(1, rels.size()); | |||
assertEquals("Sheet1!A1", rels.get(0).getRelationship().getTargetURI().getFragment()); | |||
referenceRelationships = drawing.getReferenceRelationships(); | |||
assertEquals(1, referenceRelationships.size()); | |||
assertEquals("#Sheet1!A1", referenceRelationships.get(0).getUri().toString()); | |||
} | |||
} | |||
} |