This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git

commit 05930cba1e5e93314508ea83fc455c880a0aef20
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Fri Feb 2 17:12:47 2024 +0100

    Resolve relative path of the form "file:something#foo".
    Before this commit, the "#foo" fragment prevented the resolution.
---
 .../apache/sis/xml/util/ExternalLinkHandler.java   | 43 +++++++++++++---------
 .../main/org/apache/sis/xml/util/URISource.java    | 13 ++++++-
 2 files changed, 38 insertions(+), 18 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/util/ExternalLinkHandler.java
 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/util/ExternalLinkHandler.java
index dd4c91e0dd..a7f98045a9 100644
--- 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/util/ExternalLinkHandler.java
+++ 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/util/ExternalLinkHandler.java
@@ -56,12 +56,21 @@ public class ExternalLinkHandler {
      * If the conversion fails, then this value is set to {@code null} for 
avoiding to try again.
      *
      * <p>Note that the URI is a path to the sibling document rather than a 
path to the parent directory.
-     * This is okay, {@link URI#resolve(URI)} appears to behave as intended 
for deriving relative paths.</p>
+     * This is okay, {@link URI#resolve(URI)} appears to behave as intended 
for deriving relative paths.
+     * Fragment (the text after '#'), if any, will be ignored.</p>
      *
      * @see #resolve(URI)
      */
     private Object base;
 
+    /**
+     * The fragment (without leading dash) from a {@link URL}, {@link URI} or 
{@link CharSequence} instance.
+     * If no fragment is found, or if the {@linkplain #base} does not support 
fragments, this is {@code null}.
+     *
+     * @see #getFragment()
+     */
+    private String fragment;
+
     /**
      * Creates a new resolver for documents relative to the document in the 
specified URL.
      * The given URL can be what StAX, SAX and DOM call {@code systemId}.
@@ -77,7 +86,7 @@ public class ExternalLinkHandler {
     /**
      * Creates a new resolver for documents relative to the document in the 
specified file.
      *
-     * @param  sibling  path to the sibling document, or {@code null} if none.
+     * @param  sibling  path to the sibling document.
      */
     public ExternalLinkHandler(final File sibling) {
         base = sibling;
@@ -86,20 +95,23 @@ public class ExternalLinkHandler {
     /**
      * Creates a new resolver for documents relative to the document at the 
specified URL.
      *
-     * @param  sibling  URL to the sibling document, or {@code null} if none.
+     * @param  sibling  URL to the sibling document.
      */
     public ExternalLinkHandler(final URL sibling) {
         base = sibling;
+        fragment = sibling.getRef();
     }
 
     /**
      * Creates a new resolver for documents relative to the document read from 
the specified source.
      *
-     * @param  sibling  source to the sibling document, or {@code null} if 
none.
+     * @param  sibling  source to the sibling document.
      */
     public ExternalLinkHandler(final Source sibling) {
         if (sibling instanceof URISource) {
-            base = ((URISource) sibling).document;
+            final var s = (URISource) sibling;
+            base = s.document;
+            fragment = s.fragment;
         } else {
             base = sibling.getSystemId();
         }
@@ -108,7 +120,7 @@ public class ExternalLinkHandler {
     /**
      * Creates a new resolver for documents relative to the document written 
to the specified result.
      *
-     * @param  sibling  result of the sibling document, or {@code null} if 
none.
+     * @param  sibling  result of the sibling document.
      */
     public ExternalLinkHandler(final Result sibling) {
         base = sibling.getSystemId();
@@ -129,23 +141,20 @@ public class ExternalLinkHandler {
      * @return the fragment in the base URI, or {@code null} if none.
      */
     public final String getFragment() {
-        if (base instanceof URI) {
-            return ((URI) base).getFragment();
-        } else if (base instanceof URL) {
-            return ((URL) base).getRef();
-        } else if (base instanceof String) {
-            final var b = (String) base;
-            final int s = b.lastIndexOf('#');
-            if (s >= 0) {
-                return b.substring(s+1);
+        if (fragment == null) {
+            final URI uri = getURI();
+            if (uri != null) {
+                fragment = uri.getFragment();
             }
         }
-        return null;
+        return fragment;
     }
 
     /**
-     * {@return the base URI of the link handler}. This is the same value as 
{@link #getBase()},
+     * Returns the base URI of the link handler. This is the same value as 
{@link #getBase()},
      * but converted to an {@link URI} object when first invoked.
+     *
+     * @return the base URI of the link handler, or {@code null} if none.
      */
     public final URI getURI() {
         final Object b = base;
diff --git 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/util/URISource.java
 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/util/URISource.java
index a9cec509b1..38aed58dbe 100644
--- 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/util/URISource.java
+++ 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/util/URISource.java
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.xml.util;
 
+import java.io.File;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.io.InputStream;
@@ -54,7 +55,17 @@ public final class URISource extends StreamSource {
     URISource(URI source) throws URISyntaxException {
         source = source.normalize();
         // Build a new URI unconditionally because it also decodes escaped 
characters.
-        final URI c = new URI(source.getScheme(), 
source.getSchemeSpecificPart(), null);
+        URI c = new URI(source.getScheme(), source.getSchemeSpecificPart(), 
null);
+        if (c.isOpaque() && "file".equalsIgnoreCase(c.getScheme())) {
+            /*
+             * If the URI is "file:something" without "/" or "///" characters, 
resolve as an absolute path.
+             * This special case happens if `IOUtilities.toFileOrURI(String)` 
did not converted a string to
+             * a `java.io.File` because it contains a fragment. Since this 
constructor removed the fragment,
+             * we can now attempt this conversion again. The result will be an 
absolute path. This is needed
+             * for `URI.resolve(URI)` to work.
+             */
+            c = new File(c.getSchemeSpecificPart()).toURI();
+        }
         document = source.equals(c) ? source : c;       // Share the existing 
instance if applicable.
         fragment = Strings.trimOrNull(source.getFragment());
     }

Reply via email to