diff --git a/NanoXLSX.Reader/Internal/Readers/DiscoveryReader.cs b/NanoXLSX.Reader/Internal/Readers/DiscoveryReader.cs index 7cbe62e73..8221afed6 100644 --- a/NanoXLSX.Reader/Internal/Readers/DiscoveryReader.cs +++ b/NanoXLSX.Reader/Internal/Readers/DiscoveryReader.cs @@ -1,4 +1,4 @@ -/* +/* * NanoXLSX is a small .NET library to generate and read XLSX (Microsoft Excel 2007 or newer) files in an easy and native way * Copyright Raphael Stoeckli © 2026 * This library is licensed under the MIT License. @@ -238,10 +238,23 @@ private RelationshipInfo ParseRelationship(XmlReader reader, string relationship string resolvedTargetPath = null; if (targetMode == TargetMode.Internal) { - if (targetUri.IsAbsoluteUri) + // [VENDOR-PATCH NanoXLSX#mono-rootrelative-target] A target beginning with '/' is a + // ROOT-RELATIVE path, which OPC permits for an internal relationship. Mono's System.Uri + // parses such a string as an ABSOLUTE Uri while .NET's does not, so testing IsAbsoluteUri + // alone silently discards every root-relative relationship on Mono. In practice that is + // sharedStrings.xml: the relationship is dropped from the catalog, the (optional) shared + // strings part is never read, and every string cell is left holding its raw shared-string + // INDEX instead of its text -- with no exception raised. Test for a real scheme instead, + // and rebuild the target as relative so ResolvePartUri agrees on both runtimes. + bool rootRelativeTarget = target.StartsWith("/", StringComparison.Ordinal); + if (targetUri.IsAbsoluteUri && !rootRelativeTarget) { return HandleRelationshipIssue(relationshipPartPath, id, "An internal relationship target cannot be an absolute URI.", issues, null); } + if (rootRelativeTarget) + { + targetUri = new Uri(target, UriKind.Relative); + } Uri sourceUri = new Uri("/" + sourcePartPath, UriKind.Relative); Uri resolvedTargetUri = PackUriHelper.ResolvePartUri(sourceUri, targetUri); resolvedTargetPath = resolvedTargetUri.OriginalString.TrimStart('/');