Table of Contents

EncDotNet.S100.Datasets.S122

Library for reading and portraying IHO S-122 (Marine Protected Areas) datasets.

S-122 provides a standard data model for distributing information about marine protected areas, restricted areas, vessel traffic service areas, and related zoned overlays as GML-encoded datasets conforming to the S-100 framework.

Features

  • Parse S-122 GML datasets (S-100 Part 10b encoding)
  • Extract feature instances (MarineProtectedArea, RestrictedArea, VesselTrafficServiceArea, DataCoverage, InformationArea, QualityOfNonBathymetricData, TextPlacement)
  • Convert to S-100 Part 9 FeatureXML for portrayal pipeline consumption
  • XSLT-based portrayal via the bundled S-122 Portrayal Catalogue (v2.0.0)

Overview

Key types include:

  • S122Dataset — root model containing parsed features, information types, and dataset identification. ReadMetadata() (plus static ReadMetadata(path) / ReadMetadata(stream)) is the phased-loading "peek" path (issue #460): it returns a DatasetMetadata with the declared spec and the raw WGS-84 extent folded from feature geometry (null when the dataset carries only geometry-less container features), skipping the XSLT portrayal pipeline.
  • S122Feature — a geographic feature with type code, geometry, simple attributes, and complex attributes.
  • S122InformationType — a non-geographic information type instance (e.g. Authority, Regulations, SpatialQuality).
  • S122ComplexAttribute — a complex attribute instance containing sub-attribute values.
  • S100GeometryType — shared enum (from EncDotNet.S100.Core) describing the geometry primitive type of a feature.
  • FeatureXML projection — there is no S-122-specific source type: the S-122 dataset processor in EncDotNet.S100.Datasets.Pipelines projects an S122Dataset into S-100 Part 9 FeatureXML for the XSLT portrayal rules with the shared GmlFeatureXmlSource<TFeature> from EncDotNet.S100.Core.
  • S122PortrayalCatalogue — IVectorPortrayalCatalogue implementation that loads XSLT rules, symbols, line styles, area fills, and color palettes.

Notes

  • Coordinate ordering in <gml:pos> / <gml:posList> is lat lon for EPSG:4326 (S-100 Part 10b convention).
  • Producer-bug compensation: lon-lat axis order. Some S-122 producers (notably the UKHO trial dataset GBNPI12200002045.gml) emit <gml:posList> in lon-lat order while keeping <gml:Envelope> corners correctly in lat-lon. The reader detects this by sampling parsed feature coords against the declared envelope; if the as-parsed interpretation clearly falls outside but the swapped interpretation clearly falls inside, every feature's coordinates are swapped before they reach the pipeline. Spec-conformant datasets are left untouched.
  • Producer-bug compensation: comma-separated tuples in posList. GML 3.2 mandates whitespace-only separators inside <gml:posList>, but some S-122 producers emit lon,lat lon,lat ... tokens (the older gml:coordinates convention). The reader treats both whitespace and commas as coordinate separators so either shape parses correctly.
  • The reader tolerates the s100gml namespace variants found across S-122 sample releases (http://www.iho.int/s100gml/1.0, http://www.iho.int/S100/profile/s100gml/1.0, http://www.iho.int/s100gml/5.0) and falls back to scanning the document's namespace declarations.
  • Both the standard <member>/<imember> wrappers and the inline <members>/<imembers> containers used by some sample datasets are supported.
  • Palette switching is currently a no-op for S-122. The bundled v2.0.0 Portrayal Catalogue ships only a Day <palette> block in colorProfile.xml, even though duskSvgStyle.css and nightSvgStyle.css are present in Symbols/. As a result, requesting Dusk or Night through SwitchPalette silently leaves ActivePalette = Day and the renderer keeps resolving colour tokens to their Day sRGB values. TODO: synthesise Dusk / Night palettes locally (e.g. from the S-101 PC or via the ship-provided CSS files) so the viewer can offer night-mode S-122 portrayal until upstream publishes the missing palette blocks.

Installation

dotnet add package EncDotNet.S100.Datasets.S122

Strongly-typed data model

In addition to the feature-bag S122Dataset, the library exposes a strongly-typed projection rooted at S122MarineProtectedAreaDataset under EncDotNet.S100.Datasets.S122.DataModel. It uses the shared typed-model abstractions in EncDotNet.S100.Core.DataModel (XlinkResolver, ProjectionContext, GeoPosition, AttributeParser, ExtraAttributes) and follows the same pattern as the S-124 / S-125 / S-128 / S-201 projections.

using EncDotNet.S100.Datasets.S122;
using EncDotNet.S100.Datasets.S122.DataModel;

var dataset = S122Dataset.Open("122TESTDATASET.gml");
var typed = S122MarineProtectedAreaDataset.From(dataset, out var diagnostics);

foreach (var mpa in typed.MarineProtectedAreas)
{
    Console.WriteLine($"{mpa.Id}: cat={mpa.CategoryOfMarineProtectedArea}, designation={mpa.Designation}");

    foreach (var infoRef in mpa.InformationReferences)
        Console.WriteLine($"  -> {infoRef.Role}: {infoRef.Target.TypeCode} #{infoRef.Target.Id}");
}

foreach (var diag in diagnostics)
    Console.WriteLine($"[{diag.Severity}] {diag.Code}: {diag.Message}");

Notes:

  • Typed projection is purely additive — the portrayal pipeline continues to run off the feature-bag dataset and is unchanged.
  • From() throws only when the source dataset has no features and no information types; everything else surfaces as a ProjectionDiagnostic (unresolved xlinks, attribute parse failures, etc.).
  • xlink:href associations (e.g. theAuthority, theInformation, theCartographicText) are resolved into typed S122InformationReference / S122FeatureReference records. The raw GmlReference list is also preserved on every typed object for callers that need role / arcrole / href verbatim.
  • Unrecognised feature / information types are preserved as S122OtherFeature / S122OtherInformationType so future-edition catalogues round-trip without information loss.

Validation

The library ships a default rule pack for the typed dataset projection at EncDotNet.S100.Datasets.S122.Validation.S122MarineProtectedAreaRules. It follows the framework introduced for S-421 in PR #100 — see EncDotNet.S100.Core/Validation/ for IValidationRule<TModel>, ValidationRuleSet, ValidationFinding, ValidationSeverity.

using EncDotNet.S100.Datasets.S122;
using EncDotNet.S100.Datasets.S122.DataModel;
using EncDotNet.S100.Datasets.S122.Validation;

var dataset = S122Dataset.Open("122TESTDATASET.gml");
var typed = S122MarineProtectedAreaDataset.From(dataset, out _);
var report = S122MarineProtectedAreaRules.Validate(typed);

foreach (var finding in report.Findings)
    Console.WriteLine($"[{finding.Severity}] {finding.RuleId}: {finding.Message}");

The default rule pack contains seven rules:

Rule ID Severity Summary
S122-R-3.1 Warning Features that declare a Point/Curve/Surface kind must have coords.
S122-R-4.1 Error All coordinates must lie within WGS-84 lat/lon ranges.
S122-R-5.1 Error Surface features need a closed exterior ring (≥4 coords, first=last).
S122-R-6.1 Error Feature gml:id values must be unique within the dataset.
S122-R-6.2 Error Information-type gml:id values must be unique within the dataset.
S122-R-7.1 Warning When present, scaleMinimum must be a positive denominator (≥1).
S122-R-9.1 Warning When present, productIdentifier must start with S-122.

Tier-3 cross-dataset rules (e.g. an S-122 restricted area overlapping an S-101 routing zone) are deliberately out of scope for this pack; they will land alongside the MCP validate_all surface that exposes sibling datasets via ValidationContext.Services.