diff --git a/packages/XmlSchemaClassGenerator-beta.99.0.11-local.nupkg b/packages/XmlSchemaClassGenerator-beta.99.0.11-local.nupkg
deleted file mode 100644
index 59a9ec5..0000000
Binary files a/packages/XmlSchemaClassGenerator-beta.99.0.11-local.nupkg and /dev/null differ
diff --git a/packages/XmlSchemaClassGenerator-beta.99.0.14-local.nupkg b/packages/XmlSchemaClassGenerator-beta.99.0.14-local.nupkg
new file mode 100644
index 0000000..72a1a31
Binary files /dev/null and b/packages/XmlSchemaClassGenerator-beta.99.0.14-local.nupkg differ
diff --git a/packages/XmlSchemaClassGenerator.Analyzer.99.0.11-local.nupkg b/packages/XmlSchemaClassGenerator.Analyzer.99.0.11-local.nupkg
deleted file mode 100644
index dff2b17..0000000
Binary files a/packages/XmlSchemaClassGenerator.Analyzer.99.0.11-local.nupkg and /dev/null differ
diff --git a/packages/XmlSchemaClassGenerator.Analyzer.99.0.14-local.nupkg b/packages/XmlSchemaClassGenerator.Analyzer.99.0.14-local.nupkg
new file mode 100644
index 0000000..ae0efd8
Binary files /dev/null and b/packages/XmlSchemaClassGenerator.Analyzer.99.0.14-local.nupkg differ
diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props
index c25bbbb..7913daa 100644
--- a/src/Directory.Packages.props
+++ b/src/Directory.Packages.props
@@ -8,8 +8,8 @@
-
-
+
+
diff --git a/src/generator/Spillgebees.Transmodel.Generator/Services/CodeGenerator.cs b/src/generator/Spillgebees.Transmodel.Generator/Services/CodeGenerator.cs
index 81436c3..6c00c05 100644
--- a/src/generator/Spillgebees.Transmodel.Generator/Services/CodeGenerator.cs
+++ b/src/generator/Spillgebees.Transmodel.Generator/Services/CodeGenerator.cs
@@ -148,6 +148,7 @@ private static XscGenerator CreateBaseGenerator(
EnableNullableDirective = true,
GenerateRequiredModifier = true,
UseShouldSerializePattern = true,
+ UseShouldSerializeForDefaultValues = true,
GenerateChoiceGroupAttributes = true,
ChoiceGroupAttributeNamespace = rootNamespace,
GenerateStrictFixedValues = true,
diff --git a/src/netex/Spillgebees.NeTEx.Models.Tests/Serialization/Netex/v1/SerializationTests.cs b/src/netex/Spillgebees.NeTEx.Models.Tests/Serialization/Netex/v1/SerializationTests.cs
index 5219507..c770c69 100644
--- a/src/netex/Spillgebees.NeTEx.Models.Tests/Serialization/Netex/v1/SerializationTests.cs
+++ b/src/netex/Spillgebees.NeTEx.Models.Tests/Serialization/Netex/v1/SerializationTests.cs
@@ -186,6 +186,31 @@ public void Should_serialize_and_deserialize_optional_element_with_default_value
deserialized.Note.Value.Should().Be("false.");
}
+ [Test]
+ [Arguments("changed")]
+ [Arguments("false.")]
+ public void Should_preserve_edits_to_the_contents_of_a_default_object(string text)
+ {
+ // arrange
+ var serializer = new XmlSerializer(typeof(AccessVehicleEquipment));
+ var equipment = new AccessVehicleEquipment
+ {
+ Id = "NSR:AccessVehicleEquipment:1",
+ Version = "1",
+ };
+
+ // act
+ equipment.Note!.Value = text;
+ using var writer = new StringWriter();
+ serializer.Serialize(writer, equipment);
+ using var reader = new StringReader(writer.ToString());
+ var result = (AccessVehicleEquipment)serializer.Deserialize(reader)!;
+
+ // assert
+ writer.ToString().Should().Contain($"{text}");
+ result.Note!.Value.Should().Be(text);
+ }
+
[Test]
public void Should_serialize_simple_content_ref_as_self_closing_element_when_value_is_null()
{
diff --git a/src/netex/Spillgebees.NeTEx.Models.Tests/XsdTypeMappingTests.cs b/src/netex/Spillgebees.NeTEx.Models.Tests/XsdTypeMappingTests.cs
index cff8535..9e7778b 100644
--- a/src/netex/Spillgebees.NeTEx.Models.Tests/XsdTypeMappingTests.cs
+++ b/src/netex/Spillgebees.NeTEx.Models.Tests/XsdTypeMappingTests.cs
@@ -118,7 +118,7 @@ public void Should_not_have_default_value_attribute_on_nullable_string_property_
}
[Test]
- public void Should_still_have_default_value_attribute_on_value_type_property_with_xsd_default()
+ public void Should_track_assignment_instead_of_omitting_explicit_default_values()
{
// arrange
var property = typeof(DayTypeAssignmentVersionStructure)
@@ -128,8 +128,8 @@ public void Should_still_have_default_value_attribute_on_value_type_property_wit
var attr = property.GetCustomAttribute();
// assert
- attr.Should().NotBeNull();
- attr!.Value.Should().Be(true);
+ attr.Should().BeNull();
+ property.DeclaringType!.GetMethod("ShouldSerialize" + property.Name).Should().NotBeNull();
}
[Test]
diff --git a/src/siri/Spillgebees.SIRI.Models.Tests/ChoiceSchemaRegressionTests.cs b/src/siri/Spillgebees.SIRI.Models.Tests/ChoiceSchemaRegressionTests.cs
new file mode 100644
index 0000000..9c26ea7
--- /dev/null
+++ b/src/siri/Spillgebees.SIRI.Models.Tests/ChoiceSchemaRegressionTests.cs
@@ -0,0 +1,46 @@
+using System.Reflection;
+using AwesomeAssertions;
+
+namespace Spillgebees.SIRI.Models.Tests;
+
+public class ChoiceSchemaRegressionTests
+{
+ [Test]
+ [Arguments(typeof(V2_1.SIRI.AffectedSectionStructureIndirectSectionRef))]
+ [Arguments(typeof(V2_2.SIRI.AffectedSectionStructureIndirectSectionRef))]
+ public void Should_allow_mixed_references_in_repeated_situation_exchange_choice(Type sectionType)
+ {
+ // arrange
+ var properties = new[] { "IntermediateStopPointRef", "IntermediateStopPlaceRef", "IntermediateQuayRef" };
+
+ // act
+ var attributes = properties.SelectMany(name => sectionType.GetProperty(name)!.GetCustomAttributesData())
+ .Where(attribute => attribute.AttributeType.Name == "XmlChoiceGroupAttribute")
+ .ToList();
+
+ // assert
+ attributes.Should().BeEmpty("each repetition can select a different reference type");
+ }
+
+ [Test]
+ [Arguments(typeof(V2_1.SIRI.VehicleMonitoringSubscriptionStructure), "ChangeBeforeUpdates", "UpdateInterval")]
+ [Arguments(typeof(V2_2.SIRI.VehicleMonitoringSubscriptionStructure), "ChangeBeforeUpdates", "UpdateInterval")]
+ [Arguments(typeof(V2_1.SIRI.SituationExchangeRequestStructure), "LineRef", "Lines")]
+ [Arguments(typeof(V2_2.SIRI.SituationExchangeRequestStructure), "LineRef", "Lines")]
+ public void Should_allow_omitting_choices_with_optional_alternatives(Type modelType, string first, string second)
+ {
+ // arrange
+ var properties = new[] { first, second };
+
+ // act
+ var attributes = properties.Select(name => modelType.GetProperty(name)!.GetCustomAttributesData()
+ .Single(attribute => attribute.AttributeType.Name == "XmlChoiceGroupAttribute")).ToList();
+
+ // assert
+ attributes[0].ConstructorArguments[0].Value.Should().Be(attributes[1].ConstructorArguments[0].Value);
+ attributes[0].ConstructorArguments[1].Value.Should().NotBe(attributes[1].ConstructorArguments[1].Value);
+ attributes.Should().AllSatisfy(attribute =>
+ attribute.NamedArguments.Single(argument => argument.MemberName == "IsRequired")
+ .TypedValue.Value.Should().Be(false));
+ }
+}
diff --git a/src/siri/Spillgebees.SIRI.Models.Tests/Serialization/DefaultPresenceTests.cs b/src/siri/Spillgebees.SIRI.Models.Tests/Serialization/DefaultPresenceTests.cs
new file mode 100644
index 0000000..15d8073
--- /dev/null
+++ b/src/siri/Spillgebees.SIRI.Models.Tests/Serialization/DefaultPresenceTests.cs
@@ -0,0 +1,70 @@
+using System.Xml.Linq;
+using System.Xml.Serialization;
+using AwesomeAssertions;
+using Spillgebees.SIRI.Models.V2_2.SIRI;
+
+namespace Spillgebees.SIRI.Models.Tests.Serialization;
+
+public class DefaultPresenceTests
+{
+ [Test]
+ [Arguments(null)]
+ [Arguments(true)]
+ [Arguments(false)]
+ public void Should_preserve_assignment_of_defaulted_monitored_value(bool? assignedValue)
+ {
+ // arrange
+ var original = new MonitoredVehicleJourneyStructure();
+ if (assignedValue.HasValue)
+ {
+ original.Monitored = assignedValue.Value;
+ }
+
+ // act
+ var xml = Serialize(original);
+ var monitored = xml.Root!.Element(XName.Get("Monitored", "http://www.siri.org.uk/siri"));
+
+ // assert
+ original.Monitored.Should().Be(assignedValue ?? true);
+ if (assignedValue.HasValue)
+ {
+ monitored.Should().NotBeNull();
+ monitored!.Value.Should().Be(assignedValue.Value ? "true" : "false");
+ }
+ else
+ {
+ monitored.Should().BeNull();
+ }
+ }
+
+ [Test]
+ [Arguments("")]
+ [Arguments("true")]
+ [Arguments("false")]
+ public void Should_preserve_default_presence_after_deserialization(string element)
+ {
+ // arrange
+ var serializer = new XmlSerializer(typeof(MonitoredVehicleJourneyStructure));
+ using var reader = new StringReader($"{element}");
+
+ // act
+ var model = (MonitoredVehicleJourneyStructure)serializer.Deserialize(reader)!;
+ var xml = Serialize(model);
+
+ // assert
+ var monitored = xml.Root!.Element(XName.Get("Monitored", "http://www.siri.org.uk/siri"));
+ (monitored is not null).Should().Be(element.Length != 0);
+ if (monitored is not null)
+ {
+ monitored.Value.Should().Be(model.Monitored ? "true" : "false");
+ }
+ }
+
+ private static XDocument Serialize(MonitoredVehicleJourneyStructure model)
+ {
+ var serializer = new XmlSerializer(typeof(MonitoredVehicleJourneyStructure));
+ using var writer = new StringWriter();
+ serializer.Serialize(writer, model);
+ return XDocument.Parse(writer.ToString());
+ }
+}
diff --git a/src/siri/Spillgebees.SIRI.Models.Tests/Serialization/FixedValueSerializationTests.cs b/src/siri/Spillgebees.SIRI.Models.Tests/Serialization/FixedValueSerializationTests.cs
new file mode 100644
index 0000000..920f662
--- /dev/null
+++ b/src/siri/Spillgebees.SIRI.Models.Tests/Serialization/FixedValueSerializationTests.cs
@@ -0,0 +1,83 @@
+using System.Xml.Linq;
+using System.Xml.Serialization;
+using AwesomeAssertions;
+using Spillgebees.SIRI.Models.V2_2.SIRI;
+
+namespace Spillgebees.SIRI.Models.Tests.Serialization;
+
+public class FixedValueSerializationTests
+{
+ [Test]
+ public void Should_serialize_required_fixed_discovery_version()
+ {
+ // arrange
+ var original = new ConnectionLinksDiscoveryRequestStructure
+ {
+ RequestTimestamp = DateTimeOffset.UnixEpoch,
+ RequestorRef = new ParticipantRefStructure { Value = "test:requestor" },
+ };
+ var serializer = new XmlSerializer(original.GetType());
+
+ // act
+ using var writer = new StringWriter();
+ serializer.Serialize(writer, original);
+ var xml = XDocument.Parse(writer.ToString());
+
+ // assert
+ var version = xml.Root!.Attribute("version");
+ version.Should().NotBeNull();
+ version!.Value.Should().Be("2.1");
+ typeof(ConnectionLinksDiscoveryRequestStructure).GetProperty(nameof(original.Version))!.CanWrite.Should().BeFalse();
+ }
+
+ [Test]
+ public void Should_include_optional_fixed_capability_only_when_requested()
+ {
+ // arrange
+ var original = new SituationExchangeServiceCapabilitiesStructureTopicFiltering
+ {
+ DefaultPreviewInterval = TimeSpan.FromHours(1),
+ };
+ var serializer = new XmlSerializer(original.GetType());
+ using var untouchedWriter = new StringWriter();
+ serializer.Serialize(untouchedWriter, original);
+
+ // act
+ original.IncludeFilterByLocationRef();
+ using var writer = new StringWriter();
+ serializer.Serialize(writer, original);
+ var xml = XDocument.Parse(writer.ToString());
+ using var reader = new StringReader(writer.ToString());
+ var result = (SituationExchangeServiceCapabilitiesStructureTopicFiltering)serializer.Deserialize(reader)!;
+ using var roundTripWriter = new StringWriter();
+ serializer.Serialize(roundTripWriter, result);
+
+ // assert
+ XDocument.Parse(untouchedWriter.ToString()).Descendants()
+ .Should().NotContain(element => element.Name.LocalName == "FilterByLocationRef");
+ xml.Descendants().Single(element => element.Name.LocalName == "FilterByLocationRef").Value.Should().Be("true");
+ XDocument.Parse(roundTripWriter.ToString()).Descendants()
+ .Single(element => element.Name.LocalName == "FilterByLocationRef").Value.Should().Be("true");
+ }
+
+ [Test]
+ public void Should_serialize_required_fixed_vehicle_monitoring_capability()
+ {
+ // arrange
+ var original = new VehicleMonitoringServiceCapabilitiesStructureTopicFiltering
+ {
+ DefaultPreviewInterval = TimeSpan.FromHours(1),
+ };
+ var serializer = new XmlSerializer(original.GetType());
+
+ // act
+ using var writer = new StringWriter();
+ serializer.Serialize(writer, original);
+ var xml = XDocument.Parse(writer.ToString());
+
+ // assert
+ var capability = xml.Root!.Element(XName.Get("FilterByVehicleMonitoringRef", "http://www.siri.org.uk/siri"));
+ capability.Should().NotBeNull();
+ capability!.Value.Should().Be("true");
+ }
+}
diff --git a/src/siri/Spillgebees.SIRI.Models.Tests/Serialization/SiriSerializationTests.cs b/src/siri/Spillgebees.SIRI.Models.Tests/Serialization/SiriSerializationTests.cs
index ba51476..55259cd 100644
--- a/src/siri/Spillgebees.SIRI.Models.Tests/Serialization/SiriSerializationTests.cs
+++ b/src/siri/Spillgebees.SIRI.Models.Tests/Serialization/SiriSerializationTests.cs
@@ -153,13 +153,8 @@ public void Should_have_correct_xml_type_namespace_on_siri_types()
xmlTypeAttr.Namespace.Should().Be("http://www.siri.org.uk/siri");
}
- ///
- /// Siri.Version defaults to "2.1" via backing field initialization.
- /// With [DefaultValueAttribute] suppressed on string? properties,
- /// XmlSerializer must include the default value in the serialized XML.
- ///
[Test]
- public void Should_serialize_default_string_value_when_property_is_left_as_default()
+ public void Should_omit_untouched_default_string_value()
{
// arrange
var serializer = new XmlSerializer(typeof(Siri));
@@ -174,7 +169,7 @@ public void Should_serialize_default_string_value_when_property_is_left_as_defau
var deserialized = serializer.Deserialize(reader) as Siri;
// assert
- xml.Should().Contain("version=\"2.1\"");
+ xml.Should().NotContain("version=\"2.1\"");
deserialized.Should().NotBeNull();
deserialized.Version.Should().Be("2.1");
}
diff --git a/src/siri/Spillgebees.SIRI.Models.Tests/XsdTypeMappingTests.cs b/src/siri/Spillgebees.SIRI.Models.Tests/XsdTypeMappingTests.cs
index e7dd629..ec50c7c 100644
--- a/src/siri/Spillgebees.SIRI.Models.Tests/XsdTypeMappingTests.cs
+++ b/src/siri/Spillgebees.SIRI.Models.Tests/XsdTypeMappingTests.cs
@@ -110,7 +110,7 @@ public void Should_not_have_default_value_attribute_on_nullable_string_property_
}
[Test]
- public void Should_still_have_default_value_attribute_on_value_type_property_with_xsd_default()
+ public void Should_track_assignment_instead_of_omitting_explicit_default_values()
{
// arrange
var property = typeof(HalfOpenTimestampOutputRangeStructure)
@@ -120,8 +120,8 @@ public void Should_still_have_default_value_attribute_on_value_type_property_wit
var attr = property.GetCustomAttribute();
// assert
- attr.Should().NotBeNull();
- attr!.Value.Should().Be(EndTimeStatusEnumeration.Undefined);
+ attr.Should().BeNull();
+ property.DeclaringType!.GetMethod("ShouldSerialize" + property.Name).Should().NotBeNull();
}
[Test]