mirror of https://github.com/apache/poi.git
[bug-63189] support hyperlink relationships. Thanks to Ohyoung Kwon. This closes #617
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1917134 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
d525d1a5b1
commit
eebb3717e0
|
@ -0,0 +1,44 @@
|
||||||
|
/* ====================================================================
|
||||||
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
this work for additional information regarding copyright ownership.
|
||||||
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
(the "License"); you may not use this file except in compliance with
|
||||||
|
the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
==================================================================== */
|
||||||
|
package org.apache.poi.ooxml;
|
||||||
|
|
||||||
|
import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a hyperlink relationship.
|
||||||
|
*
|
||||||
|
* @since POI 5.2.6
|
||||||
|
*/
|
||||||
|
public class HyperlinkRelationship extends ReferenceRelationship {
|
||||||
|
/**
|
||||||
|
* Initializes a new instance of the HyperlinkRelationship.
|
||||||
|
*
|
||||||
|
* @param hyperlinkUri The target uri of the hyperlink relationship.
|
||||||
|
* @param isExternal Is the URI external.
|
||||||
|
* @param id The relationship ID.
|
||||||
|
*/
|
||||||
|
protected HyperlinkRelationship(POIXMLDocumentPart container, URI hyperlinkUri, boolean isExternal, String id) {
|
||||||
|
super(container, hyperlinkUri, isExternal, PackageRelationshipTypes.HYPERLINK_PART, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRelationshipType() {
|
||||||
|
return PackageRelationshipTypes.HYPERLINK_PART;
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,6 +23,7 @@ import java.util.Collections;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
@ -38,7 +39,6 @@ import org.apache.poi.openxml4j.opc.PackageRelationshipCollection;
|
||||||
import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;
|
import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;
|
||||||
import org.apache.poi.openxml4j.opc.PackagingURIHelper;
|
import org.apache.poi.openxml4j.opc.PackagingURIHelper;
|
||||||
import org.apache.poi.openxml4j.opc.TargetMode;
|
import org.apache.poi.openxml4j.opc.TargetMode;
|
||||||
import org.apache.poi.util.IOUtils;
|
|
||||||
import org.apache.poi.util.Internal;
|
import org.apache.poi.util.Internal;
|
||||||
import org.apache.poi.xddf.usermodel.chart.XDDFChart;
|
import org.apache.poi.xddf.usermodel.chart.XDDFChart;
|
||||||
import org.apache.poi.xssf.usermodel.XSSFRelation;
|
import org.apache.poi.xssf.usermodel.XSSFRelation;
|
||||||
|
@ -59,6 +59,7 @@ public class POIXMLDocumentPart {
|
||||||
private PackagePart packagePart;
|
private PackagePart packagePart;
|
||||||
private POIXMLDocumentPart parent;
|
private POIXMLDocumentPart parent;
|
||||||
private final Map<String, RelationPart> relations = new LinkedHashMap<>();
|
private final Map<String, RelationPart> relations = new LinkedHashMap<>();
|
||||||
|
private final Map<String, ReferenceRelationship> referenceRelationships = new LinkedHashMap<>();
|
||||||
private boolean isCommitted = false;
|
private boolean isCommitted = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -640,38 +641,42 @@ public class POIXMLDocumentPart {
|
||||||
|
|
||||||
// scan breadth-first, so parent-relations are hopefully the shallowest element
|
// scan breadth-first, so parent-relations are hopefully the shallowest element
|
||||||
for (PackageRelationship rel : rels) {
|
for (PackageRelationship rel : rels) {
|
||||||
if (rel.getTargetMode() == TargetMode.INTERNAL) {
|
if (Objects.equals(rel.getRelationshipType(), HyperlinkRelationship.HYPERLINK_REL_TYPE)) {
|
||||||
URI uri = rel.getTargetURI();
|
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')
|
// check for internal references (e.g. '#Sheet1!A1')
|
||||||
PackagePartName relName;
|
PackagePartName relName;
|
||||||
if (uri.getRawFragment() != null) {
|
if (uri.getRawFragment() != null) {
|
||||||
relName = PackagingURIHelper.createPartName(uri.getPath());
|
relName = PackagingURIHelper.createPartName(uri.getPath());
|
||||||
} else {
|
} else {
|
||||||
relName = PackagingURIHelper.createPartName(uri);
|
relName = PackagingURIHelper.createPartName(uri);
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
childPart.parent = this;
|
|
||||||
// already add child to context, so other children can reference it
|
|
||||||
context.put(p, childPart);
|
|
||||||
readLater.add(childPart);
|
|
||||||
}
|
|
||||||
|
|
||||||
addRelation(rel, childPart);
|
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);
|
||||||
|
}
|
||||||
|
childPart.parent = this;
|
||||||
|
// already add child to context, so other children can reference it
|
||||||
|
context.put(p, childPart);
|
||||||
|
readLater.add(childPart);
|
||||||
|
}
|
||||||
|
|
||||||
|
addRelation(rel, childPart);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -767,4 +772,31 @@ public class POIXMLDocumentPart {
|
||||||
throw new POIXMLException("OOXML file structure broken/invalid", e);
|
throw new POIXMLException("OOXML file structure broken/invalid", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean removeReferenceRelationship(String relId) {
|
||||||
|
ReferenceRelationship existing = referenceRelationships.remove(relId);
|
||||||
|
if (existing != null) {
|
||||||
|
packagePart.removeRelationship(relId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReferenceRelationship getReferenceRelationship(String relId) {
|
||||||
|
return referenceRelationships.get(relId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HyperlinkRelationship createHyperlink(URI uri, boolean isExternal, String relId) {
|
||||||
|
PackageRelationship pr = packagePart.addRelationship(uri, isExternal ? TargetMode.EXTERNAL : TargetMode.INTERNAL,
|
||||||
|
HyperlinkRelationship.HYPERLINK_REL_TYPE, relId);
|
||||||
|
HyperlinkRelationship hyperlink = new HyperlinkRelationship(this, uri, isExternal, relId);
|
||||||
|
referenceRelationships.put(relId, hyperlink);
|
||||||
|
return hyperlink;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ReferenceRelationship> getReferenceRelationships() {
|
||||||
|
List<ReferenceRelationship> list = new ArrayList<>(referenceRelationships.values());
|
||||||
|
return Collections.unmodifiableList(list);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
/* ====================================================================
|
||||||
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
this work for additional information regarding copyright ownership.
|
||||||
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
(the "License"); you may not use this file except in compliance with
|
||||||
|
the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
==================================================================== */
|
||||||
|
package org.apache.poi.ooxml;
|
||||||
|
|
||||||
|
import org.apache.poi.openxml4j.opc.PackageRelationship;
|
||||||
|
import org.apache.poi.openxml4j.opc.TargetMode;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a reference relationship. A reference relationship can be internal or external.
|
||||||
|
*
|
||||||
|
* @since POI 5.2.6
|
||||||
|
*/
|
||||||
|
public abstract class ReferenceRelationship {
|
||||||
|
private POIXMLDocumentPart container;
|
||||||
|
private final String relationshipType;
|
||||||
|
private final boolean external;
|
||||||
|
private final String id;
|
||||||
|
private final URI uri;
|
||||||
|
|
||||||
|
protected ReferenceRelationship(POIXMLDocumentPart container, PackageRelationship packageRelationship) {
|
||||||
|
if (packageRelationship == null) {
|
||||||
|
throw new IllegalArgumentException("packageRelationship");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.container = container;
|
||||||
|
this.relationshipType = packageRelationship.getRelationshipType();
|
||||||
|
this.uri = packageRelationship.getTargetURI();
|
||||||
|
this.external = packageRelationship.getTargetMode() == TargetMode.EXTERNAL;
|
||||||
|
this.id = packageRelationship.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ReferenceRelationship(POIXMLDocumentPart container, URI targetUri, boolean isExternal, String relationshipType, String id) {
|
||||||
|
if (targetUri == null) {
|
||||||
|
throw new IllegalArgumentException("targetUri");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.container = container;
|
||||||
|
this.relationshipType = relationshipType;
|
||||||
|
this.uri = targetUri;
|
||||||
|
this.id = id;
|
||||||
|
this.external = isExternal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public POIXMLDocumentPart getContainer() {
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRelationshipType() {
|
||||||
|
return relationshipType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isExternal() {
|
||||||
|
return external;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public URI getUri() {
|
||||||
|
return uri;
|
||||||
|
}
|
||||||
|
}
|
|
@ -186,6 +186,12 @@ public final class PackageRelationship {
|
||||||
return targetUri;
|
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
|
// Internal target
|
||||||
// If it isn't absolute, resolve it relative
|
// If it isn't absolute, resolve it relative
|
||||||
// to ourselves
|
// to ourselves
|
||||||
|
|
|
@ -21,6 +21,7 @@ import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
||||||
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
|
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.PackagePartName;
|
||||||
import org.apache.poi.openxml4j.opc.PackageRelationship;
|
import org.apache.poi.openxml4j.opc.PackageRelationship;
|
||||||
import org.apache.poi.openxml4j.opc.PackageRelationshipCollection;
|
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.PackagingURIHelper;
|
||||||
import org.apache.poi.openxml4j.opc.StreamHelper;
|
import org.apache.poi.openxml4j.opc.StreamHelper;
|
||||||
import org.apache.poi.openxml4j.opc.TargetMode;
|
import org.apache.poi.openxml4j.opc.TargetMode;
|
||||||
|
@ -154,7 +156,14 @@ public final class ZipPartMarshaller implements PartMarshaller {
|
||||||
// the relationship Target
|
// the relationship Target
|
||||||
String targetValue;
|
String targetValue;
|
||||||
URI uri = rel.getTargetURI();
|
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,
|
// Save the target as-is - we don't need to validate it,
|
||||||
// alter it etc
|
// alter it etc
|
||||||
targetValue = uri.toString();
|
targetValue = uri.toString();
|
||||||
|
|
|
@ -47,10 +47,12 @@ import org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.apache.poi.hpsf.ClassIDPredefined;
|
import org.apache.poi.hpsf.ClassIDPredefined;
|
||||||
|
import org.apache.poi.ooxml.HyperlinkRelationship;
|
||||||
import org.apache.poi.ooxml.POIXMLDocument;
|
import org.apache.poi.ooxml.POIXMLDocument;
|
||||||
import org.apache.poi.ooxml.POIXMLDocumentPart;
|
import org.apache.poi.ooxml.POIXMLDocumentPart;
|
||||||
import org.apache.poi.ooxml.POIXMLException;
|
import org.apache.poi.ooxml.POIXMLException;
|
||||||
import org.apache.poi.ooxml.POIXMLProperties;
|
import org.apache.poi.ooxml.POIXMLProperties;
|
||||||
|
import org.apache.poi.ooxml.ReferenceRelationship;
|
||||||
import org.apache.poi.ooxml.util.PackageHelper;
|
import org.apache.poi.ooxml.util.PackageHelper;
|
||||||
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
|
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
|
||||||
import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
|
import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
|
||||||
|
@ -683,6 +685,14 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Date1904Su
|
||||||
addRelation(rp, clonedSheet);
|
addRelation(rp, clonedSheet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// copy sheet's reference relations;
|
||||||
|
List<ReferenceRelationship> referenceRelationships = srcSheet.getReferenceRelationships();
|
||||||
|
for (ReferenceRelationship ref : referenceRelationships) {
|
||||||
|
if (ref instanceof HyperlinkRelationship) {
|
||||||
|
createHyperlink(ref.getUri(), ref.isExternal(), ref.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for(PackageRelationship pr : srcSheet.getPackagePart().getRelationships()) {
|
for(PackageRelationship pr : srcSheet.getPackagePart().getRelationships()) {
|
||||||
if (pr.getTargetMode() == TargetMode.EXTERNAL) {
|
if (pr.getTargetMode() == TargetMode.EXTERNAL) {
|
||||||
|
@ -742,6 +752,14 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Date1904Su
|
||||||
addRelation(rp, clonedDg);
|
addRelation(rp, clonedDg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// copy sheet's reference relations;
|
||||||
|
List<ReferenceRelationship> srcRefs = drawingPatriarch.getReferenceRelationships();
|
||||||
|
for (ReferenceRelationship ref : srcRefs) {
|
||||||
|
if (ref instanceof HyperlinkRelationship) {
|
||||||
|
clonedDg.createHyperlink(ref.getUri(), ref.isExternal(), ref.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
XSSFSheet.cloneTables(clonedSheet);
|
XSSFSheet.cloneTables(clonedSheet);
|
||||||
|
|
|
@ -284,7 +284,7 @@ public final class TestPackage {
|
||||||
assertEquals(1, rels.size());
|
assertEquals(1, rels.size());
|
||||||
PackageRelationship rel = rels.getRelationship(0);
|
PackageRelationship rel = rels.getRelationship(0);
|
||||||
assertNotNull(rel);
|
assertNotNull(rel);
|
||||||
assertEquals("Sheet1!A1", rel.getTargetURI().getRawFragment());
|
assertEquals("#Sheet1!A1", rel.getTargetURI().toString());
|
||||||
|
|
||||||
assertMSCompatibility(pkg);
|
assertMSCompatibility(pkg);
|
||||||
}
|
}
|
||||||
|
|
|
@ -323,10 +323,11 @@ class TestRelationships {
|
||||||
|
|
||||||
PackageRelationship rId1 = drawingPart.getRelationship("rId1");
|
PackageRelationship rId1 = drawingPart.getRelationship("rId1");
|
||||||
URI parent = drawingPart.getPartName().getURI();
|
URI parent = drawingPart.getPartName().getURI();
|
||||||
URI rel1 = parent.relativize(rId1.getTargetURI());
|
// Hyperlink is not a target of relativize() because it is not resolved based on sourceURI in getTargetURI()
|
||||||
URI rel11 = PackagingURIHelper.relativizeURI(drawingPart.getPartName().getURI(), rId1.getTargetURI());
|
// URI rel1 = parent.relativize(rId1.getTargetURI());
|
||||||
assertEquals("'Another Sheet'!A1", rel1.getFragment());
|
// URI rel11 = PackagingURIHelper.relativizeURI(drawingPart.getPartName().getURI(), rId1.getTargetURI());
|
||||||
assertEquals("'Another Sheet'!A1", rel11.getFragment());
|
// assertEquals("'Another Sheet'!A1", rel1.getFragment());
|
||||||
|
// assertEquals("'Another Sheet'!A1", rel11.getFragment());
|
||||||
|
|
||||||
PackageRelationship rId2 = drawingPart.getRelationship("rId2");
|
PackageRelationship rId2 = drawingPart.getRelationship("rId2");
|
||||||
URI rel2 = PackagingURIHelper.relativizeURI(drawingPart.getPartName().getURI(), rId2.getTargetURI());
|
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.POIDataSamples;
|
||||||
import org.apache.poi.common.usermodel.HyperlinkType;
|
import org.apache.poi.common.usermodel.HyperlinkType;
|
||||||
import org.apache.poi.extractor.ExtractorFactory;
|
import org.apache.poi.extractor.ExtractorFactory;
|
||||||
|
import org.apache.poi.ooxml.HyperlinkRelationship;
|
||||||
import org.apache.poi.ooxml.POIXMLDocumentPart;
|
import org.apache.poi.ooxml.POIXMLDocumentPart;
|
||||||
import org.apache.poi.ooxml.POIXMLDocumentPart.RelationPart;
|
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.exceptions.InvalidFormatException;
|
||||||
import org.apache.poi.openxml4j.opc.OPCPackage;
|
import org.apache.poi.openxml4j.opc.OPCPackage;
|
||||||
import org.apache.poi.openxml4j.opc.PackagePartName;
|
import org.apache.poi.openxml4j.opc.PackagePartName;
|
||||||
|
@ -384,23 +386,31 @@ class TestXSLFBugs {
|
||||||
|
|
||||||
// Check the relations from this
|
// Check the relations from this
|
||||||
Collection<RelationPart> rels = slide.getRelationParts();
|
Collection<RelationPart> rels = slide.getRelationParts();
|
||||||
|
Collection<ReferenceRelationship> referenceRelationships = slide.getReferenceRelationships();
|
||||||
|
|
||||||
// Should have 6 relations:
|
// Should have 6 relations:
|
||||||
// 1 external hyperlink (skipped from list)
|
// 1 external hyperlink (skipped from list)
|
||||||
// 4 internal hyperlinks
|
// 4 internal hyperlinks
|
||||||
// 1 slide layout
|
// 1 slide layout
|
||||||
assertEquals(5, rels.size());
|
assertEquals(1, rels.size());
|
||||||
|
assertEquals(5, referenceRelationships.size());
|
||||||
int layouts = 0;
|
int layouts = 0;
|
||||||
int hyperlinks = 0;
|
int hyperlinks = 0;
|
||||||
|
int extHyperLinks = 0;
|
||||||
for (RelationPart p : rels) {
|
for (RelationPart p : rels) {
|
||||||
if (p.getRelationship().getRelationshipType().equals(XSLFRelation.HYPERLINK.getRelation())) {
|
if (p.getDocumentPart() instanceof XSLFSlideLayout) {
|
||||||
hyperlinks++;
|
|
||||||
} else if (p.getDocumentPart() instanceof XSLFSlideLayout) {
|
|
||||||
layouts++;
|
layouts++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (ReferenceRelationship ref : referenceRelationships) {
|
||||||
|
if (ref instanceof HyperlinkRelationship) {
|
||||||
|
if (ref.isExternal()) extHyperLinks++;
|
||||||
|
else hyperlinks++;
|
||||||
|
}
|
||||||
|
}
|
||||||
assertEquals(1, layouts);
|
assertEquals(1, layouts);
|
||||||
assertEquals(4, hyperlinks);
|
assertEquals(4, hyperlinks);
|
||||||
|
assertEquals(1, extHyperLinks);
|
||||||
|
|
||||||
// Hyperlinks should all be to #_ftn1 or #ftnref1
|
// Hyperlinks should all be to #_ftn1 or #ftnref1
|
||||||
for (RelationPart p : rels) {
|
for (RelationPart p : rels) {
|
||||||
|
|
|
@ -18,19 +18,31 @@
|
||||||
package org.apache.poi.xssf;
|
package org.apache.poi.xssf;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
import org.apache.poi.ooxml.ReferenceRelationship;
|
||||||
|
import org.apache.poi.openxml4j.opc.PackageRelationship;
|
||||||
import org.apache.poi.ss.usermodel.BaseTestCloneSheet;
|
import org.apache.poi.ss.usermodel.BaseTestCloneSheet;
|
||||||
import org.apache.poi.ss.usermodel.Sheet;
|
import org.apache.poi.ss.usermodel.Sheet;
|
||||||
import org.apache.poi.ss.usermodel.Workbook;
|
import org.apache.poi.ss.usermodel.Workbook;
|
||||||
import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
|
import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
|
||||||
import org.apache.poi.xssf.usermodel.XSSFDrawing;
|
import org.apache.poi.xssf.usermodel.XSSFDrawing;
|
||||||
|
import org.apache.poi.xssf.usermodel.XSSFPicture;
|
||||||
import org.apache.poi.xssf.usermodel.XSSFSheet;
|
import org.apache.poi.xssf.usermodel.XSSFSheet;
|
||||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.openxmlformats.schemas.drawingml.x2006.main.CTBlip;
|
||||||
|
import org.openxmlformats.schemas.drawingml.x2006.main.CTBlipFillProperties;
|
||||||
|
import org.openxmlformats.schemas.drawingml.x2006.main.CTHyperlink;
|
||||||
|
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
|
||||||
|
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualPictureProperties;
|
||||||
|
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTPicture;
|
||||||
|
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTPictureNonVisual;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@ -127,4 +139,74 @@ class TestXSSFCloneSheet extends BaseTestCloneSheet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testBug63189() throws IOException {
|
||||||
|
try (XSSFWorkbook workbook = XSSFTestDataSamples.openSampleWorkbook("bug63189.xlsx")) {
|
||||||
|
// given
|
||||||
|
String linkRelationType = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink";
|
||||||
|
String linkTargetUrl = "#Sheet3!A1";
|
||||||
|
String imageRelationType = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
|
||||||
|
String imageTargetUrl = "/xl/media/image1.png";
|
||||||
|
|
||||||
|
XSSFSheet srcSheet = workbook.getSheetAt(0);
|
||||||
|
assertEquals("CloneMe", srcSheet.getSheetName());
|
||||||
|
XSSFDrawing drawing = srcSheet.getDrawingPatriarch();
|
||||||
|
assertNotNull(drawing);
|
||||||
|
assertEquals(1, drawing.getShapes().size());
|
||||||
|
assertInstanceOf(XSSFPicture.class, drawing.getShapes().get(0));
|
||||||
|
XSSFPicture lPic = (XSSFPicture)drawing.getShapes().get(0);
|
||||||
|
CTPicture pic = lPic.getCTPicture();
|
||||||
|
CTPictureNonVisual nvPicPr = pic.getNvPicPr();
|
||||||
|
CTNonVisualDrawingProps cNvPr = nvPicPr.getCNvPr();
|
||||||
|
assertTrue(cNvPr.isSetHlinkClick());
|
||||||
|
CTHyperlink hlinkClick = cNvPr.getHlinkClick();
|
||||||
|
String linkRelId = hlinkClick.getId();
|
||||||
|
|
||||||
|
ReferenceRelationship linkRel = drawing.getReferenceRelationship(linkRelId);
|
||||||
|
assertEquals(linkRelationType, linkRel.getRelationshipType());
|
||||||
|
assertEquals(linkTargetUrl, linkRel.getUri().toString());
|
||||||
|
|
||||||
|
CTNonVisualPictureProperties cNvPicPr = nvPicPr.getCNvPicPr();
|
||||||
|
assertTrue(cNvPicPr.getPicLocks().getNoChangeAspect());
|
||||||
|
|
||||||
|
CTBlipFillProperties blipFill = pic.getBlipFill();
|
||||||
|
CTBlip blip = blipFill.getBlip();
|
||||||
|
String imageRelId = blip.getEmbed();
|
||||||
|
|
||||||
|
PackageRelationship imageRel = drawing.getRelationPartById(imageRelId).getRelationship();
|
||||||
|
assertEquals(imageRelationType, imageRel.getRelationshipType());
|
||||||
|
assertEquals(imageTargetUrl, imageRel.getTargetURI().toString());
|
||||||
|
|
||||||
|
// when
|
||||||
|
XSSFSheet clonedSheet = workbook.cloneSheet(0);
|
||||||
|
|
||||||
|
// then
|
||||||
|
XSSFDrawing drawing2 = clonedSheet.getDrawingPatriarch();
|
||||||
|
assertNotNull(drawing2);
|
||||||
|
assertEquals(1, drawing2.getShapes().size());
|
||||||
|
assertInstanceOf(XSSFPicture.class, drawing2.getShapes().get(0));
|
||||||
|
XSSFPicture lPic2 = (XSSFPicture)drawing2.getShapes().get(0);
|
||||||
|
CTPicture pic2 = lPic2.getCTPicture();
|
||||||
|
CTPictureNonVisual nvPicPr2 = pic2.getNvPicPr();
|
||||||
|
CTNonVisualDrawingProps cNvPr2 = nvPicPr2.getCNvPr();
|
||||||
|
assertTrue(cNvPr2.isSetHlinkClick());
|
||||||
|
CTHyperlink hlinkClick2 = cNvPr2.getHlinkClick();
|
||||||
|
String linkRelId2 = hlinkClick2.getId();
|
||||||
|
|
||||||
|
ReferenceRelationship linkRel2 = drawing2.getReferenceRelationship(linkRelId2);
|
||||||
|
assertEquals(linkRelationType, linkRel2.getRelationshipType());
|
||||||
|
assertEquals(linkTargetUrl, linkRel2.getUri().toString());
|
||||||
|
|
||||||
|
CTNonVisualPictureProperties cNvPicPr2 = nvPicPr2.getCNvPicPr();
|
||||||
|
assertTrue(cNvPicPr2.getPicLocks().getNoChangeAspect());
|
||||||
|
|
||||||
|
CTBlipFillProperties blipFill2 = pic2.getBlipFill();
|
||||||
|
CTBlip blip2 = blipFill2.getBlip();
|
||||||
|
String imageRelId2 = blip2.getEmbed();
|
||||||
|
|
||||||
|
PackageRelationship imageRel2 = drawing2.getRelationPartById(imageRelId2).getRelationship();
|
||||||
|
assertEquals(imageRelationType, imageRel2.getRelationshipType());
|
||||||
|
assertEquals(imageTargetUrl, imageRel2.getTargetURI().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,6 +60,7 @@ import org.apache.poi.ooxml.POIXMLDocumentPart;
|
||||||
import org.apache.poi.ooxml.POIXMLDocumentPart.RelationPart;
|
import org.apache.poi.ooxml.POIXMLDocumentPart.RelationPart;
|
||||||
import org.apache.poi.ooxml.POIXMLException;
|
import org.apache.poi.ooxml.POIXMLException;
|
||||||
import org.apache.poi.ooxml.POIXMLProperties;
|
import org.apache.poi.ooxml.POIXMLProperties;
|
||||||
|
import org.apache.poi.ooxml.ReferenceRelationship;
|
||||||
import org.apache.poi.ooxml.util.DocumentHelper;
|
import org.apache.poi.ooxml.util.DocumentHelper;
|
||||||
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
|
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
|
||||||
import org.apache.poi.openxml4j.exceptions.InvalidOperationException;
|
import org.apache.poi.openxml4j.exceptions.InvalidOperationException;
|
||||||
|
@ -234,18 +235,18 @@ public final class TestXSSFBugs extends BaseTestBugzillaIssues {
|
||||||
assertEquals(1, wb1.getNumberOfSheets());
|
assertEquals(1, wb1.getNumberOfSheets());
|
||||||
XSSFSheet sh = wb1.getSheetAt(0);
|
XSSFSheet sh = wb1.getSheetAt(0);
|
||||||
XSSFDrawing drawing = sh.createDrawingPatriarch();
|
XSSFDrawing drawing = sh.createDrawingPatriarch();
|
||||||
List<RelationPart> rels = drawing.getRelationParts();
|
List<ReferenceRelationship> referenceRelationships = drawing.getReferenceRelationships();
|
||||||
assertEquals(1, rels.size());
|
assertEquals(1, referenceRelationships.size());
|
||||||
assertEquals("Sheet1!A1", rels.get(0).getRelationship().getTargetURI().getFragment());
|
assertEquals("#Sheet1!A1", referenceRelationships.get(0).getUri().toString());
|
||||||
|
|
||||||
// And again, just to be sure
|
// And again, just to be sure
|
||||||
try (XSSFWorkbook wb2 = writeOutAndReadBack(wb1)) {
|
try (XSSFWorkbook wb2 = writeOutAndReadBack(wb1)) {
|
||||||
assertEquals(1, wb2.getNumberOfSheets());
|
assertEquals(1, wb2.getNumberOfSheets());
|
||||||
sh = wb2.getSheetAt(0);
|
sh = wb2.getSheetAt(0);
|
||||||
drawing = sh.createDrawingPatriarch();
|
drawing = sh.createDrawingPatriarch();
|
||||||
rels = drawing.getRelationParts();
|
referenceRelationships = drawing.getReferenceRelationships();
|
||||||
assertEquals(1, rels.size());
|
assertEquals(1, referenceRelationships.size());
|
||||||
assertEquals("Sheet1!A1", rels.get(0).getRelationship().getTargetURI().getFragment());
|
assertEquals("#Sheet1!A1", referenceRelationships.get(0).getUri().toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
Loading…
Reference in New Issue