DocumentFormat.OpenXml.Packaging.OpenXmlPackageException:“A malformed URI was found in the document. Please provide a OpenSettings.RelationshipErrorRewriter to handle these errors while opening a package.”
或者在更古老的 OpenXML SDK 里面会提示下面代码
DocumentFormat.OpenXml.Packaging.OpenXmlPackageException: Invalid Hyperlink: Malformed URI is embedded as a hyperlink in the document.
at DocumentFormat.OpenXml.Packaging.OpenXmlPackage.Load() in OpenXmlPackage.cs: line 490
at DocumentFormat.OpenXml.Packaging.OpenXmlPackage.OpenCore(String path, Boolean readWriteMode) in OpenXmlPackage.cs: line 402
at DocumentFormat.OpenXml.Packaging.WordprocessingDocument.Open(String path, Boolean isEditable, OpenSettings openSettings) in PackageDocument.cs: line 297
at DocumentFormat.OpenXml.Packaging.WordprocessingDocument.Open(String path, Boolean isEditable) in PackageDocument.cs: line 256
和以下内容代码
at System.Uri.CreateThis(String uri, Boolean dontEscape, UriKind uriKind)
at System.Uri..ctor(String uriString, UriKind uriKind)
at MS.Internal.IO.Packaging.InternalRelationshipCollection.ProcessRelationshipAttributes(XmlCompatibilityReader reader)
at MS.Internal.IO.Packaging.InternalRelationshipCollection.ParseRelationshipPart(PackagePart part)
at MS.Internal.IO.Packaging.InternalRelationshipCollection..ctor(Package package, PackagePart part)
at System.IO.Packaging.PackagePart.EnsureRelationships()
at System.IO.Packaging.PackagePart.GetRelationshipsHelper(String filterString)
at System.IO.Packaging.PackagePart.GetRelationships()
at DocumentFormat.OpenXml.Packaging.PackagePartRelationshipPropertyCollection..ctor(PackagePart packagePart)
at DocumentFormat.OpenXml.Packaging.OpenXmlPart.Load(OpenXmlPackage openXmlPackage, OpenXmlPart parent, Uri uriTarget, String id, Dictionary`2 loadedParts)
at DocumentFormat.OpenXml.Packaging.OpenXmlPartContainer.LoadReferencedPartsAndRelationships(OpenXmlPackage openXmlPackage, OpenXmlPart sourcePart, RelationshipCollection relationshipCollection, Dictionary`2 loadedParts)
at DocumentFormat.OpenXml.Packaging.OpenXmlPackage.Load()
这是一个古老的坑,在 2015 就有人在官方报告,请看 Malformed mailto Hyperlink causes Exception on .NET 4.5+ · Issue #38 · OfficeDev/Open-XML-SDK
而在 OpenXML SDK 的 2.12.0 终于提供了修复方法,更改代码请看 Add a relationship rewriter to help sanitize malformed URIs by twsouthwick · Pull Request #793 · OfficeDev/Open-XML-SDK
可以看到我也在这个修复中,提了一些有趣的看法
在 2.12.0 或以上的版本,可以在 OpenSettings 里面传入如何处理格式不对的 Uri 的文档,如本文使用到的测试文档,这是一个 Excel 文档,这个文档里面包含下面代码
<t xml:space="preserve">mailto:mailto@one@ </t>
可以看到这个超链接是格式不正确的,此时如果使用 Uri 的构造函数传入,将会提示格式出错
在 2.12.0 或以上版本提供了重写的方法,判断如果格式不正确,那么让开发者返回一个正确的格式,重新写入回文档,这样就能修复此问题,如下面代码的实现
var openSettings = new OpenSettings()
RelationshipErrorHandlerFactory = RelationshipErrorHandler.CreateRewriterFactory(Rewriter)
以上代码使用了 RelationshipErrorHandler.CreateRewriterFactory 方法传入了 Rewriter 方法,在 Rewriter 方法里面提供了返回正确的值的方法
/// <summary>
/// 表示如何重写修复超链接格式
/// </summary>
/// <param name="partUri">这个 <paramref name="uri"/> 属于哪个文档 Part 内容,值如 /xl/worksheets/_rels/sheet1.xml.rels 等</param>
/// <param name="id">这个资源的值</param>
/// <param name="uri">格式不对的 Uri 内容</param>
/// <returns></returns>
static string Rewriter(Uri partUri, string id, string uri)
=> $"http://unknown?id={id}";
在创建文档读取的时候,传入 OpenSettings 即可,如打开 Excel 文档