Author: fanningpj
Date: Fri Apr 19 09:23:54 2024
New Revision: 1917134

URL: http://svn.apache.org/viewvc?rev=1917134&view=rev
Log:
[bug-63189] support hyperlink relationships. Thanks to Ohyoung Kwon. This 
closes #617

Added:
    
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/ooxml/HyperlinkRelationship.java
    
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/ooxml/ReferenceRelationship.java
    poi/trunk/test-data/spreadsheet/bug63189.xlsx
Modified:
    
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/ooxml/POIXMLDocumentPart.java
    
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/PackageRelationship.java
    
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/marshallers/ZipPartMarshaller.java
    
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
    
poi/trunk/poi-ooxml/src/test/java/org/apache/poi/openxml4j/opc/TestPackage.java
    
poi/trunk/poi-ooxml/src/test/java/org/apache/poi/openxml4j/opc/TestRelationships.java
    poi/trunk/poi-ooxml/src/test/java/org/apache/poi/xslf/TestXSLFBugs.java
    
poi/trunk/poi-ooxml/src/test/java/org/apache/poi/xssf/TestXSSFCloneSheet.java
    
poi/trunk/poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFBugs.java

Added: 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/ooxml/HyperlinkRelationship.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/poi-ooxml/src/main/java/org/apache/poi/ooxml/HyperlinkRelationship.java?rev=1917134&view=auto
==============================================================================
--- 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/ooxml/HyperlinkRelationship.java
 (added)
+++ 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/ooxml/HyperlinkRelationship.java
 Fri Apr 19 09:23:54 2024
@@ -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;
+    }
+}

Modified: 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/ooxml/POIXMLDocumentPart.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/poi-ooxml/src/main/java/org/apache/poi/ooxml/POIXMLDocumentPart.java?rev=1917134&r1=1917133&r2=1917134&view=diff
==============================================================================
--- 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/ooxml/POIXMLDocumentPart.java 
(original)
+++ 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/ooxml/POIXMLDocumentPart.java 
Fri Apr 19 09:23:54 2024
@@ -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;
@@ -38,7 +39,6 @@ import org.apache.poi.openxml4j.opc.Pack
 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.util.IOUtils;
 import org.apache.poi.util.Internal;
 import org.apache.poi.xddf.usermodel.chart.XDDFChart;
 import org.apache.poi.xssf.usermodel.XSSFRelation;
