diff --git a/Directory.Packages.props b/Directory.Packages.props index fb1dcee..f0ba2a3 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -13,7 +13,7 @@ - + diff --git a/src/EncDotNet.Iso8211/Iso8211DataDescriptiveRecordReader.cs b/src/EncDotNet.Iso8211/Iso8211DataDescriptiveRecordReader.cs index 0481042..f020aca 100644 --- a/src/EncDotNet.Iso8211/Iso8211DataDescriptiveRecordReader.cs +++ b/src/EncDotNet.Iso8211/Iso8211DataDescriptiveRecordReader.cs @@ -366,7 +366,8 @@ private static void ParseSubfieldLabels( int starIndex = rawName.IndexOf('*'); if (starIndex > 0) { - string leaderName = rawName.Substring(0, starIndex); + // S-100 Part 10a writes "\\" just before the '*'; it is not part of the label. + string leaderName = TrimLabel(rawName.Substring(0, starIndex)); if (!string.IsNullOrEmpty(leaderName)) { names.Add(leaderName); @@ -378,6 +379,7 @@ private static void ParseSubfieldLabels( } } + rawName = TrimLabel(rawName); if (!string.IsNullOrEmpty(rawName)) { names.Add(rawName); @@ -388,6 +390,11 @@ private static void ParseSubfieldLabels( subfieldNames = names.ToImmutable(); } + /// + /// Removes the trailing backslashes S-100 Part 10a places before a repeating-group *. + /// + private static string TrimLabel(string label) => label.TrimEnd('\\'); + /// /// Parses the descriptor portion of a DDR field into a field name and subfield names. /// @@ -439,6 +446,7 @@ private static void ParseDescriptors( rawName = rawName.Substring(1); } + rawName = TrimLabel(rawName); if (!string.IsNullOrEmpty(rawName)) { names.Add(rawName); diff --git a/tests/EncDotNet.UnitTests/Iso8211DataDescriptiveRecordReaderTests.cs b/tests/EncDotNet.UnitTests/Iso8211DataDescriptiveRecordReaderTests.cs index 20d26b0..d34734b 100644 --- a/tests/EncDotNet.UnitTests/Iso8211DataDescriptiveRecordReaderTests.cs +++ b/tests/EncDotNet.UnitTests/Iso8211DataDescriptiveRecordReaderTests.cs @@ -1528,6 +1528,55 @@ public void Parse_TwoUtFormat_ConcatenatedArrayWithLeaderAndRepeating_ParsesCorr Assert.True(c3il.SubfieldDefinitions[3].IsRepeating); } + [Fact] + public void Parse_TwoUtFormat_S100BackslashesBeforeStar_AreTrimmedFromLeaderName() + { + // Arrange — S-100 Part 10a writes "\\" before the '*' that starts the repeating group + // (S-101 2.0 DSID descriptor). + var record = CreateDdrRecordTwoUt( + tag: "DSID", + dataStructureCode: '1', + dataTypeCode: '6', + fieldName: "Dataset Identification", + subfieldLabels: @"RCNM!RCID!ENSP!ENED!PRSP!PRED!PROF!DSNM!DSTL!DSRD!DSLG!DSAB!DSED\\*DSTC", + formatControls: "(b11,b14,11A,b11)"); + + // Act + var ddr = Iso8211DataDescriptiveRecordReader.Read(record); + var dsid = ddr.FieldDefinitions[0]; + + // Assert + Assert.Equal(14, dsid.SubfieldDefinitions.Count); + Assert.Equal("DSED", dsid.SubfieldDefinitions[12].Name); + Assert.Equal("DSTC", dsid.SubfieldDefinitions[13].Name); + Assert.Equal(13, dsid.RepeatingSubfieldStartIndex); + Assert.False(dsid.SubfieldDefinitions[12].IsRepeating); + Assert.True(dsid.SubfieldDefinitions[13].IsRepeating); + } + + [Fact] + public void Parse_TwoUtFormat_S100BackslashesBeforeStar_SingleLeaderSubfield() + { + // Arrange — S-101 2.0 C3IL descriptor + var record = CreateDdrRecordTwoUt( + tag: "C3IL", + dataStructureCode: '3', + dataTypeCode: '5', + fieldName: "3-D Integer Coordinate List", + subfieldLabels: @"VCID\\*YCOO!XCOO!ZCOO", + formatControls: "(b11,3b24)"); + + // Act + var ddr = Iso8211DataDescriptiveRecordReader.Read(record); + var c3il = ddr.FieldDefinitions[0]; + + // Assert + Assert.Equal(4, c3il.SubfieldDefinitions.Count); + Assert.Equal("VCID", c3il.SubfieldDefinitions[0].Name); + Assert.Equal("YCOO", c3il.SubfieldDefinitions[1].Name); + Assert.Equal(1, c3il.RepeatingSubfieldStartIndex); + } + [Fact] public void Parse_TwoUtFormat_VectorStyleStarAtStart_StillWorks() {