您运行的 Shapefiles 转换已经成功百次,但这次因 TransformationException 而中止。没有部分输出,也没有明确指示是哪条记录导致了问题。通常,罪魁祸首是一条埋在成千上万有效要素中的无效坐标。本文解释了为何 Shapefile 转换会因该错误而失败,以及如何在 C# 中使用 OperationErrorCollector(在 Aspose.GIS for .NET 26.6 中引入)进行修复。您将学习如何让转换完成,保留每个有效要素,并获取需要关注的记录的精确报告。
如果您只需要基本的转换代码,请参阅 Convert Shapefile to KML in C#。本指南在此基础上进行扩展,重点处理错误。
为什么 Shapefile 转换会抛出 TransformationException
大多数目标格式都要求使用特定的坐标系。例如,KML 总是使用 WGS 84 经度和纬度。在转换过程中,Aspose.GIS 会将源坐标系中的每个坐标转换为目标坐标系。如果任何坐标无法转换,库会抛出 TransformationException,并且转换会停止。
最常见的原因是:
- 占位符 “no data” 值。 某些工具会写入哨兵值,而不是让几何对象为空。本文示例文件包含一个点,坐标为
(-1.7976931348623157E+308, -1.7976931348623157E+308),这是double的最小值,任何坐标系都无法转换它。 - 超出范围的坐标。 这些值超出源坐标系的有效范围,通常是由于数据录入错误或单位换算错误导致的。
.prj文件与数据不匹配。 如果以米为单位的投影坐标被声明为以度为单位的地理坐标,许多数值将远远超出有效范围。- 损坏的几何记录。 旧版导出和损坏的文件可能在单个记录中包含无效的数值。
在每种情况下,问题通常仅限于少数记录,但默认行为会丢弃整个转换。
为什么此功能重要
在第一次失败时停止是安全的,但在实际流水线中代价高昂。一个错误记录会迫使您在任何数据转换之前手动清理文件,而仅凭异常本身无法告诉您还有多少其他记录受到影响。启用错误收集后,您可以:
- 将所有有效特征转换,而不是因单个错误记录导致整个文件丢失。
- 记录每个被跳过特征的索引和坐标,以便修复源数据。
- 在脏输入情况下运行无人值守的批量转换和 ETL 作业而不崩溃。
- 接受 Web 服务中用户上传的 Shapefile,并将数据问题反馈给用户。
如何在 C# 中使用 Aspose.GIS 修复 Shapefile 转换失败
Aspose.GIS for .NET 是一个托管库,用于读取、写入和转换地理空间格式,例如 Shapefile、KML、GeoJSON、GML 和文件地理数据库,无需安装其他 GIS 软件。错误收集需要 26.6 或更高版本。请从 NuGet 安装该包:
dotnet add package Aspose.GIS
或者使用包管理器控制台:
Install-Package Aspose.GIS
本教程中使用以下类型:
- VectorLayer (
Aspose.Gis): 打开、创建和转换矢量图层。VectorLayer.Convert执行转换。 - ConversionOptions (
Aspose.Gis): 保存转换设置,包括DestinationDriverOptions和DestinationSpatialReferenceSystem。 - KmlOptions (
Aspose.Gis.Formats.Kml): KML 驱动程序选项。它继承自DriverOptions的ErrorCollector属性。 - OperationErrorCollector (
Aspose.Gis.Operations): 存储可恢复的错误。它公开Errors、Count、HasErrors、Add和Clear。 - OperationError 和 TransformationError (
Aspose.Gis.Operations): 每个错误都有Message和Exception。TransformationError额外包含FeatureIndex、X、Y和Z。 - TransformationException (
Aspose.Gis.SpatialReferencing): 当坐标无法转换且未附加收集器时抛出。
如何修复 Shapefile 转换期间的 TransformationException
此修复分为两部分。首先,附加一个 OperationErrorCollector,使转换在遇到无效要素时跳过而不是失败。其次,使用收集的报告在源头修复或删除这些记录。下面的步骤以 Shapefile 转 KML 转换为例。
1. 准备环境
- 创建一个 .NET 控制台项目并添加 Aspose.GIS 26.6+ NuGet 包。
- 将 Shapefile 及其伴随文件(
.shp、.shx、.dbf和.prj)复制到同一个文件夹。本示例使用data/light-traffics.shp。 - 添加所需的命名空间:
using System;
using System.IO;
using Aspose.Gis;
using Aspose.Gis.Formats.Kml;
using Aspose.Gis.Operations;
using Aspose.Gis.SpatialReferencing;
2. 创建 OperationErrorCollector
收集器记录在转换过程中抛出的每个可恢复错误。为每次转换创建一个新实例,以免不同文件的错误混在一起。
// Records recoverable errors instead of throwing them.
var errors = new OperationErrorCollector();
3. 通过 ConversionOptions 附加收集器
将收集器分配给 KmlOptions.ErrorCollector,然后将 KML 选项作为 DestinationDriverOptions 传递。将 DestinationSpatialReferenceSystem 设置为 WGS 84 对于 KML 是可选的,但它可以在代码中明确目标坐标系。
var options = new ConversionOptions
{
// KML always uses WGS 84; stating it makes the reprojection explicit.
DestinationSpatialReferenceSystem = SpatialReferenceSystem.Wgs84,
DestinationDriverOptions = new KmlOptions
{
ErrorCollector = errors // Skip and record features that fail transformation.
}
};
4. 运行转换
调用 VectorLayer.Convert,使用源路径、Shapefile 驱动程序、目标路径、KML 驱动程序,以及您刚刚配置的选项。
string sourcePath = Path.Combine("data", "light-traffics.shp");
string destinationPath = Path.Combine("output", "light-traffics.kml");
Directory.CreateDirectory(Path.GetDirectoryName(destinationPath));
VectorLayer.Convert(sourcePath, Drivers.Shapefile, destinationPath, Drivers.Kml, options);
当某个要素无法转换时,KML 驱动程序会向收集器添加错误,跳过该要素并继续处理下一个要素。不会抛出 TransformationException。
5. 报告已跳过的功能并验证输出
即使转换正常返回,仍可能跳过某些要素,因此始终在之后检查收集器。将每个错误强制转换为 TransformationError 以获取要素索引和失败的坐标,然后打开输出文件以确认写入了多少要素。
if (errors.HasErrors)
{
Console.WriteLine($"Skipped {errors.Count} feature(s):");
foreach (var error in errors.Errors)
{
if (error is TransformationError transformationError)
{
Console.WriteLine(
$" Feature #{transformationError.FeatureIndex} at " +
$"({transformationError.X}, {transformationError.Y}, {transformationError.Z}): {error.Message}");
}
else
{
Console.WriteLine($" {error.Message}");
}
}
}
using (var layer = VectorLayer.Open(destinationPath, Drivers.Kml))
{
Console.WriteLine($"Features written to KML: {layer.Count}");
}
对于示例文件,收集器记录了一个占位点错误,其余特征(至少 444 条)被写入 KML 文件。
此报告中的要素索引和坐标已完成修复。
在数据清理工作流中打开源 Shapefile,定位报告的记录,并对其进行纠正或删除。
如果许多记录在看似合理的值下仍然失败,请首先检查 .prj 文件,因为坐标系不匹配很可能是导致此问题的原因。
6. 完整示例代码
下面的完整控制台应用程序运行两次转换。第一次运行使用默认设置并重现 TransformationException。第二次运行附加 OperationErrorCollector,跳过无效特性,并打印报告。
using System;
using System.IO;
using Aspose.Gis;
using Aspose.Gis.Formats.Kml;
using Aspose.Gis.Operations;
using Aspose.Gis.SpatialReferencing;
namespace ShapefileTransformationErrors
{
internal class Program
{
private static void Main()
{
string sourcePath = Path.Combine("data", "light-traffics.shp");
string outputFolder = "output";
Directory.CreateDirectory(outputFolder);
// -----------------------------------------------------------------
// Run 1: default behavior. The first failed transformation aborts
// the whole conversion with a TransformationException.
// -----------------------------------------------------------------
string failFastPath = Path.Combine(outputFolder, "fail-fast.kml");
try
{
VectorLayer.Convert(sourcePath, Drivers.Shapefile, failFastPath, Drivers.Kml);
Console.WriteLine("Default conversion finished without transformation errors.");
}
catch (TransformationException ex)
{
Console.WriteLine($"Default conversion aborted: {ex.Message}");
Console.WriteLine($"Failing coordinate: ({ex.X}, {ex.Y}, {ex.Z})");
}
// -----------------------------------------------------------------
// Run 2: error-tolerant conversion. Invalid features are skipped
// and recorded in the collector; valid features are written.
// -----------------------------------------------------------------
string destinationPath = Path.Combine(outputFolder, "light-traffics.kml");
var errors = new OperationErrorCollector();
var options = new ConversionOptions
{
DestinationSpatialReferenceSystem = SpatialReferenceSystem.Wgs84,
DestinationDriverOptions = new KmlOptions
{
ErrorCollector = errors
}
};
VectorLayer.Convert(sourcePath, Drivers.Shapefile, destinationPath, Drivers.Kml, options);
// Report every skipped feature so the source data can be repaired.
if (errors.HasErrors)
{
Console.WriteLine($"Conversion completed with {errors.Count} skipped feature(s):");
foreach (var error in errors.Errors)
{
if (error is TransformationError transformationError)
{
Console.WriteLine(
$" Feature #{transformationError.FeatureIndex} at " +
$"({transformationError.X}, {transformationError.Y}, {transformationError.Z}): {error.Message}");
}
else
{
Console.WriteLine($" {error.Message}");
}
}
}
else
{
Console.WriteLine("Conversion completed with no errors.");
}
// Verify the output file.
using (var layer = VectorLayer.Open(destinationPath, Drivers.Kml))
{
Console.WriteLine($"Features written to KML: {layer.Count}");
}
}
}
}
7. 常见陷阱及如何避免
| 陷阱 | 原因 | 解决方案 |
|---|---|---|
ErrorCollector 或 OperationErrorCollector 无法编译 | 两者均在 Aspose.GIS for .NET 26.6 中添加。 | 将 NuGet 包升级到 26.6 或更高版本。 |
转换仍然抛出 TransformationException | 未将收集器附加到目标驱动程序选项。 | 在分配给 ConversionOptions.DestinationDriverOptions 的驱动程序选项对象上设置 ErrorCollector。 |
| “成功”的转换缺少要素 | 收集器抑制了异常,因此 Convert 正常返回。 | 在每次调用后检查 errors.HasErrors 并记录结果。 |
| 将跳过的要素视为已修复 | 收集器会跳过无效记录;它不会修复这些记录。 | 使用报告的要素索引和坐标来纠正或删除源数据中的记录。 |
| 数百个要素一次性失败 | .prj 文件可能与实际坐标不匹配。 | 在调查单个记录之前,先验证源坐标系。 |
| 多个文件的错误出现在同一报告中 | 在多个转换中重复使用了同一个收集器实例。 | 为每个文件创建新的 OperationErrorCollector,或在运行之间调用 Clear()。 |
| 重复运行时出现文件锁错误 | 使用 VectorLayer.Open 打开的图层未被释放。 | 将 VectorLayer.Open 包装在 using 块中。 |
获取免费许可证
您可以从 Aspose 临时许可证页面获取 Aspose.GIS 的临时免费许可证:https://purchase.aspose.com/temporary-license/
免费附加资源
- 文档: https://docs.aspose.com/gis/net/
- API 参考: https://reference.aspose.com/gis/net/
- 免费 Web 应用: https://products.aspose.app/gis/family
结论
A TransformationException 在 Shapefile 转换过程中通常表示少量记录包含无法转换的坐标,例如占位符值、超出范围的数字,或与其 .prj 文件不匹配的数据。 在 C# 中修复它需要两个步骤:首先附加 OperationErrorCollector,让 Aspose.GIS for .NET 跳过无效要素并完成转换;然后使用收集到的要素索引和坐标来修复源数据。 结果是一个管道,能够持续输出有效结果,同时将硬性失败转化为可操作的数据质量报告。
常见问题
为什么在转换 Shapefile 时会出现 TransformationException? 它发生在坐标无法从源坐标系转换到目标坐标系时。常见原因包括占位符 “no data” 值、坐标超出其坐标系的有效范围、
.prj文件与实际数据不匹配,以及几何记录损坏。默认情况下,当坐标无法转换时会发生什么?
VectorLayer.Convert抛出TransformationException并且转换停止。自 26.6 版起,异常还会公开导致失败的坐标的X、Y和Z值。哪个版本的 Aspose.GIS for .NET 支持 OperationErrorCollector?
OperationErrorCollector和DriverOptions.ErrorCollector属性是在 Aspose.GIS for .NET 26.6 中引入的。早期版本不包含它们。OperationErrorCollector 是否修复无效坐标? 不。它会跳过转换失败的要素并记录它们,因此输出仅包含有效的要素。使用报告的要素索引和坐标来修复或删除源数据中的错误记录。
我可以在除 KML 之外的输出格式中使用 OperationErrorCollector 吗?
ErrorCollector在基类DriverOptions中定义,因此每个驱动程序选项类都公开它。文档示例涵盖 KML 和 MapInfo TAB 目标;在生产环境中依赖之前,请使用您自己的目标驱动程序测试其行为。每个收集的错误包含哪些细节? 每个
OperationError提供一个Message和底层的Exception。转换失败会以TransformationError对象的形式报告,该对象会添加失败坐标的FeatureIndex以及X、Y、Z值。我如何知道转换是否在没有任何错误的情况下完成? 在
VectorLayer.Convert返回后,检查收集器的HasErrors或Count属性。即使转换未抛出异常,也可能跳过了一些要素。
