Converting GML (Geography Markup Language) files looks simple until the reader cannot find the XML schema. A GML file describes its feature types and attributes in a separate XSD that is referenced through the schemaLocation attribute. When that schema has been lost, moved, or cannot be downloaded, the attribute definitions go with it, and a conversion job that worked on your machine starts failing on a build server. This guide shows how to preserve GML schema information during conversion in C# using Aspose.GIS for .NET, and how to prove that features and attributes survived the round trip.

Why Preserving the GML Schema Matters

GML is a popular interchange format because it carries geometry and attribute data together. The structure of that data, meaning the feature types, attribute names, and data types, is defined by an application schema. Aspose.GIS reads this schema to build a layer’s attribute collection, so the schema is what turns raw XML into usable columns in your code, in QGIS, or in ArcGIS.

In real pipelines the schema is often the weakest link. Files are copied without their XSD, schemaLocation points to an outdated URL, or the server running the conversion has no internet access. In these cases Aspose.GIS stops with a GisException explaining that it failed to build the feature attribute collection. The GmlOptions.RestoreSchema option solves this by allowing the reader to reconstruct the attribute schema from the feature data itself, so your conversions keep their attributes instead of failing or producing incomplete output.

Getting Started with Aspose.GIS for .NET

Aspose.GIS for .NET is a managed library for reading, writing, and converting GIS formats such as GML, Shapefile, GeoJSON, KML, and File Geodatabase, without requiring ArcGIS or QGIS on the machine. Add it to your project from NuGet:

Install-Package Aspose.GIS

Or with the .NET CLI:

dotnet add package Aspose.GIS

You can learn more on the Aspose.GIS for .NET product page and in the Aspose.GIS .NET API Reference. The two namespaces used in this tutorial are Aspose.Gis, which contains VectorLayer, Drivers, and ConversionOptions, and Aspose.Gis.Formats.Gml, which contains GmlOptions.

Step-by-Step Tutorial to Preserve GML Schema

The following C# example converts a GML file to a new GML file while restoring the attribute schema, then verifies the result. It targets .NET 6 or later.

What the example does

  1. Creates reader options with GmlOptions.RestoreSchema set to true.
  2. Opens the source GML and records its feature count and attribute names.
  3. Converts the file with VectorLayer.Convert, passing the reader options through ConversionOptions.SourceDriverOptions.
  4. Reopens the output with schema restoration and compares it against the source.
using System;
using System.IO;
using System.Linq;
using Aspose.Gis;
using Aspose.Gis.Formats.Gml;

class PreserveGmlSchema
{
    static void Main()
    {
        // Input and output paths. Adjust them to your environment.
        string sourcePath = Path.Combine("data", "input.gml");
        string destinationPath = Path.Combine("data", "output.gml");

        // Step 1: Capture the structure of the source layer.
        // RestoreSchema lets the reader infer attributes when the XSD is missing or unreachable.
        int sourceFeatureCount;
        string[] sourceAttributeNames;

        using (VectorLayer source = VectorLayer.Open(sourcePath, Drivers.Gml, CreateReadOptions()))
        {
            sourceFeatureCount = source.Count;
            sourceAttributeNames = source.Attributes.Select(a => a.Name).ToArray();
        }

        // Step 2: Convert GML to GML. RestoreSchema is a reader option,
        // so it is supplied through SourceDriverOptions.
        var conversionOptions = new ConversionOptions
        {
            SourceDriverOptions = CreateReadOptions()
        };

        VectorLayer.Convert(sourcePath, Drivers.Gml, destinationPath, Drivers.Gml, conversionOptions);

        // Step 3: Reopen the output and compare it with the source.
        using (VectorLayer output = VectorLayer.Open(destinationPath, Drivers.Gml, CreateReadOptions()))
        {
            if (output.Count != sourceFeatureCount)
            {
                throw new InvalidOperationException(
                    $"Feature count mismatch: source has {sourceFeatureCount}, output has {output.Count}.");
            }

            string[] outputAttributeNames = output.Attributes.Select(a => a.Name).ToArray();
            string[] missingAttributes = sourceAttributeNames.Except(outputAttributeNames).ToArray();

            if (missingAttributes.Length > 0)
            {
                throw new InvalidOperationException(
                    $"Attributes missing from output: {string.Join(", ", missingAttributes)}");
            }

            Console.WriteLine($"Converted {output.Count} features with {output.Attributes.Count} attributes:");

            foreach (FeatureAttribute attribute in output.Attributes)
            {
                Console.WriteLine($"  {attribute.Name} ({attribute.DataType})");
            }
        }
    }

