diff --git a/README.md b/README.md index 4520b5ab..6cec8b98 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Java model classes generated from [NeTEx](https://github.com/entur/NeTEx) (Netwo 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. -- **NeTEx version**: 1.16 (model generation), with legacy validation support back to 1.07 +- **NeTEx version**: 1.16.1 (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` @@ -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 1.16. A version is validated against its latest patch schema: documents declaring 1.16 are validated against the 1.16.1 schema, which is backward compatible with 1.16. **Note on GML types**: This library generates classes under `net.opengis.gml._3` as part of the NeTEx model. diff --git a/bindings.xjb b/bindings.xjb index 089dc6c0..ffcaccde 100644 --- a/bindings.xjb +++ b/bindings.xjb @@ -14,14 +14,14 @@ -| +| + schemaLocation="./src/main/resources/xsd/1.16.1/netex_framework/netex_genericFramework/netex_organisation_version.xsd"> @@ -30,35 +30,35 @@ + schemaLocation="./src/main/resources/xsd/1.16.1/netex_part_3/part3_fares/netex_salesOfferPackage_version.xsd"> + schemaLocation="./src/main/resources/xsd/1.16.1/netex_part_2/part2_journeyTimes/netex_vehicleJourneyFrequency_version.xsd"> + schemaLocation="./src/main/resources/xsd/1.16.1/netex_part_3/part3_salesTransactions/netex_salesContract_version.xsd"> + schemaLocation="./src/main/resources/xsd/1.16.1/netex_part_3/part3_salesTransactions/netex_retailConsortium_version.xsd"> + schemaLocation="./src/main/resources/xsd/1.16.1/netex_framework/netex_responsibility/netex_version_support.xsd"> @@ -71,7 +71,7 @@ + schemaLocation="./src/main/resources/xsd/1.16.1/netex_framework/netex_genericFramework/netex_zone_version.xsd"> diff --git a/pom.xml b/pom.xml index c3d8dbba..f6aa7eb9 100644 --- a/pom.xml +++ b/pom.xml @@ -69,9 +69,9 @@ 11 NeTEx - master + tags/v1.0.16.1 https://github.com/entur/${netexRepoName} - 1.16 + 1.16.1 4.0.5 @@ -285,7 +285,7 @@ ${netexGithubUrl}/archive/${netexBranch}.zip src/main/resources/xsd/${netexVersion} - NeTEx-${netexBranch}/xsd/* + NeTEx-tags-v1.0.16.1/xsd/* ./bin/netex-download-extract.sh diff --git a/src/main/java/org/rutebanken/netex/validation/NeTExValidator.java b/src/main/java/org/rutebanken/netex/validation/NeTExValidator.java index 4b3f4a83..7cd69393 100644 --- a/src/main/java/org/rutebanken/netex/validation/NeTExValidator.java +++ b/src/main/java/org/rutebanken/netex/validation/NeTExValidator.java @@ -44,17 +44,36 @@ public enum NetexVersion { v1_13 ("1.13"), v1_14 ("1.14"), v1_15 ("1.15"), - v1_16 ("1.16"); - + /** + * NeTEx 1.16, validated against the latest 1.16 patch schema. Patch releases of the schema + * are backward compatible, and documents only ever declare the minor version, so a document + * declaring 1.16 is validated against the same schema the model is generated from. + */ + v1_16 ("1.16", "1.16.1"), + /** + * @deprecated the 1.16.1 schema is what {@link #v1_16} validates against. Use {@link #v1_16}. + */ + @Deprecated + v1_16_1 ("1.16.1"); + + private final String version; private final String folderName; - NetexVersion(String folderName) { + NetexVersion(String version) { + this(version, version); + } + + NetexVersion(String version, String folderName) { + this.version = version; this.folderName = folderName; } + /** + * @return the NeTEx version, which is not always the name of the folder holding its schema. + */ @Override public String toString() { - return folderName; + return version; } } private final Schema neTExSchema; @@ -102,7 +121,7 @@ public NeTExValidator() throws IOException, SAXException { public NeTExValidator(NetexVersion version) throws IOException, SAXException { SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); - String resourceName = "xsd/"+ version +"/NeTEx_publication.xsd"; + String resourceName = "xsd/"+ version.folderName +"/NeTEx_publication.xsd"; LOGGER.info("Loading resource: {}", resourceName); URL resource = getClass().getClassLoader().getResource(resourceName); if(resource == null) { diff --git a/src/test/java/org/rutebanken/netex/model/UnmarshalResourceFrameExtendedTest.java b/src/test/java/org/rutebanken/netex/model/UnmarshalResourceFrameExtendedTest.java index 2ee3ea29..7ca3c6bb 100644 --- a/src/test/java/org/rutebanken/netex/model/UnmarshalResourceFrameExtendedTest.java +++ b/src/test/java/org/rutebanken/netex/model/UnmarshalResourceFrameExtendedTest.java @@ -121,4 +121,51 @@ void unmarshalOperatorWithBrandingRef() throws JAXBException { assertNotNull(operator.getBrandingRef()); assertEquals("TST:Branding:1", operator.getBrandingRef().getRef()); } + + @Test + void unmarshalResponsibilitySetWithAssociatedContract() throws JAXBException { + + String xml = "\n" + + "\n" + + " 2026-09-10T10:00:00\n" + + " TST\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " Contracted operation\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + + Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); + + @SuppressWarnings("unchecked") + JAXBElement jaxbElement = (JAXBElement) unmarshaller + .unmarshal(new ByteArrayInputStream(xml.getBytes())); + + PublicationDeliveryStructure publicationDeliveryStructure = jaxbElement.getValue(); + ResourceFrame resourceFrame = (ResourceFrame) publicationDeliveryStructure.getDataObjects().getCompositeFrameOrCommonFrame().get(0).getValue(); + + ResponsibilitySet responsibilitySet = resourceFrame.getResponsibilitySets().getResponsibilitySet().get(0); + assertEquals("Contracted operation", responsibilitySet.getName().getValue()); + + ResponsibilityRoleAssignment_VersionedChildStructure roleAssignment = responsibilitySet.getRoles().getResponsibilityRoleAssignment().get(0); + + ContractRef_RelStructure associatedContract = roleAssignment.getAssociatedContract(); + assertNotNull(associatedContract); + ContractRefStructure contractRef = associatedContract.getContractRef(); + assertNotNull(contractRef); + assertEquals("TST:Contract:1", contractRef.getRef()); + assertEquals("1", contractRef.getVersion()); + } } diff --git a/src/test/java/org/rutebanken/netex/validation/NeTExValidatorTest.java b/src/test/java/org/rutebanken/netex/validation/NeTExValidatorTest.java index 1d9b00c7..74168092 100644 --- a/src/test/java/org/rutebanken/netex/validation/NeTExValidatorTest.java +++ b/src/test/java/org/rutebanken/netex/validation/NeTExValidatorTest.java @@ -24,6 +24,7 @@ import java.io.StringReader; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertEquals; class NeTExValidatorTest { @@ -52,4 +53,58 @@ void validatePublicationDeliveryWithLatestVersion() throws IOException, SAXExcep } -} \ No newline at end of file + /** + * AssociatedContract / ContractRef on a ResponsibilityRoleAssignment was added in NeTEx 1.16.1 + * (entur/NeTEx#63). 1.16 is validated against the 1.16.1 schema, so it is valid against 1.16 too. + */ + private static final String RESPONSIBILITY_SET_WITH_ASSOCIATED_CONTRACT = "\n" + + "\n" + + " 2026-09-10T10:00:00\n" + + " TST\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " Contracted operation\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + + @Test + void latestVersionIs1_16() { + assertEquals(NeTExValidator.NetexVersion.v1_16, NeTExValidator.LATEST); + } + + @Test + void version1_16IsNamed1_16() { + assertEquals("1.16", NeTExValidator.NetexVersion.v1_16.toString()); + } + + @Test + void validateResponsibilitySetWithAssociatedContractAgainstLatestVersion() throws IOException, SAXException { + neTExValidator.validate(new StreamSource(new StringReader(RESPONSIBILITY_SET_WITH_ASSOCIATED_CONTRACT))); + } + + @Test + void validateResponsibilitySetWithAssociatedContractAgainstVersion1_16() throws IOException, SAXException { + NeTExValidator validator1_16 = NeTExValidator.getNeTExValidator(NeTExValidator.NetexVersion.v1_16); + validator1_16.validate(new StreamSource(new StringReader(RESPONSIBILITY_SET_WITH_ASSOCIATED_CONTRACT))); + } + + @Test + @SuppressWarnings("deprecation") + void validateResponsibilitySetWithAssociatedContractAgainstDeprecatedVersion1_16_1() throws IOException, SAXException { + NeTExValidator validator1_16_1 = NeTExValidator.getNeTExValidator(NeTExValidator.NetexVersion.v1_16_1); + validator1_16_1.validate(new StreamSource(new StringReader(RESPONSIBILITY_SET_WITH_ASSOCIATED_CONTRACT))); + } + +}