Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
name: Build and Deploy
on:
workflow_dispatch:
push:
branches:
- master
- upgrade-netex-2.0
pull_request:
branches:
- master
- upgrade-netex-2.0
jobs:
maven-verify:
runs-on: ubuntu-24.04
Expand All @@ -22,7 +23,7 @@ jobs:
sudo apt-get -y install xmlstarlet
- uses: actions/setup-java@v4
with:
java-version: 17
java-version: 21
distribution: liberica
- name: Cache Maven dependencies
uses: actions/cache@v5
Expand Down Expand Up @@ -68,13 +69,13 @@ jobs:

publish-snapshot:
name: Publish snapshot to Maven Central
if: github.repository_owner == 'entur' && github.event_name == 'push' && github.ref == 'refs/heads/master'
if: github.repository_owner == 'entur' && github.event_name == 'push' && github.ref == 'refs/heads/upgrade-netex-2.0'
needs: maven-verify
uses: ./.github/workflows/maven-jreleaser-release.yml
with:
version: ${{ needs.maven-verify.outputs.version }}
snapshot: true
skip_version_update: true
java_version: 11
java_version: 21
java_distribution: liberica
secrets: inherit
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
[![Maven Central](https://img.shields.io/maven-central/v/org.entur/netex-java-model.svg?label=Maven%20Central)](https://central.sonatype.com/artifact/org.entur/netex-java-model)
[![Maven Snapshots](https://img.shields.io/maven-metadata/v?metadataUrl=https%3A%2F%2Fcentral.sonatype.com%2Frepository%2Fmaven-snapshots%2Forg%2Fentur%2Fnetex-java-model%2Fmaven-metadata.xml&label=Snapshot)](https://central.sonatype.com/repository/maven-snapshots)
[![License: EUPL-1.2](https://img.shields.io/badge/License-EUPL--1.2-blue.svg)](https://joinup.ec.europa.eu/software/page/eupl)
[![Java 11+](https://img.shields.io/badge/Java-11%2B-orange)](https://adoptium.net/)
[![Java 21+](https://img.shields.io/badge/Java-21%2B-orange)](https://adoptium.net/)

Java model classes generated from [NeTEx](https://github.com/entur/NeTEx) (Network Timetable Exchange) XML Schema Definition (XSD) files using JAXB. Maintained by [Entur AS](https://www.entur.org).
Java model classes generated from [NeTEx](https://github.com/NeTEx-CEN/NeTEx) (Network Timetable Exchange) XML Schema Definition (XSD) files using JAXB. Maintained by [Entur AS](https://www.entur.org).

## Overview

This library downloads the NeTEx XSD files from the [Entur NeTEx fork](https://github.com/entur/NeTEx) and compiles them into JAXB-annotated Java model classes at build time. The generated classes support full marshalling and unmarshalling of NeTEx XML documents, including schema validation against multiple NeTEx versions.
This library downloads the NeTEx XSD files from the [CEN NeTEx repository](https://github.com/NeTEx-CEN/NeTEx) and compiles them into JAXB-annotated Java model classes at build time. The generated classes support full marshalling and unmarshalling of NeTEx XML documents, including schema validation against multiple NeTEx versions. Legacy schemas (1.08 - 1.15) are downloaded from the [Entur NeTEx fork](https://github.com/entur/NeTEx).

- **NeTEx version**: 1.16 (model generation), with legacy validation support back to 1.07
- **NeTEx version**: 2.0 (model generation), with legacy validation support back to 1.07
- **JAXB**: Jakarta XML Bind 4.x (Jakarta EE 9+)
- **Generated package**: `org.rutebanken.netex.model`
- **GML types package**: `net.opengis.gml._3`
Expand Down Expand Up @@ -61,7 +61,7 @@ Then add the dependency with the snapshot version:

### Prerequisites

- Java 11+
- Java 21+
- Maven 3.x
- [`xmlstarlet`](https://xmlstar.sourceforge.net/) (`apt install xmlstarlet` on Debian/Ubuntu, `brew install xmlstarlet` on macOS)

Expand Down Expand Up @@ -103,7 +103,7 @@ The XSD files are downloaded from GitHub during the `generate-sources` phase and
- Property name conflict resolution
- Package mapping to `org.rutebanken.netex.model`

**Schema validation**: `NeTExValidator` supports validation against NeTEx versions 1.07 through 1.16.
**Schema validation**: `NeTExValidator` supports validation against NeTEx versions 1.07 through 2.0.

**Note on GML types**: This library generates classes under `net.opengis.gml._3` as part of the NeTEx model.

Expand Down
54 changes: 38 additions & 16 deletions bindings.xjb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" jxb:version="3.0" jxb:extensionBindingPrefixes="xjc">

<jxb:bindings>
<jxb:globalBindings underscoreBinding="asCharInWord">
<xjc:javaType name="java.time.LocalDateTime" xmlType="xs:dateTime" adapter="org.rutebanken.util.LocalDateTimeISO8601XmlAdapter" />
Expand All @@ -14,14 +14,14 @@

<!-- See the script bin/version_updater.sh It updates version in schema locations-->

| <jxb:bindings schemaLocation="./src/main/resources/xsd/1.16/NeTEx_publication.xsd">
| <jxb:bindings schemaLocation="./src/main/resources/xsd/2.0/NeTEx_publication.xsd">
<jxb:schemaBindings>
<jxb:package name="org.rutebanken.netex.model" />
</jxb:schemaBindings>
</jxb:bindings>

<jxb:bindings
schemaLocation="./src/main/resources/xsd/1.16/netex_framework/netex_genericFramework/netex_organisation_version.xsd">
schemaLocation="./src/main/resources/xsd/2.0/netex_framework/netex_genericFramework/netex_organisation_version.xsd">
<jxb:bindings node="//xsd:element[@name = 'Status']">
<jxb:property name="StatusOrganisationGroup" />
</jxb:bindings>
Expand All @@ -30,35 +30,28 @@
</jxb:bindings>
</jxb:bindings>
<jxb:bindings
schemaLocation="./src/main/resources/xsd/1.16/netex_part_3/part3_fares/netex_salesOfferPackage_version.xsd">
schemaLocation="./src/main/resources/xsd/2.0/netex_part_3/part3_fares/netex_salesOfferPackage_version.xsd">
<jxb:bindings node="//xsd:element[@ref = 'ResponsibilitySetRef']">
<jxb:property name="ResponsibilitySetRefDistributionByGroup" />
</jxb:bindings>
</jxb:bindings>

<jxb:bindings
schemaLocation="./src/main/resources/xsd/1.16/netex_part_2/part2_journeyTimes/netex_vehicleJourneyFrequency_version.xsd">
<jxb:bindings node="//xsd:group[@name= 'HeadwayJourneyGroupGroup']/xsd:sequence/xsd:element[@name = 'Description']">
<jxb:property name="DescriptionHeadwayJourneyGroupGroup" />
</jxb:bindings>
</jxb:bindings>

<jxb:bindings
schemaLocation="./src/main/resources/xsd/1.16/netex_part_3/part3_salesTransactions/netex_salesContract_version.xsd">
schemaLocation="./src/main/resources/xsd/2.0/netex_part_3/part3_salesTransactions/netex_salesContract_version.xsd">
<jxb:bindings node="//xsd:element[@name = 'Status']">
<jxb:property name="StatusPassengerContractGroup" />
</jxb:bindings>
</jxb:bindings>

<jxb:bindings
schemaLocation="./src/main/resources/xsd/1.16/netex_part_3/part3_salesTransactions/netex_retailConsortium_version.xsd">
schemaLocation="./src/main/resources/xsd/2.0/netex_part_3/part3_salesTransactions/netex_retailConsortium_version.xsd">
<jxb:bindings node="//xsd:element[@name = 'Status']">
<jxb:property name="StatusRetailDeviceGroup" />
</jxb:bindings>
</jxb:bindings>

<jxb:bindings
schemaLocation="./src/main/resources/xsd/1.16/netex_framework/netex_responsibility/netex_version_support.xsd">
schemaLocation="./src/main/resources/xsd/2.0/netex_framework/netex_responsibility/netex_version_support.xsd">
<jxb:bindings node="//xsd:simpleType[@name = 'VersionIdType']">
<xjc:javaType name="java.lang.String" adapter="org.rutebanken.util.VersionXmlAdapter" />
</jxb:bindings>
Expand All @@ -71,14 +64,43 @@
</jxb:bindings>

<jxb:bindings
schemaLocation="./src/main/resources/xsd/1.16/netex_framework/netex_genericFramework/netex_zone_version.xsd">
<jxb:bindings node="//xsd:complexType[@name = 'tariffZonesInFrame_RelStructure']/xsd:complexContent/xsd:extension[@base = 'containmentAggregationStructure']/xsd:sequence/xsd:element[@ref = 'TariffZone_']">
schemaLocation="./src/main/resources/xsd/2.0/netex_framework/netex_genericFramework/netex_zone_version.xsd">
<jxb:bindings node="//xsd:complexType[@name = 'tariffZonesInFrame_RelStructure']/xsd:complexContent/xsd:extension[@base = 'containmentAggregationStructure']/xsd:sequence/xsd:element[@ref = 'TariffZone_Dummy']">
<jxb:property name="tariffZone" />
</jxb:bindings>
</jxb:bindings>

<!-- NeTEx 2.0: Resolve ObjectFactory collisions for bookingArrangements vs BookingArrangements -->
<jxb:bindings
schemaLocation="./src/main/resources/xsd/2.0/netex_part_1/part1_tacticalPlanning/netex_servicePattern_version.xsd">
<jxb:bindings node="//xsd:group[@name = 'StopPointInPatternPropertiesGroup']/xsd:sequence/xsd:choice/xsd:element[@name = 'bookingArrangements']">
<jxb:property name="bookingArrangementsRelStructure" />
</jxb:bindings>
</jxb:bindings>

<jxb:bindings
schemaLocation="./src/main/resources/xsd/2.0/netex_part_5/part5_rc/netex_nm_mobilityService_version.xsd">
<jxb:bindings node="//xsd:group[@name = 'MobilityServiceGroup']/xsd:sequence/xsd:choice/xsd:element[@name = 'serviceBookingArrangements']">
<jxb:property name="serviceBookingArrangementsRelStructure" />
</jxb:bindings>
</jxb:bindings>

<jxb:bindings
schemaLocation="./src/main/resources/xsd/2.0/netex_part_3/part3_fares/netex_usageParameterBooking_version.xsd">
<jxb:bindings node="//xsd:group[@name = 'ReservingGroup']/xsd:sequence/xsd:choice/xsd:element[@name = 'bookingArrangements']">
<jxb:property name="bookingArrangementsRelStructureReserving" />
</jxb:bindings>
<jxb:bindings node="//xsd:group[@name = 'CancellingGroup']/xsd:sequence/xsd:choice/xsd:element[@name = 'bookingArrangements']">
<jxb:property name="bookingArrangementsRelStructureCancelling" />
</jxb:bindings>
</jxb:bindings>

<jxb:bindings
schemaLocation="./src/main/resources/xsd/2.0/netex_part_1/part1_ifopt/netex_assistanceBooking_version.xsd">
<jxb:bindings node="//xsd:group[@name = 'AssistanceBookingServiceGroup']/xsd:sequence/xsd:choice/xsd:element[@name = 'bookingArrangements']">
<jxb:property name="bookingArrangementsRelStructureAssistance" />
</jxb:bindings>
</jxb:bindings>


</jxb:bindings>
33 changes: 17 additions & 16 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.entur</groupId>
<artifactId>netex-java-model</artifactId>
<version>2.0.17-SNAPSHOT</version>
<version>3.0.0-SNAPSHOT</version>

<name>netex-java-model</name>
<description>Generates Java model from NeTEx XSDs using JAXB.</description>
Expand Down Expand Up @@ -66,12 +66,13 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- Do not edit, this is automatically updated by the Maven release plugin -->
<project.build.outputTimestamp>2026-03-17T14:54:35Z</project.build.outputTimestamp>
<jdk.version>11</jdk.version>
<jdk.version>21</jdk.version>

<netexRepoName>NeTEx</netexRepoName>
<netexBranch>master</netexBranch>
<netexGithubUrl>https://github.com/entur/${netexRepoName}</netexGithubUrl>
<netexVersion>1.16</netexVersion>
<netexBranch>v2.0</netexBranch>
<cenNetexGithubUrl>https://github.com/NeTEx-CEN/${netexRepoName}</cenNetexGithubUrl>
<enturNetexGithubUrl>https://github.com/entur/${netexRepoName}</enturNetexGithubUrl>
<netexVersion>2.0</netexVersion>

<!-- JAXB components versions -->
<jakarta-xml-bind.version>4.0.5</jakarta-xml-bind.version>
Expand Down Expand Up @@ -283,9 +284,9 @@
</goals>
<configuration>
<environmentVariables>
<GITHUB_URL>${netexGithubUrl}/archive/${netexBranch}.zip</GITHUB_URL>
<GITHUB_URL>${cenNetexGithubUrl}/archive/${netexBranch}.zip</GITHUB_URL>
<DESTINATION_PATH>src/main/resources/xsd/${netexVersion}</DESTINATION_PATH>
<ZIP_PATH_TO_EXTRACT>NeTEx-${netexBranch}/xsd/*</ZIP_PATH_TO_EXTRACT>
<ZIP_PATH_TO_EXTRACT>NeTEx-${netexVersion}/xsd/*</ZIP_PATH_TO_EXTRACT>
</environmentVariables>
<executable>./bin/netex-download-extract.sh</executable>
</configuration>
Expand Down Expand Up @@ -314,7 +315,7 @@
</goals>
<configuration>
<environmentVariables>
<GITHUB_URL>${netexGithubUrl}/archive/tags/v1.0.15.zip</GITHUB_URL>
<GITHUB_URL>${enturNetexGithubUrl}/archive/tags/v1.0.15.zip</GITHUB_URL>
<DESTINATION_PATH>src/main/resources/xsd/1.15</DESTINATION_PATH>
<ZIP_PATH_TO_EXTRACT>NeTEx-tags-v1.0.15/xsd/*</ZIP_PATH_TO_EXTRACT>
</environmentVariables>
Expand All @@ -330,7 +331,7 @@
</goals>
<configuration>
<environmentVariables>
<GITHUB_URL>${netexGithubUrl}/archive/tags/v1.0.14.zip</GITHUB_URL>
<GITHUB_URL>${enturNetexGithubUrl}/archive/tags/v1.0.14.zip</GITHUB_URL>
<DESTINATION_PATH>src/main/resources/xsd/1.14</DESTINATION_PATH>
<ZIP_PATH_TO_EXTRACT>NeTEx-tags-v1.0.14/xsd/*</ZIP_PATH_TO_EXTRACT>
</environmentVariables>
Expand All @@ -346,7 +347,7 @@
</goals>
<configuration>
<environmentVariables>
<GITHUB_URL>${netexGithubUrl}/archive/tags/v1.0.13.zip</GITHUB_URL>
<GITHUB_URL>${enturNetexGithubUrl}/archive/tags/v1.0.13.zip</GITHUB_URL>
<DESTINATION_PATH>src/main/resources/xsd/1.13</DESTINATION_PATH>
<ZIP_PATH_TO_EXTRACT>NeTEx-tags-v1.0.13/xsd/*</ZIP_PATH_TO_EXTRACT>
</environmentVariables>
Expand All @@ -362,7 +363,7 @@
</goals>
<configuration>
<environmentVariables>
<GITHUB_URL>${netexGithubUrl}/archive/tags/v1.0.12.zip</GITHUB_URL>
<GITHUB_URL>${enturNetexGithubUrl}/archive/tags/v1.0.12.zip</GITHUB_URL>
<DESTINATION_PATH>src/main/resources/xsd/1.12</DESTINATION_PATH>
<ZIP_PATH_TO_EXTRACT>NeTEx-tags-v1.0.12/xsd/*</ZIP_PATH_TO_EXTRACT>
</environmentVariables>
Expand All @@ -378,7 +379,7 @@
</goals>
<configuration>
<environmentVariables>
<GITHUB_URL>${netexGithubUrl}/archive/tags/v1.0.11.zip</GITHUB_URL>
<GITHUB_URL>${enturNetexGithubUrl}/archive/tags/v1.0.11.zip</GITHUB_URL>
<DESTINATION_PATH>src/main/resources/xsd/1.11</DESTINATION_PATH>
<ZIP_PATH_TO_EXTRACT>NeTEx-tags-v1.0.11/xsd/*</ZIP_PATH_TO_EXTRACT>
</environmentVariables>
Expand All @@ -394,7 +395,7 @@
</goals>
<configuration>
<environmentVariables>
<GITHUB_URL>${netexGithubUrl}/archive/tags/v1.0.10-entur.zip</GITHUB_URL>
<GITHUB_URL>${enturNetexGithubUrl}/archive/tags/v1.0.10-entur.zip</GITHUB_URL>
<DESTINATION_PATH>src/main/resources/xsd/1.10</DESTINATION_PATH>
<ZIP_PATH_TO_EXTRACT>NeTEx-tags-v1.0.10-entur/xsd/*</ZIP_PATH_TO_EXTRACT>
</environmentVariables>
Expand All @@ -410,7 +411,7 @@
</goals>
<configuration>
<environmentVariables>
<GITHUB_URL>${netexGithubUrl}/archive/tags/v1.0.9.zip</GITHUB_URL>
<GITHUB_URL>${enturNetexGithubUrl}/archive/tags/v1.0.9.zip</GITHUB_URL>
<DESTINATION_PATH>src/main/resources/xsd/1.09</DESTINATION_PATH>
<ZIP_PATH_TO_EXTRACT>NeTEx-tags-v1.0.9/xsd/*</ZIP_PATH_TO_EXTRACT>
</environmentVariables>
Expand All @@ -426,7 +427,7 @@
</goals>
<configuration>
<environmentVariables>
<GITHUB_URL>${netexGithubUrl}/archive/tags/v1.0.8.zip</GITHUB_URL>
<GITHUB_URL>${enturNetexGithubUrl}/archive/tags/v1.0.8.zip</GITHUB_URL>
<DESTINATION_PATH>src/main/resources/xsd/1.08</DESTINATION_PATH>
<ZIP_PATH_TO_EXTRACT>NeTEx-tags-v1.0.8/xsd/*</ZIP_PATH_TO_EXTRACT>
</environmentVariables>
Expand Down Expand Up @@ -680,7 +681,7 @@
</activation>

<properties>
<jdk.version>11</jdk.version>
<jdk.version>21</jdk.version>
<sonar-maven-plugin.version>3.9.1.2184</sonar-maven-plugin.version>
</properties>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ public enum NetexVersion {
v1_13 ("1.13"),
v1_14 ("1.14"),
v1_15 ("1.15"),
v1_16 ("1.16");
v1_16 ("1.16"),
v2_0 ("2.0");

private final String folderName;

Expand All @@ -59,7 +60,7 @@ public String toString() {
}
private final Schema neTExSchema;

public static final NetexVersion LATEST = NetexVersion.v1_16;
public static final NetexVersion LATEST = NetexVersion.v2_0;

private static final Map<NetexVersion, NeTExValidator> VALIDATORS_PER_VERSION = new EnumMap<>(NetexVersion.class);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,20 @@ public static void initContext() throws JAXBException {

}


/**
* Helper method to extract string value from MultilingualString.
* In NeTEx 2.0, MultilingualString uses mixed content instead of a simple value.
*/
protected static String getStringValue(MultilingualString multilingualString) {
if (multilingualString == null || multilingualString.getContent() == null) {
return null;
}
return multilingualString.getContent().stream()
.filter(String.class::isInstance)
.map(String.class::cast)
.findFirst()
.orElse(null);
}


}
Loading
Loading