    // A fresh options instance for each read keeps the configuration explicit.
    static GmlOptions CreateReadOptions() => new GmlOptions { RestoreSchema = true };
}

Explanation of Each Step

  • Creating reader options – GmlOptions holds GML-specific driver settings. According to the GmlOptions.RestoreSchema reference, setting it to true means the reader no longer requires an XML schema. The driver scans the file for known GML structures and infers the feature classes and their properties. The default is false.
  • Capturing the source structure – Opening the source with VectorLayer.Open gives you a baseline. layer.Count returns the number of features, and layer.Attributes exposes the attribute collection, where each FeatureAttribute has a Name and a DataType.
  • Calling VectorLayer.Convert – The overload used here accepts the source path, source driver, destination path, destination driver, and a ConversionOptions object. SourceDriverOptions controls how the input is read, while DestinationDriverOptions controls how the output is written. Since RestoreSchema affects reading, it goes on the source side.
  • Verifying the output – The output is reopened with the same reader option so verification does not depend on an XSD being present. Instead of hard-coded numbers, the sample compares the output against the source. It fails when features or attributes are lost and prints the restored attribute names and data types for review. Extra attributes are not treated as errors, because identifiers such as gml_id may be exposed differently after conversion.

Reading GML When the Original XSD Is Available

Schema restoration is a fallback. If you still have the original schema file, point the reader to it with SchemaLocation so attribute definitions come from the XSD rather than being inferred:

using System;
using Aspose.Gis;
using Aspose.Gis.Formats.Gml;

var options = new GmlOptions
{
    // Space-separated pair: namespace URI, then the path to its XML schema.
    SchemaLocation = "http://www.example.com/myfeatures schema.xsd",
    LoadSchemasFromInternet = false
};

using (VectorLayer layer = VectorLayer.Open("input.gml", Drivers.Gml, options))
{
    Console.WriteLine($"Features: {layer.Count}, attributes: {layer.Attributes.Count}");
}

When SchemaLocation is null (the default), Aspose.GIS reads schemaLocation from the root element of the GML document. LoadSchemasFromInternet is false by default, so schemas referenced by absolute non-file:// URIs are not downloaded unless you enable it.

Get a Free License

Aspose.GIS runs in evaluation mode with limitations until a license is applied. To test the full feature set, request a Free Temporary License and apply it before your first GIS operation:

var license = new Aspose.Gis.License();
license.SetLicense("Aspose.GIS.NET.lic");

Free Additional Resources

Conclusion

Preserving GML schema information during conversion comes down to controlling how the source is read. With GmlOptions.RestoreSchema passed through ConversionOptions.SourceDriverOptions, Aspose.GIS for .NET can rebuild attribute definitions even when the XSD is missing or unreachable, so conversions keep their data instead of failing. Pairing that option with a source-to-output comparison gives you evidence that features and attributes made it through, and switching to SchemaLocation when the original schema is available gives you the most faithful result. Together, these practices make GML conversion reliable in batch jobs, web services, and CI pipelines.

FAQs

1. What does GmlOptions.RestoreSchema actually do? It lets the Aspose.GIS GML reader parse feature attributes when the XML schema (XSD) referenced by the file is missing or cannot be loaded. The driver scans the document for known GML structures and infers the feature classes and their properties from the data. The default value is false.

2. Do I need to set RestoreSchema for both the conversion and the output file? Only for files whose schema cannot be loaded. RestoreSchema is a reader option, so during conversion it belongs in ConversionOptions.SourceDriverOptions, and when you reopen the output you pass it to VectorLayer.Open. The sample sets it in both places so the workflow does not depend on an XSD being available.

3. What happens if RestoreSchema is false and the schema is missing? Aspose.GIS cannot build the feature attribute collection and throws a GisException. The exception message suggests setting RestoreSchema to true, or LoadSchemasFromInternet to true when the schema is hosted online.

4. Is a restored schema identical to the original XSD? Not necessarily. Aspose.GIS describes schema restoration as error prone because attributes are inferred by scanning the file. Verify the result, as the sample does, and use GmlOptions.SchemaLocation when you have the original XSD.

5. Can I use RestoreSchema when converting GML to Shapefile, GeoJSON, or other formats? Yes. SourceDriverOptions controls how the GML source is read regardless of the destination driver. The restored attributes are then written using the destination format’s own attribute model.

6. Do I need a license to run this code? No. Without a license, Aspose.GIS runs in evaluation mode with limitations. A free temporary license removes those limitations for testing, and production use requires a purchased license.

Read More