@@ -59,6 +59,7 @@ public class POIXMLDocumentPart {
     private PackagePart packagePart;
     private POIXMLDocumentPart parent;
     private final Map<String, RelationPart> relations = new LinkedHashMap<>();
+    private final Map<String, ReferenceRelationship> referenceRelationships = 
new LinkedHashMap<>();
     private boolean isCommitted = false;
 
     /**
@@ -640,38 +641,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.HYPERLINK_REL_TYPE)) {
+                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);
+                }
             }
         }
 
@@ -767,4 +772,31 @@ public class POIXMLDocumentPart {
             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);
+    }
 }

Added: 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/ooxml/ReferenceRelationship.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/poi-ooxml/src/main/java/org/apache/poi/ooxml/ReferenceRelationship.java?rev=1917134&view=auto
==============================================================================
--- 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/ooxml/ReferenceRelationship.java
 (added)
+++ 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/ooxml/ReferenceRelationship.java
 Fri Apr 19 09:23:54 2024
@@ -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;
+    }
+}

Modified: 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/PackageRelationship.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/PackageRelationship.java?rev=1917134&r1=1917133&r2=1917134&view=diff
==============================================================================
--- 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/PackageRelationship.java
 (original)
+++ 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/PackageRelationship.java
 Fri Apr 19 09:23:54 2024
@@ -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

Modified: 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/marshallers/ZipPartMarshaller.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/marshallers/ZipPartMarshaller.java?rev=1917134&r1=1917133&r2=1917134&view=diff
==============================================================================
--- 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/marshallers/ZipPartMarshaller.java
 (original)
+++ 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/marshallers/ZipPartMarshaller.java
 Fri Apr 19 09:23:54 2024
@@ -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.Pack
 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 imp
             // 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();

Modified: 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/poi-ooxml/src/main/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java?rev=1917134&r1=1917133&r2=1917134&view=diff
==============================================================================
--- 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
 (original)
+++ 
poi/trunk/poi-ooxml/src/main/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
 Fri Apr 19 09:23:54 2024
@@ -47,10 +47,12 @@ import org.apache.commons.io.output.Unsy
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.apache.poi.hpsf.ClassIDPredefined;
+import org.apache.poi.ooxml.HyperlinkRelationship;
 import org.apache.poi.ooxml.POIXMLDocument;
 import org.apache.poi.ooxml.POIXMLDocumentPart;
 import org.apache.poi.ooxml.POIXMLException;
 import org.apache.poi.ooxml.POIXMLProperties;
+import org.apache.poi.ooxml.ReferenceRelationship;
 import org.apache.poi.ooxml.util.PackageHelper;
 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
@@ -683,6 +685,14 @@ public class XSSFWorkbook extends POIXML
             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 {
             for(PackageRelationship pr : 
srcSheet.getPackagePart().getRelationships()) {
                 if (pr.getTargetMode() == TargetMode.EXTERNAL) {
@@ -742,6 +752,14 @@ public class XSSFWorkbook extends POIXML
                         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);

Modified: 
poi/trunk/poi-ooxml/src/test/java/org/apache/poi/openxml4j/opc/TestPackage.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/poi-ooxml/src/test/java/org/apache/poi/openxml4j/opc/TestPackage.java?rev=1917134&r1=1917133&r2=1917134&view=diff
==============================================================================
--- 
poi/trunk/poi-ooxml/src/test/java/org/apache/poi/openxml4j/opc/TestPackage.java 
(original)
+++ 
poi/trunk/poi-ooxml/src/test/java/org/apache/poi/openxml4j/opc/TestPackage.java 
Fri Apr 19 09:23:54 2024
@@ -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);
         }

Modified: 
poi/trunk/poi-ooxml/src/test/java/org/apache/poi/openxml4j/opc/TestRelationships.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/poi-ooxml/src/test/java/org/apache/poi/openxml4j/opc/TestRelationships.java?rev=1917134&r1=1917133&r2=1917134&view=diff
==============================================================================
--- 
poi/trunk/poi-ooxml/src/test/java/org/apache/poi/openxml4j/opc/TestRelationships.java
 (original)
+++ 
poi/trunk/poi-ooxml/src/test/java/org/apache/poi/openxml4j/opc/TestRelationships.java
 Fri Apr 19 09:23:54 2024
@@ -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());

Modified: 
poi/trunk/poi-ooxml/src/test/java/org/apache/poi/xslf/TestXSLFBugs.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/poi-ooxml/src/test/java/org/apache/poi/xslf/TestXSLFBugs.java?rev=1917134&r1=1917133&r2=1917134&view=diff
==============================================================================
--- poi/trunk/poi-ooxml/src/test/java/org/apache/poi/xslf/TestXSLFBugs.java 
(original)
+++ poi/trunk/poi-ooxml/src/test/java/org/apache/poi/xslf/TestXSLFBugs.java Fri 
Apr 19 09:23:54 2024
@@ -53,8 +53,10 @@ import org.apache.commons.io.output.Null
 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) {

Modified: 
poi/trunk/poi-ooxml/src/test/java/org/apache/poi/xssf/TestXSSFCloneSheet.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/poi-ooxml/src/test/java/org/apache/poi/xssf/TestXSSFCloneSheet.java?rev=1917134&r1=1917133&r2=1917134&view=diff
==============================================================================
--- 
poi/trunk/poi-ooxml/src/test/java/org/apache/poi/xssf/TestXSSFCloneSheet.java 
(original)
+++ 
poi/trunk/poi-ooxml/src/test/java/org/apache/poi/xssf/TestXSSFCloneSheet.java 
Fri Apr 19 09:23:54 2024
@@ -18,19 +18,31 @@
 package org.apache.poi.xssf;
 
 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.assertNotNull;
 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.Sheet;
 import org.apache.poi.ss.usermodel.Workbook;
 import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
 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.XSSFWorkbook;
 import org.junit.jupiter.api.BeforeEach;
 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;
 
@@ -127,4 +139,74 @@ class TestXSSFCloneSheet  extends BaseTe
         }
     }
 
+    @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());
+        }
+    }
 }

Modified: 
poi/trunk/poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFBugs.java
URL: 
http://svn.apache.org/viewvc/poi/trunk/poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFBugs.java?rev=1917134&r1=1917133&r2=1917134&view=diff
==============================================================================
--- 
poi/trunk/poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFBugs.java
 (original)
+++ 
poi/trunk/poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFBugs.java
 Fri Apr 19 09:23:54 2024
@@ -60,6 +60,7 @@ import org.apache.poi.ooxml.POIXMLDocume
 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
             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());
             }
         }
     }

Added: poi/trunk/test-data/spreadsheet/bug63189.xlsx
URL: 
http://svn.apache.org/viewvc/poi/trunk/test-data/spreadsheet/bug63189.xlsx?rev=1917134&view=auto
==============================================================================
Binary files poi/trunk/test-data/spreadsheet/bug63189.xlsx (added) and 
poi/trunk/test-data/spreadsheet/bug63189.xlsx Fri Apr 19 09:23:54 2024 differ



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to