Skip to content
Merged
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
4 changes: 3 additions & 1 deletion src/Firely.Fhir.Validation/Impl/ExtensionContextValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,9 @@ private bool validateContext(PocoNode input, TypedContext context, ValidationSet

private static bool validateElementContext(string contextExpression, PocoNode instance, ValidationSettings vc)
{
if (contextExpression == "Element") return true;
// Base is the root of the FHIR type hierarchy (used by e.g. the _datatype extension), so like Element
// it matches anything
if (contextExpression is "Element" or "Base") return true;

// Element ids can be profile-qualified ([url]#[elementid]). We cannot verify conformance against
// the profile here, so we match on the element id part only
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using FluentAssertions;
using Hl7.Fhir.Model;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Linq;
using Assert = Microsoft.VisualStudio.TestTools.UnitTesting.Assert;

Expand Down Expand Up @@ -220,6 +221,48 @@ public void ExtensionContext_OnBackboneElement_MatchesAbstractType(string expres
result.IsSuccessful.Should().Be(expected);
}

// The _datatype extension from the FHIR extensions pack declares its context as {element, Base}. Base is the
// root of the FHIR type hierarchy, so the extension may appear on any element, including resources and the
// value of a cross-version extension (its main use).
// https://build.fhir.org/ig/HL7/fhir-extensions/StructureDefinition-datatype.html
[DataTestMethod]
[DataRow("")] // the resource itself
[DataRow("active")]
[DataRow("name")]
[DataRow("contact")]
[DataRow("extension.value")]
public void ExtensionContext_BaseContextOfDatatypeExtension_MatchesAnyElement(string path)
{
var crossVersionValue = new FhirString("9223372036854775807");
var patient = new Patient
{
ActiveElement = new FhirBoolean(true),
Name = [new HumanName { Family = "Doe" }],
Contact = [new Patient.ContactComponent { Gender = AdministrativeGender.Other }],
Extension = [new Extension("http://example.org/extensions/cross-version", crossVersionValue)]
};

IExtendable host = path switch
{
"" => patient,
"active" => patient.ActiveElement,
"name" => patient.Name[0],
"contact" => patient.Contact[0],
"extension.value" => crossVersionValue,
_ => throw new ArgumentOutOfRangeException(nameof(path))
};
host.AddExtension("http://hl7.org/fhir/StructureDefinition/_datatype", new FhirString("integer64"));

var ctxValidator = new ExtensionContextValidator([new(ExtensionContextValidator.ContextType.ELEMENT, "Base")], []);
var validator = new ChildrenValidator([("extension", ctxValidator)]) { AllowAdditionalChildren = true };
foreach (var name in path.Split('.', StringSplitOptions.RemoveEmptyEntries).Reverse())
validator = new ChildrenValidator([(name, validator)]) { AllowAdditionalChildren = true };

var result = validator.Validate(patient.ToPocoNode(), new ValidationSettings(), new ValidationState());

result.IsSuccessful.Should().BeTrue();
}

// Issues 540/481: Parameters.parameter.part is defined via contentReference to Parameters.parameter,
// so its TypeName is "Parameters.parameter". A context of "Parameters.parameter" must therefore match
// an extension placed on a .part element, even though the literal instance path is "parameter.part".
Expand Down
Loading