diff --git a/src/Hl7.Fhir.Base/CompatibilitySuppressions.xml b/src/Hl7.Fhir.Base/CompatibilitySuppressions.xml
index dc3bc4cf75..77b42f2d3f 100644
--- a/src/Hl7.Fhir.Base/CompatibilitySuppressions.xml
+++ b/src/Hl7.Fhir.Base/CompatibilitySuppressions.xml
@@ -84,6 +84,41 @@
lib/net8.0/Hl7.Fhir.Base.dlltrue
+
+ CP0002
+ M:Hl7.Fhir.FhirPath.FhirEvaluationContext.get_TerminologyService
+ lib/net8.0/Hl7.Fhir.Base.dll
+ lib/net8.0/Hl7.Fhir.Base.dll
+ true
+
+
+ CP0002
+ M:Hl7.Fhir.FhirPath.FhirEvaluationContext.WithResourceOverrides(Hl7.Fhir.ElementModel.ITypedElement,Hl7.Fhir.ElementModel.ITypedElement)
+ lib/net8.0/Hl7.Fhir.Base.dll
+ lib/net8.0/Hl7.Fhir.Base.dll
+ true
+
+
+ CP0002
+ M:Hl7.Fhir.Model.Parameters.get_Item(System.String)
+ lib/net8.0/Hl7.Fhir.Base.dll
+ lib/net8.0/Hl7.Fhir.Base.dll
+ true
+
+
+ CP0002
+ M:Hl7.Fhir.Rest.ContentType.BuildContentType(Hl7.Fhir.Rest.ResourceFormat,System.String)
+ lib/net8.0/Hl7.Fhir.Base.dll
+ lib/net8.0/Hl7.Fhir.Base.dll
+ true
+
+
+ CP0002
+ M:Hl7.Fhir.Rest.ContentType.BuildMediaType(Hl7.Fhir.Rest.ResourceFormat,System.String)
+ lib/net8.0/Hl7.Fhir.Base.dll
+ lib/net8.0/Hl7.Fhir.Base.dll
+ true
+ CP0002M:Hl7.Fhir.Serialization.IFhirSerializationEngine.SerializeToXml(Hl7.Fhir.Model.Resource)
@@ -105,6 +140,20 @@
lib/net8.0/Hl7.Fhir.Base.dlltrue
+
+ CP0002
+ M:Hl7.Fhir.Utility.ReflectionHelper.IsTypedCollection(System.Type)
+ lib/net8.0/Hl7.Fhir.Base.dll
+ lib/net8.0/Hl7.Fhir.Base.dll
+ true
+
+
+ CP0002
+ M:Hl7.FhirPath.EvaluationContext.WithResourceOverrides(Hl7.Fhir.ElementModel.ITypedElement,Hl7.Fhir.ElementModel.ITypedElement)
+ lib/net8.0/Hl7.Fhir.Base.dll
+ lib/net8.0/Hl7.Fhir.Base.dll
+ true
+ CP0002M:Hl7.Fhir.ElementModel.TypedElementExtensions.IsExactlyEqualTo``1(``0,``0,System.Boolean)
@@ -168,6 +217,41 @@
lib/netstandard2.0/Hl7.Fhir.Base.dlltrue
+
+ CP0002
+ M:Hl7.Fhir.FhirPath.FhirEvaluationContext.get_TerminologyService
+ lib/netstandard2.0/Hl7.Fhir.Base.dll
+ lib/netstandard2.0/Hl7.Fhir.Base.dll
+ true
+
+
+ CP0002
+ M:Hl7.Fhir.FhirPath.FhirEvaluationContext.WithResourceOverrides(Hl7.Fhir.ElementModel.ITypedElement,Hl7.Fhir.ElementModel.ITypedElement)
+ lib/netstandard2.0/Hl7.Fhir.Base.dll
+ lib/netstandard2.0/Hl7.Fhir.Base.dll
+ true
+
+
+ CP0002
+ M:Hl7.Fhir.Model.Parameters.get_Item(System.String)
+ lib/netstandard2.0/Hl7.Fhir.Base.dll
+ lib/netstandard2.0/Hl7.Fhir.Base.dll
+ true
+
+
+ CP0002
+ M:Hl7.Fhir.Rest.ContentType.BuildContentType(Hl7.Fhir.Rest.ResourceFormat,System.String)
+ lib/netstandard2.0/Hl7.Fhir.Base.dll
+ lib/netstandard2.0/Hl7.Fhir.Base.dll
+ true
+
+
+ CP0002
+ M:Hl7.Fhir.Rest.ContentType.BuildMediaType(Hl7.Fhir.Rest.ResourceFormat,System.String)
+ lib/netstandard2.0/Hl7.Fhir.Base.dll
+ lib/netstandard2.0/Hl7.Fhir.Base.dll
+ true
+ CP0002M:Hl7.Fhir.Serialization.IFhirSerializationEngine.SerializeToXml(Hl7.Fhir.Model.Resource)
@@ -189,6 +273,20 @@
lib/netstandard2.0/Hl7.Fhir.Base.dlltrue
+
+ CP0002
+ M:Hl7.Fhir.Utility.ReflectionHelper.IsTypedCollection(System.Type)
+ lib/netstandard2.0/Hl7.Fhir.Base.dll
+ lib/netstandard2.0/Hl7.Fhir.Base.dll
+ true
+
+
+ CP0002
+ M:Hl7.FhirPath.EvaluationContext.WithResourceOverrides(Hl7.Fhir.ElementModel.ITypedElement,Hl7.Fhir.ElementModel.ITypedElement)
+ lib/netstandard2.0/Hl7.Fhir.Base.dll
+ lib/netstandard2.0/Hl7.Fhir.Base.dll
+ true
+ CP0006M:Hl7.Fhir.ElementModel.ITypedElement.Children(System.String)
@@ -329,46 +427,4 @@
lib/netstandard2.0/Hl7.Fhir.Base.dlltrue
-
- CP0002
- M:Hl7.Fhir.Model.Parameters.get_Item(System.String)
- lib/net8.0/Hl7.Fhir.Base.dll
- lib/net8.0/Hl7.Fhir.Base.dll
- true
-
-
- CP0002
- M:Hl7.Fhir.Utility.ReflectionHelper.IsTypedCollection(System.Type)
- lib/net8.0/Hl7.Fhir.Base.dll
- lib/net8.0/Hl7.Fhir.Base.dll
- true
-
-
- CP0002
- M:Hl7.Fhir.Model.Parameters.get_Item(System.String)
- lib/netstandard2.0/Hl7.Fhir.Base.dll
- lib/netstandard2.0/Hl7.Fhir.Base.dll
- true
-
-
- CP0002
- M:Hl7.Fhir.Utility.ReflectionHelper.IsTypedCollection(System.Type)
- lib/netstandard2.0/Hl7.Fhir.Base.dll
- lib/netstandard2.0/Hl7.Fhir.Base.dll
- true
-
-
- CP0002
- M:Hl7.Fhir.FhirPath.FhirEvaluationContext.get_TerminologyService
- lib/net8.0/Hl7.Fhir.Base.dll
- lib/net8.0/Hl7.Fhir.Base.dll
- true
-
-
- CP0002
- M:Hl7.Fhir.FhirPath.FhirEvaluationContext.get_TerminologyService
- lib/netstandard2.0/Hl7.Fhir.Base.dll
- lib/netstandard2.0/Hl7.Fhir.Base.dll
- true
-
\ No newline at end of file
diff --git a/src/Hl7.Fhir.Base/FhirPath/EvaluationContext.cs b/src/Hl7.Fhir.Base/FhirPath/EvaluationContext.cs
index a69511bb98..9b71ec64f2 100644
--- a/src/Hl7.Fhir.Base/FhirPath/EvaluationContext.cs
+++ b/src/Hl7.Fhir.Base/FhirPath/EvaluationContext.cs
@@ -41,12 +41,6 @@ public EvaluationContext(ITypedElement? resource, ITypedElement? rootResource, I
{
Environment = environment;
}
-
- ///
- /// Explicitly override the values of %resource and %rootResource in the evaluation context.
- ///
- public static EvaluationContext WithResourceOverrides(ITypedElement? resource, ITypedElement? rootResource = null) =>
- new EvaluationContext { Resource = resource, RootResource = rootResource ?? resource };
///
/// The data represented by %rootResource.
@@ -67,4 +61,14 @@ public static EvaluationContext WithResourceOverrides(ITypedElement? resource, I
/// A delegate that handles the output for the trace() function.
///
public Action>? Tracer { get; set; }
+}
+
+public static class EvaluationContextExtensions
+{
+ public static T WithResourceOverrides(this T context, ITypedElement? resource, ITypedElement? rootResource = null) where T : EvaluationContext
+ {
+ context.Resource = resource;
+ context.RootResource = rootResource ?? resource;
+ return context;
+ }
}
\ No newline at end of file
diff --git a/src/Hl7.Fhir.Base/FhirPath/FhirEvaluationContext.cs b/src/Hl7.Fhir.Base/FhirPath/FhirEvaluationContext.cs
index 41c57cc670..b1817fd9e1 100644
--- a/src/Hl7.Fhir.Base/FhirPath/FhirEvaluationContext.cs
+++ b/src/Hl7.Fhir.Base/FhirPath/FhirEvaluationContext.cs
@@ -64,11 +64,6 @@ public FhirEvaluationContext(ScopedNode node)
RootResource = Resource is ScopedNode sn ? sn.ResourceContext : node;
}
- ///
- /// Explicitly override the values of %resource and %rootResource in the evaluation context.
- ///
- public static new FhirEvaluationContext WithResourceOverrides(ITypedElement? resource, ITypedElement? rootResource = null) =>
- (FhirEvaluationContext)EvaluationContext.WithResourceOverrides(resource, rootResource);
public ICodeValidationTerminologyService? TerminologyService { get; set; }
private static ITypedElement toNearestResource(ScopedNode node)
@@ -93,4 +88,4 @@ public Func? ElementResolver
}
}
-#nullable restore
+#nullable restore
\ No newline at end of file
diff --git a/src/Hl7.Fhir.Base/Model/Parameters.cs b/src/Hl7.Fhir.Base/Model/Parameters.cs
index db939979ca..00efc383ee 100644
--- a/src/Hl7.Fhir.Base/Model/Parameters.cs
+++ b/src/Hl7.Fhir.Base/Model/Parameters.cs
@@ -122,7 +122,7 @@ public void Remove(string name, bool matchPrefix = false)
/// Searches for a parameter with the given name, and returns the matching parameter(s)
///
/// The name of the parameter
- /// If true, will remove all parameters which begin with the string given in the "name" parameter
+ /// If true, will retrieve all parameters which begin with the string given in the "name" parameter
public IEnumerable Get(string name, bool matchPrefix = false)
{
if (name == null) throw new ArgumentNullException("name");
@@ -137,7 +137,7 @@ public IEnumerable Get(string name, bool matchPrefix = false
/// Searches for a parameter with the given name, and returns the matching parameter(s)
///
/// The name of the parameter
- /// If true, will remove all parameters which begin with the string given in the "name" parameter
+ /// If true, will retrieve all parameters which begin with the string given in the "name" parameter
public ParameterComponent GetSingle(string name, bool matchPrefix = false)
{
if (name == null) throw new ArgumentNullException("name");
@@ -174,4 +174,4 @@ private string DebuggerDisplay
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Hl7.Fhir.Base/Rest/ContentType.cs b/src/Hl7.Fhir.Base/Rest/ContentType.cs
index 573e8a0ede..0cc1699114 100644
--- a/src/Hl7.Fhir.Base/Rest/ContentType.cs
+++ b/src/Hl7.Fhir.Base/Rest/ContentType.cs
@@ -102,8 +102,9 @@ public static ResourceFormat GetResourceFormatFromContentType(string? contentTyp
///
/// Whether the body is xml or json.
/// Optional. The version of FHIR to add to the header.
- public static string BuildContentType(ResourceFormat format, string? fhirVersion = default) =>
- BuildMediaType(format, fhirVersion).ToString();
+ /// Optional. Whether exclude charset.
+ public static string BuildContentType(ResourceFormat format, string? fhirVersion = default, bool excludeCharset = false) =>
+ BuildMediaType(format, fhirVersion, excludeCharset).ToString();
///
/// Creates a for use in a Content-Type header,
@@ -111,8 +112,9 @@ public static string BuildContentType(ResourceFormat format, string? fhirVersion
///
/// Whether the body is xml or json.
/// Optional. The version of FHIR to add to the header.
+ /// Optional. Whether exclude charset.
/// Unsupported serialization.
- public static MediaTypeHeaderValue BuildMediaType(ResourceFormat format, string? fhirVersion = default)
+ public static MediaTypeHeaderValue BuildMediaType(ResourceFormat format, string? fhirVersion = default, bool excludeCharset = false)
{
var contentType = format switch
{
@@ -121,10 +123,11 @@ public static MediaTypeHeaderValue BuildMediaType(ResourceFormat format, string?
_ => throw new ArgumentException("Cannot determine content type for data format " + format),
};
- var result = new MediaTypeHeaderValue(contentType)
+ var result = new MediaTypeHeaderValue(contentType);
+ if (!excludeCharset)
{
- CharSet = Encoding.UTF8.WebName
- };
+ result.CharSet = Encoding.UTF8.WebName;
+ }
if (fhirVersion is not null && SemVersion.TryParse(fhirVersion, out var version))
{
diff --git a/src/Hl7.Fhir.Base/Rest/HttpContentBuilders.cs b/src/Hl7.Fhir.Base/Rest/HttpContentBuilders.cs
index d271891200..3978eee48c 100644
--- a/src/Hl7.Fhir.Base/Rest/HttpContentBuilders.cs
+++ b/src/Hl7.Fhir.Base/Rest/HttpContentBuilders.cs
@@ -134,8 +134,8 @@ public static HttpRequestMessage WithAccept(this HttpRequestMessage message,
string? contentTypeFhirVersion,
bool requestCompressedResponse)
{
- message.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse(
- ContentType.BuildContentType(serialization, contentTypeFhirVersion)));
+ message.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse(ContentType.BuildContentType(serialization, contentTypeFhirVersion, true)));
+ message.Headers.AcceptCharset.Add(new StringWithQualityHeaderValue(Encoding.UTF8.WebName));
if (requestCompressedResponse)
{
diff --git a/src/Hl7.Fhir.Conformance/Specification/Snapshot/SnapshotGeneratorExtensions.cs b/src/Hl7.Fhir.Base/Specification/Snapshot/SnapshotGeneratorExtensions.cs
similarity index 68%
rename from src/Hl7.Fhir.Conformance/Specification/Snapshot/SnapshotGeneratorExtensions.cs
rename to src/Hl7.Fhir.Base/Specification/Snapshot/SnapshotGeneratorExtensions.cs
index b1b8688e5c..3cd2cb0abb 100644
--- a/src/Hl7.Fhir.Conformance/Specification/Snapshot/SnapshotGeneratorExtensions.cs
+++ b/src/Hl7.Fhir.Base/Specification/Snapshot/SnapshotGeneratorExtensions.cs
@@ -7,7 +7,7 @@
*/
using Hl7.Fhir.Model;
-using Hl7.Fhir.Support;
+using Hl7.Fhir.Rest;
using Hl7.Fhir.Utility;
using System;
using System.Collections.Generic;
@@ -19,7 +19,7 @@ namespace Hl7.Fhir.Specification.Snapshot
// This extension indicates snapshot elements with associated differential constraints in the profile.
// Note: extensions are persisted to XML/JSON, whereas annotations are ephemeral (in-memory only)
- /// Helper methods for the class to generate and inspect custom extensions.
+ /// Helper methods for the SnapshotGenerator class to generate and inspect custom extensions.
public static class SnapshotGeneratorExtensions
{
/// The canonical url of the extension definition that marks snapshot elements with associated differential constraints.
@@ -54,6 +54,7 @@ public static void RemoveConstrainedByDiffExtension(this IExtendable element)
}
/// Recursively removes all instances of the extension from the specified element definition and all it's child objects.
+ [Obsolete("Use RemoveAllNonInheritableExtensions(this Element element) instead.")]
public static void RemoveAllConstrainedByDiffExtensions(this Element element)
{
if (element == null) { throw Error.ArgumentNull(nameof(element)); }
@@ -65,6 +66,7 @@ public static void RemoveAllConstrainedByDiffExtensions(this Element element)
}
/// Recursively removes all instances of the extension from all the elements and their respective child objects.
+ [Obsolete("Use RemoveAllNonInheritableExtensions(this IEnumerable elements) instead.")]
public static void RemoveAllConstrainedByDiffExtensions(this IEnumerable elements) where T : Element
{
if (elements == null) { throw Error.ArgumentNull(nameof(elements)); }
@@ -74,6 +76,47 @@ public static void RemoveAllConstrainedByDiffExtensions(this IEnumerable e
}
}
+
+ internal static void RemoveAllNonInheritableExtensions(this Element element)
+ {
+ if (element == null) { throw Error.ArgumentNull(nameof(element)); }
+ element.RemoveNonInheritableExtensions();
+ foreach (var child in element.Children.OfType())
+ {
+ child.RemoveAllNonInheritableExtensions();
+ }
+ }
+
+ internal static void RemoveNonInheritableExtensions(this IExtendable element)
+ {
+ if (element == null) { throw Error.ArgumentNull(nameof(element)); }
+ foreach (var ext in _nonInheritableExtensions)
+ {
+ element.RemoveExtension(ext);
+ }
+ }
+
+ private static readonly List _nonInheritableExtensions = [
+ ResourceIdentity.CORE_BASE_URL + "elementdefinition-isCommonBinding",
+ ResourceIdentity.CORE_BASE_URL + "structuredefinition-fmm",
+ ResourceIdentity.CORE_BASE_URL + "structuredefinition-fmm-no-warnings",
+ ResourceIdentity.CORE_BASE_URL + "structuredefinition-hierarchy",
+ ResourceIdentity.CORE_BASE_URL + "structuredefinition-interface",
+ ResourceIdentity.CORE_BASE_URL + "structuredefinition-normative-version",
+ ResourceIdentity.CORE_BASE_URL + "structuredefinition-applicable-version",
+ ResourceIdentity.CORE_BASE_URL + "structuredefinition-category",
+ ResourceIdentity.CORE_BASE_URL + "structuredefinition-codegen-super",
+ ResourceIdentity.CORE_BASE_URL + "structuredefinition-security-category",
+ ResourceIdentity.CORE_BASE_URL + "structuredefinition-standards-status",
+ ResourceIdentity.CORE_BASE_URL + "structuredefinition-summary",
+ ResourceIdentity.CORE_BASE_URL + "structuredefinition-wg",
+ ResourceIdentity.CORE_BASE_URL + "replaces",
+ ResourceIdentity.CORE_BASE_URL + "resource-approvalDate",
+ ResourceIdentity.CORE_BASE_URL + "resource-effectivePeriod",
+ ResourceIdentity.CORE_BASE_URL + "resource-lastReviewDate",
+ CONSTRAINED_BY_DIFF_EXT //this is our own extension to define differences compared to the base, this can't be inherited from the base profile
+ ];
+
// ========== For internal use only ==========
// [WMR 20170209] OBSOLETE
#if false
diff --git a/src/Hl7.Fhir.Conformance/CompatibilitySuppressions.xml b/src/Hl7.Fhir.Conformance/CompatibilitySuppressions.xml
new file mode 100644
index 0000000000..50df2e8381
--- /dev/null
+++ b/src/Hl7.Fhir.Conformance/CompatibilitySuppressions.xml
@@ -0,0 +1,18 @@
+
+
+
+
+ CP0001
+ T:Hl7.Fhir.Specification.Snapshot.SnapshotGeneratorExtensions
+ lib/net8.0/Hl7.Fhir.Conformance.dll
+ lib/net8.0/Hl7.Fhir.Conformance.dll
+ true
+
+
+ CP0001
+ T:Hl7.Fhir.Specification.Snapshot.SnapshotGeneratorExtensions
+ lib/netstandard2.0/Hl7.Fhir.Conformance.dll
+ lib/netstandard2.0/Hl7.Fhir.Conformance.dll
+ true
+
+
\ No newline at end of file
diff --git a/src/Hl7.Fhir.Conformance/Specification/Snapshot/ElementDefnMerger.cs b/src/Hl7.Fhir.Conformance/Specification/Snapshot/ElementDefnMerger.cs
index bf508b3588..593fed0cda 100644
--- a/src/Hl7.Fhir.Conformance/Specification/Snapshot/ElementDefnMerger.cs
+++ b/src/Hl7.Fhir.Conformance/Specification/Snapshot/ElementDefnMerger.cs
@@ -156,7 +156,7 @@ void merge(ElementDefinition snap, ElementDefinition diff, bool mergeElementId,
// Constraints are cumulative, so they are always "new" (hence a constant false for the comparer)
// [WMR 20160917] Note: constraint keys must be unique. The validator will detect duplicate keys, so the derived
// profile author can correct the conflicting constraint key.
- // [WMR 20160918] MUST merge indentical constraints, otherwise each derived profile accumulates
+ // [WMR 20160918] MUST merge identical constraints, otherwise each derived profile accumulates
// additional identical constraints inherited from e.g. BackboneElement.
// snap.Constraint = mergeCollection(snap.Constraint, diff.Constraint, (a, b) => false);
// [WMR 20190723] R4 NEW: Initialize Constraint.source property
@@ -283,7 +283,7 @@ ElementDefinition.TypeRefComponent mergeElementType(ElementDefinition.TypeRefCom
// TODO: Move logic to MergeTo method on partial class TypeRefComponent
// TODO: Copy diff annotations...?
- if (diff.ElementId != null) { result.ElementId = diff.ElementId; }
+ result.ElementId = mergeString(snap.ElementId, diff.ElementId);
result.Extension = mergeExtensions(snap.Extension, diff.Extension);
result.CodeElement = mergePrimitiveElement(snap.CodeElement, diff.CodeElement);
@@ -366,6 +366,7 @@ private ElementDefinition.ElementDefinitionBindingComponent mergeBinding(Element
snap.StrengthElement = mergePrimitiveElement(snap.StrengthElement, diff.StrengthElement);
snap.DescriptionElement = mergePrimitiveElement(snap.DescriptionElement, diff.DescriptionElement);
snap.ValueSetElement = mergeComplexAttribute(snap.ValueSetElement, diff.ValueSetElement);
+ snap.ElementId = mergeString(snap.ElementId, diff.ElementId);
snap.Extension = mergeExtensions(snap.Extension, diff.Extension);
snap.Additional = mergeCollection(snap.Additional, diff.Additional, matchExactly);
onConstraint(result);
@@ -670,7 +671,8 @@ T mergePrimitiveElement(T snap, T diff, bool allowAppend = false) where T : P
{
result.ObjectValue = diffValue;
}
- // Also merge extensions on primitives
+ // Also merge element id and extensions on primitives
+ result.ElementId = mergeString(snap.ElementId, diff.ElementId);
result.Extension = mergeExtensions(snap.Extension, diff.Extension);
onConstraint(result);
}
@@ -692,7 +694,7 @@ static string mergeId(ElementDefinition snap, ElementDefinition diff, bool merge
}
// Newly introduced named slices NEVER inherit element id
// Must always regenerate new unique identifier for named slices
- else if (!IsEqualName(diff.SliceName, snap.SliceName))
+ if (!IsEqualName(diff.SliceName, snap.SliceName))
{
// Regenerate; don't inherit from snap
return null;
@@ -700,13 +702,13 @@ static string mergeId(ElementDefinition snap, ElementDefinition diff, bool merge
// Otherwise inherit existing element id from snap
return snap.ElementId;
}
- else
- {
- // Don't merge elementId, e.g. for type profiles
- return null;
- }
+
+ // Don't merge elementId, e.g. for type profiles
+ return null;
}
+ static string mergeString(string snap, string diff) => diff ?? snap;
+
// Functions to match snap collection items to diff collection items
// Matching key depends on collection type
diff --git a/src/Hl7.Fhir.Conformance/Specification/Snapshot/SnapshotGenerator.cs b/src/Hl7.Fhir.Conformance/Specification/Snapshot/SnapshotGenerator.cs
index 3ab2d39af4..87d34e30b7 100644
--- a/src/Hl7.Fhir.Conformance/Specification/Snapshot/SnapshotGenerator.cs
+++ b/src/Hl7.Fhir.Conformance/Specification/Snapshot/SnapshotGenerator.cs
@@ -465,7 +465,7 @@ private async Tasks.Task> generate(StructureDefinition s
// [WMR 20170208] Moved to *AFTER* ensureBaseComponents - emits annotations...
// [WMR 20160915] Derived profiles should never inherit the ChangedByDiff extension from the base structure
- snapshot.Element.RemoveAllConstrainedByDiffExtensions();
+ snapshot.RemoveAllNonInheritableExtensions();
snapshot.Element.RemoveAllConstrainedByDiffAnnotations();
// Notify observers
@@ -1487,7 +1487,7 @@ private static bool copyChildren(ElementDefinitionNavigator nav, ElementDefiniti
var elem = elems[pos];
// [WMR 20160826] Never inherit Changed extension from base profile!
- elem.RemoveAllConstrainedByDiffExtensions();
+ elem.RemoveAllNonInheritableExtensions();
elem.RemoveAllConstrainedByDiffAnnotations();
// [WMR 20160902] Initialize empty ElementDefinition.Base components if necessary
@@ -2224,11 +2224,17 @@ private async Tasks.Task ensureSnapshot(StructureDefinition sd, string pro
try
{
- if (_settings.GenerateSnapshotForExternalProfiles
+ var shouldGenerate = _settings.RegenerationBehaviour switch
+ {
+ RegenerationSettings.TRY_USE_EXISTING => !sd.HasSnapshot,
+ RegenerationSettings.REGENERATE_ONCE => !sd.HasSnapshot || !sd.Snapshot.IsCreatedBySnapshotGenerator(),
#pragma warning disable CS0618 // Type or member is obsolete
- && (!sd.HasSnapshot || (_settings.ForceRegenerateSnapshots && !sd.Snapshot.IsCreatedBySnapshotGenerator()))
- )
+ RegenerationSettings.FORCE_REGENERATE => true, // possible infinite recursion
#pragma warning restore CS0618 // Type or member is obsolete
+ _ => throw new InvalidOperationException($"Invalid RegenerationSettings value {_settings.RegenerationBehaviour}")
+ };
+
+ if (_settings.GenerateSnapshotForExternalProfiles && shouldGenerate)
{
// Automatically expand external profiles on demand
// Debug.Print($"[{nameof(SnapshotGenerator)}.{nameof(ensureSnapshot)}] Recursively generate snapshot for type profile with url: '{sd.Url}' ...");
@@ -2310,11 +2316,18 @@ private async Tasks.Task getSnapshotRootElement(StructureDefi
var cachedRoot = sd.GetSnapshotRootElementAnnotation();
if (cachedRoot != null) { return cachedRoot; }
#endif
-
- // 2. Return root element definition from existing (pre-generated) snapshot, if it exists
+ var hasValidRoot = _settings.RegenerationBehaviour switch
+ {
+ RegenerationSettings.TRY_USE_EXISTING => sd.HasSnapshot,
+ RegenerationSettings.REGENERATE_ONCE => sd.HasSnapshot && sd.Snapshot.IsCreatedBySnapshotGenerator(),
#pragma warning disable CS0618 // Type or member is obsolete
- if (sd.HasSnapshot && (sd.Snapshot.IsCreatedBySnapshotGenerator() || !_settings.ForceRegenerateSnapshots))
+ RegenerationSettings.FORCE_REGENERATE => false,
#pragma warning restore CS0618 // Type or member is obsolete
+ _ => throw new InvalidOperationException($"Invalid RegenerationSettings value {_settings.RegenerationBehaviour}")
+ };
+
+ // 2. Return root element definition from existing (pre-generated) snapshot, if it exists
+ if (hasValidRoot)
{
// Debug.Print($"[{nameof(SnapshotGenerator)}.{nameof(getSnapshotRootElement)}] {nameof(profileUri)} = '{profileUri}' - use existing root element definition from snapshot: #{sd.Snapshot.Element[0].GetHashCode()}");
// No need to save root ElemDef annotation, as the snapshot has already been fully expanded
diff --git a/src/Hl7.Fhir.STU3.Tests/Model/ValidateAllExamplesSearchExtractionTest.cs b/src/Hl7.Fhir.STU3.Tests/Model/ValidateAllExamplesSearchExtractionTest.cs
index 0ddb477ff2..508b850b7c 100644
--- a/src/Hl7.Fhir.STU3.Tests/Model/ValidateAllExamplesSearchExtractionTest.cs
+++ b/src/Hl7.Fhir.STU3.Tests/Model/ValidateAllExamplesSearchExtractionTest.cs
@@ -154,7 +154,7 @@ private static void ExtractExamplesFromResource(Dictionary 0)
{
foreach (var t2 in results)
diff --git a/src/Hl7.Fhir.STU3.Tests/Validation/SearchDataExtraction.cs b/src/Hl7.Fhir.STU3.Tests/Validation/SearchDataExtraction.cs
index a0217ebed4..f33881ae31 100644
--- a/src/Hl7.Fhir.STU3.Tests/Validation/SearchDataExtraction.cs
+++ b/src/Hl7.Fhir.STU3.Tests/Validation/SearchDataExtraction.cs
@@ -20,6 +20,7 @@
using System.IO.Compression;
using System.Linq;
using System.Xml;
+using FhirEvaluationContext = Hl7.Fhir.FhirPath.FhirEvaluationContext;
namespace Hl7.Fhir.Test.Validation
{
@@ -130,7 +131,7 @@ private static void ExtractValuesForSearchParameterFromFile(Dictionary exampleSearchValues, Resource resource, ModelInfo.SearchParamDefinition index, string key)
{
- var results = resource.Select(index.Expression, new FhirEvaluationContext(resource.ToTypedElement()));
+ var results = resource.Select(index.Expression, new FhirEvaluationContext());
if (results.Any())
{
// we perform the Select on a Poco, because then we get the FHIR dialect of FhirPath as well.
diff --git a/src/Hl7.Fhir.STU3/CompatibilitySuppressions.xml b/src/Hl7.Fhir.STU3/CompatibilitySuppressions.xml
index b34981588c..24cccf410d 100644
--- a/src/Hl7.Fhir.STU3/CompatibilitySuppressions.xml
+++ b/src/Hl7.Fhir.STU3/CompatibilitySuppressions.xml
@@ -1,6 +1,20 @@
+
+ CP0001
+ T:Hl7.Fhir.Specification.Snapshot.SnapshotGeneratorExtensions
+ lib/net8.0/Hl7.Fhir.STU3.dll
+ lib/net8.0/Hl7.Fhir.STU3.dll
+ true
+
+
+ CP0001
+ T:Hl7.Fhir.Specification.Snapshot.SnapshotGeneratorExtensions
+ lib/netstandard2.0/Hl7.Fhir.STU3.dll
+ lib/netstandard2.0/Hl7.Fhir.STU3.dll
+ true
+ CP0002F:Hl7.Fhir.Model.ExplanationOfBenefit.ActInvoiceGroupCode.ActInvoiceInterGroupCode
diff --git a/src/Hl7.Fhir.STU3/Specification/Snapshot/ElementDefnMerger.cs b/src/Hl7.Fhir.STU3/Specification/Snapshot/ElementDefnMerger.cs
index c115c9bb27..bcd81ac848 100644
--- a/src/Hl7.Fhir.STU3/Specification/Snapshot/ElementDefnMerger.cs
+++ b/src/Hl7.Fhir.STU3/Specification/Snapshot/ElementDefnMerger.cs
@@ -246,8 +246,9 @@ T mergePrimitiveAttribute(T snap, T diff, bool allowAppend = false) where T :
result.ObjectValue = diffText;
}
- // Also merge extensions on primitives
+ // Also merge element id and extensions on primitives
// [Backported from R4]
+ result.ElementId = mergeString(snap?.ElementId, diff.ElementId);
result.Extension = mergeExtensions(snap?.Extension, diff.Extension);
onConstraint(result);
return result;
@@ -509,6 +510,7 @@ private ElementDefinition.ElementDefinitionBindingComponent mergeBinding(Element
snap.StrengthElement = mergePrimitiveAttribute(snap.StrengthElement, diff.StrengthElement);
snap.DescriptionElement = mergePrimitiveAttribute(snap.DescriptionElement, diff.DescriptionElement);
snap.ValueSet = mergeComplexAttribute(snap.ValueSet, diff.ValueSet);
+ snap.ElementId = mergeString(snap.ElementId, diff.ElementId);
snap.Extension = mergeExtensions(snap.Extension, diff.Extension);
onConstraint(result);
}
@@ -535,7 +537,7 @@ string mergeId(ElementDefinition snap, ElementDefinition diff, bool mergeElement
}
// Newly introduced named slices NEVER inherit element id
// Must always regenerate new unique identifier for named slices
- else if (diff.SliceName != snap.SliceName)
+ if (diff.SliceName != snap.SliceName)
{
// Regenerate; don't inherit from snap
return null;
@@ -543,13 +545,13 @@ string mergeId(ElementDefinition snap, ElementDefinition diff, bool mergeElement
// Otherwise inherit existing element id from snap
return snap.ElementId;
}
- else
- {
- // Don't merge elementId, e.g. for type profiles
- return null;
- }
+
+ // Don't merge elementId, e.g. for type profiles
+ return null;
}
+ static string mergeString(string snap, string diff) => diff ?? snap;
+
// [WMR 20180611] NEW
static bool isEqualCoding(Coding c, Coding d)
{
diff --git a/src/Hl7.Fhir.STU3/Specification/Snapshot/SnapshotGenerator.cs b/src/Hl7.Fhir.STU3/Specification/Snapshot/SnapshotGenerator.cs
index 662f8531ea..8b2616a871 100644
--- a/src/Hl7.Fhir.STU3/Specification/Snapshot/SnapshotGenerator.cs
+++ b/src/Hl7.Fhir.STU3/Specification/Snapshot/SnapshotGenerator.cs
@@ -399,7 +399,8 @@ private async Tasks.Task> generate(StructureDefinition s
// [WMR 20170208] Moved to *AFTER* ensureBaseComponents - emits annotations...
// [WMR 20160915] Derived profiles should never inherit the ChangedByDiff extension from the base structure
- snapshot.Element.RemoveAllConstrainedByDiffExtensions();
+ // Also remove core extensions that are not supposed to be inherited by derived profiles
+ snapshot.RemoveAllNonInheritableExtensions();
snapshot.Element.RemoveAllConstrainedByDiffAnnotations();
// Notify observers
@@ -1309,7 +1310,7 @@ private static bool copyChildren(ElementDefinitionNavigator nav, ElementDefiniti
var elem = elems[pos];
// [WMR 20160826] Never inherit Changed extension from base profile!
- elem.RemoveAllConstrainedByDiffExtensions();
+ elem.RemoveAllNonInheritableExtensions();
elem.RemoveAllConstrainedByDiffAnnotations();
// [WMR 20160902] Initialize empty ElementDefinition.Base components if necessary
@@ -1940,9 +1941,17 @@ private async Tasks.Task ensureSnapshot(StructureDefinition sd, string pro
try
{
- if (_settings.GenerateSnapshotForExternalProfiles
- && (!sd.HasSnapshot || (_settings.RegenerationBehaviour == RegenerationSettings.FORCE_REGENERATE && !sd.Snapshot.IsCreatedBySnapshotGenerator()))
- )
+ var shouldGenerate = _settings.RegenerationBehaviour switch
+ {
+ RegenerationSettings.TRY_USE_EXISTING => !sd.HasSnapshot,
+ RegenerationSettings.REGENERATE_ONCE => !sd.HasSnapshot || !sd.Snapshot.IsCreatedBySnapshotGenerator(),
+#pragma warning disable CS0618 // Type or member is obsolete
+ RegenerationSettings.FORCE_REGENERATE => true,
+#pragma warning restore CS0618 // Type or member is obsolete
+ _ => throw new InvalidOperationException($"Invalid RegenerationSettings value {_settings.RegenerationBehaviour}")
+ };
+
+ if (_settings.GenerateSnapshotForExternalProfiles && shouldGenerate)
{
// Automatically expand external profiles on demand
// Debug.Print($"[{nameof(SnapshotGenerator)}.{nameof(ensureSnapshot)}] Recursively generate snapshot for type profile with url: '{sd.Url}' ...");
@@ -2024,9 +2033,18 @@ private async Tasks.Task getSnapshotRootElement(StructureDefi
var cachedRoot = sd.GetSnapshotRootElementAnnotation();
if (cachedRoot != null) { return cachedRoot; }
#endif
-
+ var hasValidRoot = _settings.RegenerationBehaviour switch
+ {
+ RegenerationSettings.TRY_USE_EXISTING => sd.HasSnapshot,
+ RegenerationSettings.REGENERATE_ONCE => sd.HasSnapshot && sd.Snapshot.IsCreatedBySnapshotGenerator(),
+#pragma warning disable CS0618 // Type or member is obsolete
+ RegenerationSettings.FORCE_REGENERATE => false,
+#pragma warning restore CS0618 // Type or member is obsolete
+ _ => throw new InvalidOperationException($"Invalid RegenerationSettings value {_settings.RegenerationBehaviour}")
+ };
+
// 2. Return root element definition from existing (pre-generated) snapshot, if it exists
- if (sd.HasSnapshot && (sd.Snapshot.IsCreatedBySnapshotGenerator() || _settings.RegenerationBehaviour != RegenerationSettings.FORCE_REGENERATE))
+ if (hasValidRoot)
{
// Debug.Print($"[{nameof(SnapshotGenerator)}.{nameof(getSnapshotRootElement)}] {nameof(profileUri)} = '{profileUri}' - use existing root element definition from snapshot: #{sd.Snapshot.Element[0].GetHashCode()}");
// No need to save root ElemDef annotation, as the snapshot has already been fully expanded
diff --git a/src/Hl7.Fhir.STU3/Specification/Snapshot/SnapshotGeneratorExtensions.cs b/src/Hl7.Fhir.STU3/Specification/Snapshot/SnapshotGeneratorExtensions.cs
deleted file mode 100644
index 2c13de5f28..0000000000
--- a/src/Hl7.Fhir.STU3/Specification/Snapshot/SnapshotGeneratorExtensions.cs
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (c) 2017, Firely (info@fire.ly) and contributors
- * See the file CONTRIBUTORS for details.
- *
- * This file is licensed under the BSD 3-Clause license
- * available at https://raw.githubusercontent.com/FirelyTeam/firely-net-sdk/master/LICENSE
- */
-
-using Hl7.Fhir.Model;
-using Hl7.Fhir.Support;
-using Hl7.Fhir.Utility;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace Hl7.Fhir.Specification.Snapshot
-{
- // [WMR 20170209] cf. ConstrainedByDifferentialAnnotation
- // This extension indicates snapshot elements with associated differential constraints in the profile.
- // Note: extensions are persisted to XML/JSON, whereas annotations are ephemeral (in-memory only)
-
- /// Helper methods for the class to generate and inspect custom extensions.
- public static class SnapshotGeneratorExtensions
- {
- /// The canonical url of the extension definition that marks snapshot elements with associated differential constraints.
- // public static readonly string CHANGED_BY_DIFF_EXT = "http://hl7.org/fhir/StructureDefinition/changedByDifferential";
- public static readonly string CONSTRAINED_BY_DIFF_EXT = "http://hl7.org/fhir/StructureDefinition/constrainedByDifferentialExtension";
-
- ///
- /// Decorate the specified snapshot element definition with a special extension
- /// to indicate that the element is constrained by the differential.
- ///
- /// An instance.
- /// An optional boolean value (default true).
- /// Sets the extension to store the boolean flag.
- internal static void SetConstrainedByDiffExtension(this IExtendable element, bool value = true)
- {
- if (element == null) { throw Error.ArgumentNull(nameof(element)); }
- element.SetBoolExtension(CONSTRAINED_BY_DIFF_EXT, value);
- }
-
- /// Determines if the snapshot element was decorated with an extension indicating the element is constrained by the differential.
- /// An instance.
- /// A boolean value, or null.
- /// Gets the boolean flag from the extension, if it exists.
- public static bool? GetConstrainedByDiffExtension(this IExtendable element) => element.GetBoolExtension(CONSTRAINED_BY_DIFF_EXT);
-
- /// Removes the extension from the specified element definition.
- public static void RemoveConstrainedByDiffExtension(this IExtendable element)
- {
- if (element == null) { throw Error.ArgumentNull(nameof(element)); }
- element.RemoveExtension(CONSTRAINED_BY_DIFF_EXT);
- }
-
- /// Recursively removes all instances of the extension from the specified element definition and all it's child objects.
- public static void RemoveAllConstrainedByDiffExtensions(this Element element)
- {
- if (element == null) { throw Error.ArgumentNull(nameof(element)); }
- element.RemoveConstrainedByDiffExtension();
- foreach (var child in element.Children.OfType())
- {
- child.RemoveAllConstrainedByDiffExtensions();
- }
- }
-
- /// Recursively removes all instances of the extension from all the elements and their respective child objects.
- public static void RemoveAllConstrainedByDiffExtensions(this IEnumerable elements) where T : Element
- {
- if (elements == null) { throw Error.ArgumentNull(nameof(elements)); }
- foreach (var elem in elements)
- {
- elem.RemoveAllConstrainedByDiffExtensions();
- }
- }
-
- // ========== For internal use only ==========
- // [WMR 20170209] OBSOLETE
-#if false
-
- /// Removes a specific extension from the snapshot element definition and it's descendant elements, recursively.
- /// An instance.
- /// The canonical url of the extension.
- static void ClearAllExtensions(this ElementDefinition elemDef, string uri)
- {
- if (elemDef != null)
- {
- ClearExtensions(elemDef, uri);
- }
- }
-
- static void ClearExtensions(this IEnumerable elements, string uri) where T : Base
- {
- if (elements != null)
- {
- foreach (var child in elements)
- {
- ClearExtensions(child, uri);
- }
- }
- }
-
- static void ClearExtensions(this T element, string uri) where T : Base
- {
- if (element != null)
- {
- ClearExtension(element as IExtendable, uri);
- ClearExtensions(element.Children, uri);
- }
- }
-
- static void ClearExtension(this IExtendable extendable, string uri)
- {
- extendable?.RemoveExtension(uri);
- }
-#endif
-
- }
-}
diff --git a/src/Hl7.Fhir.Shared.Tests/Validation/SearchDataExtraction.cs b/src/Hl7.Fhir.Shared.Tests/Validation/SearchDataExtraction.cs
index 6e4f982a63..d2f0489612 100644
--- a/src/Hl7.Fhir.Shared.Tests/Validation/SearchDataExtraction.cs
+++ b/src/Hl7.Fhir.Shared.Tests/Validation/SearchDataExtraction.cs
@@ -131,7 +131,7 @@ private static void ExtractExamplesFromResource(Dictionary exampleS
try
{
// we perform the Select on a Poco, because then we get the FHIR dialect of FhirPath as well.
- results = resource.Select(index.Expression, new FhirEvaluationContext(resource.ToTypedElement()) { ElementResolver = mockResolver });
+ results = resource.Select(index.Expression!, new FhirEvaluationContext { ElementResolver = mockResolver });
}
catch (Exception)
{
diff --git a/src/Hl7.Fhir.Shims.Base/Specification/Snapshot/SnapshotGeneratorSettings.cs b/src/Hl7.Fhir.Shims.Base/Specification/Snapshot/SnapshotGeneratorSettings.cs
index f4490475af..09ca863da8 100644
--- a/src/Hl7.Fhir.Shims.Base/Specification/Snapshot/SnapshotGeneratorSettings.cs
+++ b/src/Hl7.Fhir.Shims.Base/Specification/Snapshot/SnapshotGeneratorSettings.cs
@@ -35,9 +35,7 @@ public void CopyTo(SnapshotGeneratorSettings other)
{
if (other == null) { throw Error.ArgumentNull(nameof(other)); }
other.GenerateSnapshotForExternalProfiles = GenerateSnapshotForExternalProfiles;
-#pragma warning disable CS0618 // Type or member is obsolete
- other.ForceRegenerateSnapshots = ForceRegenerateSnapshots;
-#pragma warning restore CS0618 // Type or member is obsolete
+ other.RegenerationBehaviour = RegenerationBehaviour;
other.GenerateExtensionsOnConstraints = GenerateExtensionsOnConstraints;
other.GenerateAnnotationsOnConstraints = GenerateAnnotationsOnConstraints;
other.GenerateElementIds = GenerateElementIds;
@@ -59,11 +57,11 @@ public void CopyTo(SnapshotGeneratorSettings other)
/// If disabled (default), then the snapshot generator relies on existing snapshot components, if they exist.
///
[Obsolete(
- "This setting does not work as intended. When set to true, it regenerates a snapshot every time (which is not useful), and when set to false, it still regenerates a snapshot once, even if it already exists. We will consider removing it in a future major release. Use the new RegenerationBehaviour setting instead. See also https://github.com/FirelyTeam/firely-net-sdk/pull/2803")]
+ "This setting does not work as intended. We will maintain the old behaviour for now, and we will consider removing it in a future major release. Use the new RegenerationBehaviour setting instead. See also https://github.com/FirelyTeam/firely-net-sdk/pull/2803")]
public bool ForceRegenerateSnapshots
{
- get { return this.RegenerationBehaviour == RegenerationSettings.FORCE_REGENERATE; }
- set { this.RegenerationBehaviour = value ? RegenerationSettings.FORCE_REGENERATE : RegenerationSettings.REGENERATE_ONCE; }
+ get { return this.RegenerationBehaviour == RegenerationSettings.REGENERATE_ONCE; }
+ set { this.RegenerationBehaviour = value ? RegenerationSettings.REGENERATE_ONCE : RegenerationSettings.TRY_USE_EXISTING; }
} // ForceExpandAll
///
@@ -115,6 +113,7 @@ public enum RegenerationSettings
///
/// Regenerate the snapshot every time. This is useful for debugging and testing purposes.
///
+ [Obsolete("Watch out when using this setting! it could lead to infinite recursion and is mainly meant for debugging and testing purposes. If you previously had ForceRegenerateSnapshots set to true, consider using REGENERATE_ONCE instead.")]
FORCE_REGENERATE,
}
}
diff --git a/src/Hl7.Fhir.Shims.Base/Specification/Source/SnapshotSource.cs b/src/Hl7.Fhir.Shims.Base/Specification/Source/SnapshotSource.cs
index 9ce593ae01..01b5a880c0 100644
--- a/src/Hl7.Fhir.Shims.Base/Specification/Source/SnapshotSource.cs
+++ b/src/Hl7.Fhir.Shims.Base/Specification/Source/SnapshotSource.cs
@@ -98,14 +98,17 @@ private async Tasks.Task ensureSnapshot(Resource res)
{
if (res is StructureDefinition sd)
{
- if (
- !sd.HasSnapshot ||
- Generator.Settings.RegenerationBehaviour == RegenerationSettings.FORCE_REGENERATE ||
- (
- !sd.Snapshot.IsCreatedBySnapshotGenerator() &&
- Generator.Settings.RegenerationBehaviour == RegenerationSettings.REGENERATE_ONCE
- )
- )
+ var shouldGenerate = Generator.Settings.RegenerationBehaviour switch
+ {
+ RegenerationSettings.TRY_USE_EXISTING => !sd.HasSnapshot,
+ RegenerationSettings.REGENERATE_ONCE => !sd.HasSnapshot || !sd.Snapshot.IsCreatedBySnapshotGenerator(),
+#pragma warning disable CS0618 // Type or member is obsolete
+ RegenerationSettings.FORCE_REGENERATE => true,
+#pragma warning restore CS0618 // Type or member is obsolete
+ _ => throw Error.NotSupported($"Unknown regeneration behaviour: {Generator.Settings.RegenerationBehaviour}")
+ };
+
+ if (shouldGenerate)
{
await Generator.UpdateAsync(sd).ConfigureAwait(false);
}
diff --git a/src/Hl7.Fhir.Specification.STU3.Tests/Snapshot/ElementDefinitionPropertyProxy.cs b/src/Hl7.Fhir.Specification.STU3.Tests/Snapshot/ElementDefinitionPropertyProxy.cs
index 2ade34391d..e8b3933e7f 100644
--- a/src/Hl7.Fhir.Specification.STU3.Tests/Snapshot/ElementDefinitionPropertyProxy.cs
+++ b/src/Hl7.Fhir.Specification.STU3.Tests/Snapshot/ElementDefinitionPropertyProxy.cs
@@ -12,14 +12,18 @@ namespace Hl7.Fhir.Specification.Tests
/// The property can also be a specific item from a property list.
/// The property name is specified in the constructor.
///
- /// The name is either the name of the property (e.g. "Binding") or the name of the property list
- /// with a item selector (e.g. "Constraint[Key:dom-2]").
+ /// The name can be
+ /// - the name of the property (e.g. "Binding")
+ /// - the name of the property list with an index (e.g. "Type[0]").
+ /// - the name of the property list with an item selector (e.g. "Constraint[Key:dom-2]").
///
internal class ElementDefinitionPropertyProxy
{
+ private bool _isList;
private string _propertyName;
- private string _selectorPropertyName;
- private string _selectorValue;
+ private string _listSelectorPropertyName;
+ private string _listSelectorValue;
+ private int? _listIndex;
private PropertyInfo _propertyInfo;
private PropertyInfo _selectorPropertyInfo;
@@ -38,7 +42,7 @@ public object CreateInstance(Element element)
{
var instance = Activator.CreateInstance(_propertyInfo.PropertyType);
- if (_selectorPropertyInfo == null)
+ if (!_isList)
return instance; // Primitive property
// Create item for property list
@@ -47,8 +51,8 @@ public object CreateInstance(Element element)
// Initialize with specified element
element?.CopyTo(item);
- // Set key value
- _selectorPropertyInfo.SetValue(item, _selectorValue);
+ if (_selectorPropertyInfo != null)
+ _selectorPropertyInfo.SetValue(item, _listSelectorValue); // Set key value
// Add item to property list
if (instance is IList items)
@@ -74,18 +78,29 @@ public void SetValue(object instance, object value)
/// The property value as an Element type.
public Element GetValueAsElement(object instance)
{
- if (_selectorPropertyInfo == null)
+ if (!_isList)
return (Element)_propertyInfo.GetValue(instance);
if (_propertyInfo.GetValue(instance, null) is not IList items)
return null;
- foreach (var item in items)
+ if (_selectorPropertyInfo != null)
{
- var value = _selectorPropertyInfo.GetValue(item)?.ToString();
+ foreach (var item in items)
+ {
+ var value = _selectorPropertyInfo.GetValue(item)?.ToString();
- if (_selectorValue.Equals(value))
- return (Element)item;
+ if (_listSelectorValue.Equals(value))
+ return (Element)item;
+ }
+
+ return null;
+ }
+
+ if (_listIndex.HasValue)
+ {
+ _listIndex.Value.Should().BeInRange(0, items.Count - 1);
+ return (Element)items[_listIndex.Value];
}
return null;
@@ -98,8 +113,9 @@ private void getPropertyInfo(string propertyName)
_propertyInfo = typeof(ElementDefinition).GetProperty(_propertyName);
_propertyInfo.Should().NotBeNull(); // Check property exists
- // ReSharper disable once PossibleNullReferenceException
- if (!isList(_propertyInfo.PropertyType))
+ _isList = isList(_propertyInfo.PropertyType);
+
+ if (!_isList)
{
_propertyInfo.PropertyType.IsAssignableTo(typeof(Element)).Should().BeTrue(); // Property type should be derived from Element
return;
@@ -107,7 +123,10 @@ private void getPropertyInfo(string propertyName)
_propertyInfo.PropertyType.GenericTypeArguments[0].IsAssignableTo(typeof(Element)).Should().BeTrue(); // Property type should be derived from Element
- _selectorPropertyInfo = _propertyInfo.PropertyType.GenericTypeArguments[0].GetProperty(_selectorPropertyName);
+ if (_listSelectorPropertyName == null)
+ return;
+
+ _selectorPropertyInfo = _propertyInfo.PropertyType.GenericTypeArguments[0].GetProperty(_listSelectorPropertyName);
_selectorPropertyInfo.Should().NotBeNull(); // Check property exists
}
@@ -115,17 +134,39 @@ private void parsePropertyName(string propertyName)
{
_propertyName = propertyName;
- var regex = new Regex("(.*)\\[(.*):(.*)\\]|(.*)");
+ if (!tryParseListKey(propertyName))
+ tryParseListIndex(propertyName);
+ }
+
+ private static bool isList(Type type) => typeof(IList).IsAssignableFrom(type);
+
+ private bool tryParseListKey(string propertyName)
+ {
+ var regex = new Regex("(.+)\\[(.+):(.+)\\]");
var result = regex.Match(propertyName);
- if (!result.Success || result.Groups[4].Success)
- return;
+ if (!result.Success)
+ return false;
_propertyName = result.Groups[1].Value;
- _selectorPropertyName = result.Groups[2].Value;
- _selectorValue = result.Groups[3].Value;
+ _listSelectorPropertyName = result.Groups[2].Value;
+ _listSelectorValue = result.Groups[3].Value;
+
+ return true;
}
- private static bool isList(Type type) => typeof(IList).IsAssignableFrom(type);
+ private bool tryParseListIndex(string propertyName)
+ {
+ var regex = new Regex("(.+)\\[(\\d+)\\]");
+ var result = regex.Match(propertyName);
+
+ if (!result.Success)
+ return false;
+
+ _propertyName = result.Groups[1].Value;
+ _listIndex = int.Parse(result.Groups[2].Value);
+
+ return true;
+ }
}
}
\ No newline at end of file
diff --git a/src/Hl7.Fhir.Specification.STU3.Tests/Snapshot/SnapshotGeneratorTest.cs b/src/Hl7.Fhir.Specification.STU3.Tests/Snapshot/SnapshotGeneratorTest.cs
index 04c280575f..13814b8cfd 100644
--- a/src/Hl7.Fhir.Specification.STU3.Tests/Snapshot/SnapshotGeneratorTest.cs
+++ b/src/Hl7.Fhir.Specification.STU3.Tests/Snapshot/SnapshotGeneratorTest.cs
@@ -21,8 +21,8 @@
using Hl7.Fhir.Support;
using Hl7.Fhir.Utility;
using Microsoft.VisualStudio.TestTools.UnitTesting;
-using System;
using NSubstitute;
+using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
@@ -49,7 +49,7 @@ public class SnapshotGeneratorTest2
{
// Throw on unresolved profile references; must include in TestData folder
GenerateSnapshotForExternalProfiles = true,
- ForceRegenerateSnapshots = true,
+ RegenerationBehaviour = RegenerationSettings.REGENERATE_ONCE,
GenerateExtensionsOnConstraints = false,
GenerateAnnotationsOnConstraints = false,
GenerateElementIds = true // STU3
@@ -2433,8 +2433,8 @@ private static bool isAlmostExactly(ElementDefinition elem, ElementDefinition ba
}
// Also ignore any Changed extensions on base and diff
- elemClone.RemoveAllConstrainedByDiffExtensions();
- baseClone.RemoveAllConstrainedByDiffExtensions();
+ elemClone.RemoveAllNonInheritableExtensions();
+ baseClone.RemoveAllNonInheritableExtensions();
elemClone.RemoveAllConstrainedByDiffAnnotations();
baseClone.RemoveAllConstrainedByDiffAnnotations();
@@ -7979,7 +7979,6 @@ public async Tasks.Task TestConstraintSource()
var element = snapshot.Should().Contain(e => e.Path == "Observation.subject").Subject;
var constraint = element.Constraint.Where(c => c.Key == "ref-1").FirstOrDefault();
constraint.Source.Should().Be("http://hl7.org/fhir/StructureDefinition/Reference");
-
}
@@ -8216,23 +8215,18 @@ public static IEnumerable