From ac5996fd84766179f89e25f803e7fadae417db0e Mon Sep 17 00:00:00 2001 From: Marco Visser Date: Tue, 12 Dec 2023 12:51:12 +0100 Subject: [PATCH 1/3] First try --- firely-validator-api-tests.props | 2 +- firely-validator-api.props | 2 +- .../Support/IScopedNode.cs | 33 +++++++++++ .../Support/IScopedNodeExtensions.cs | 46 +++++++++++++++ .../Support/ScopedNodeExtended.cs | 24 ++++++++ .../Support/ScopedNodeExtensions.cs | 58 ++++++++++++++++++- .../ScopedNodeToTypedElementAdapter.cs | 48 +++++++++++++++ .../ResourceSchemaValidationTests.cs | 2 +- 8 files changed, 211 insertions(+), 4 deletions(-) create mode 100644 src/Firely.Fhir.Validation/Support/IScopedNode.cs create mode 100644 src/Firely.Fhir.Validation/Support/IScopedNodeExtensions.cs create mode 100644 src/Firely.Fhir.Validation/Support/ScopedNodeExtended.cs create mode 100644 src/Firely.Fhir.Validation/Support/ScopedNodeToTypedElementAdapter.cs diff --git a/firely-validator-api-tests.props b/firely-validator-api-tests.props index 532db30b..3586eccb 100644 --- a/firely-validator-api-tests.props +++ b/firely-validator-api-tests.props @@ -10,7 +10,7 @@ - 5.4.1-20231211.2 + 5.4.1-20231212.1232-mv 5.1.0 diff --git a/firely-validator-api.props b/firely-validator-api.props index d503347c..9e7aa8aa 100644 --- a/firely-validator-api.props +++ b/firely-validator-api.props @@ -19,7 +19,7 @@ - 5.4.1-20231211.2 + 5.4.1-20231212.1232-mv diff --git a/src/Firely.Fhir.Validation/Support/IScopedNode.cs b/src/Firely.Fhir.Validation/Support/IScopedNode.cs new file mode 100644 index 00000000..82e1cb83 --- /dev/null +++ b/src/Firely.Fhir.Validation/Support/IScopedNode.cs @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023, 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 + */ + +#nullable enable + +using Hl7.Fhir.ElementModel; + +namespace Firely.Fhir.Validation +{ + /// + /// An element within a tree of typed FHIR data with also a parent element. + /// + /// + /// This interface represents FHIR data as a tree of elements, including type information either present in + /// the instance or derived from fully aware of the FHIR definitions and types + /// +#pragma warning disable CS0618 // Type or member is obsolete + internal interface IScopedNode : IBaseElementNavigator +#pragma warning restore CS0618 // Type or member is obsolete + { + /// + /// The parent node of this node, or null if this is the root node. + /// + IScopedNode? Parent { get; } + } +} + +#nullable restore \ No newline at end of file diff --git a/src/Firely.Fhir.Validation/Support/IScopedNodeExtensions.cs b/src/Firely.Fhir.Validation/Support/IScopedNodeExtensions.cs new file mode 100644 index 00000000..942bd840 --- /dev/null +++ b/src/Firely.Fhir.Validation/Support/IScopedNodeExtensions.cs @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023, 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 + */ + +#nullable enable + + +using Hl7.Fhir.ElementModel; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Firely.Fhir.Validation +{ + internal static class IScopedNodeExtensions + { + /// + /// Converts a to a . + /// + /// An node + /// An implementation of + /// Be careful when using this method, the returned does not implement + /// the methods and . + /// + [Obsolete("WARNING! For internal API use only. Turning an IScopedNode into an ITypedElement will cause problems for" + + "Location and Definitions. Those properties are not implemented using this method and can cause problems " + + "elsewhere. Please don't use this method unless you know what you are doing.")] + public static ITypedElement AsTypedElement(this IScopedNode node) => + node is ITypedElement ite ? ite : new ScopedNodeToTypedElementAdapter(node); + + /// + /// Returns the parent resource of this node, or null if this node is not part of a resource. + /// + /// + /// + /// + public static IEnumerable Children(this IEnumerable nodes, string? name = null) => + nodes.SelectMany(n => n.Children(name)); + } +} + +#nullable restore \ No newline at end of file diff --git a/src/Firely.Fhir.Validation/Support/ScopedNodeExtended.cs b/src/Firely.Fhir.Validation/Support/ScopedNodeExtended.cs new file mode 100644 index 00000000..75d28834 --- /dev/null +++ b/src/Firely.Fhir.Validation/Support/ScopedNodeExtended.cs @@ -0,0 +1,24 @@ +using Hl7.Fhir.ElementModel; +using System.Collections.Generic; + +namespace Firely.Fhir.Validation.Support +{ + internal class ScopedNodeExtended : ScopedNode, IScopedNode + { + private readonly ScopedNodeExtended? _parent; + + public ScopedNodeExtended(ITypedElement wrapped, string? instanceUri = null) : base(wrapped, instanceUri) + { + } + + protected ScopedNodeExtended(ScopedNodeExtended parentNode, ScopedNode? parentResource, ITypedElement wrapped, string? fullUrl) : base(parentNode, parentResource, wrapped, fullUrl) + { + _parent = parentNode; + } + + IScopedNode? IScopedNode.Parent => _parent; + + IEnumerable IBaseElementNavigator.Children(string? name) => + childrenInternal(name); + } +} diff --git a/src/Firely.Fhir.Validation/Support/ScopedNodeExtensions.cs b/src/Firely.Fhir.Validation/Support/ScopedNodeExtensions.cs index c4a578bb..939e3c21 100644 --- a/src/Firely.Fhir.Validation/Support/ScopedNodeExtensions.cs +++ b/src/Firely.Fhir.Validation/Support/ScopedNodeExtensions.cs @@ -1,4 +1,5 @@ -using Hl7.Fhir.ElementModel; +using Firely.Fhir.Validation.Support; +using Hl7.Fhir.ElementModel; using Hl7.Fhir.Introspection; using Hl7.Fhir.Model; using Hl7.Fhir.Specification; @@ -14,6 +15,14 @@ namespace Firely.Fhir.Validation /// internal static class ScopedNodeExtensions { + + /// + /// Convert a to a . + /// + /// An + /// + public static IScopedNode AsScopedNode(this ITypedElement node) => node is ScopedNodeExtended sne ? sne : new ScopedNodeExtended(node); + /// /// /// @@ -25,6 +34,53 @@ public static IScopedNode ToScopedNode(this IReadOnlyDictionary inspector ??= ModelInspector.ForAssembly(node.GetType().Assembly); return new ScopedNodeOnDictionary(inspector, node.GetType().Name, node); } + + internal static Quantity ParseQuantity(this IScopedNode instance) +#pragma warning disable CS0618 // Type or member is obsolete + => instance.ParseQuantityInternal(); +#pragma warning restore CS0618 // Type or member is obsolete + + internal static T ParsePrimitive(this IScopedNode instance) where T : PrimitiveType, new() +#pragma warning disable CS0618 // Type or member is obsolete + => instance.ParsePrimitiveInternal(); +#pragma warning restore CS0618 // Type or member is obsolete + + internal static Coding ParseCoding(this IScopedNode instance) +#pragma warning disable CS0618 // Type or member is obsolete + => instance.ParseCodingInternal(); +#pragma warning restore CS0618 // Type or member is obsolete + + internal static ResourceReference ParseResourceReference(this IScopedNode instance) +#pragma warning disable CS0618 // Type or member is obsolete + => instance.ParseResourceReferenceInternal(); +#pragma warning restore CS0618 // Type or member is obsolete + + internal static CodeableConcept ParseCodeableConcept(this IScopedNode instance) +#pragma warning disable CS0618 // Type or member is obsolete + => instance.ParseCodeableConceptInternal(); +#pragma warning restore CS0618 // Type or member is obsolete + + /// + /// Parses a bindeable type (code, Coding, CodeableConcept, Quantity, string, uri) into a FHIR coded datatype. + /// Extensions will be parsed from the 'value' of the (simple) extension. + /// + /// + /// An Element of a coded type (code, Coding or CodeableConcept) dependin on the instance type, + /// or null if no bindable instance data was found + /// The instance type is mapped to a codable type as follows: + /// 'code' => code + /// 'Coding' => Coding + /// 'CodeableConcept' => CodeableConcept + /// 'Quantity' => Coding + /// 'Extension' => depends on value[x] + /// 'string' => code + /// 'uri' => code + /// + internal static Element ParseBindable(this IScopedNode instance) +#pragma warning disable CS0618 // Type or member is obsolete + => instance.ParseBindableInternal(); +#pragma warning restore CS0618 // Type or member is obsolete + } internal class ScopedNodeOnDictionary : IScopedNode diff --git a/src/Firely.Fhir.Validation/Support/ScopedNodeToTypedElementAdapter.cs b/src/Firely.Fhir.Validation/Support/ScopedNodeToTypedElementAdapter.cs new file mode 100644 index 00000000..08dccf17 --- /dev/null +++ b/src/Firely.Fhir.Validation/Support/ScopedNodeToTypedElementAdapter.cs @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2023, 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 + */ + +#nullable enable + +using Hl7.Fhir.ElementModel; +using Hl7.Fhir.Specification; +using System.Collections.Generic; +using System.Linq; + +namespace Firely.Fhir.Validation +{ + /// + /// An adapter from to . + /// + /// Be careful, this adapter does not implement the and + /// property. + /// + internal class ScopedNodeToTypedElementAdapter : ITypedElement + { + private readonly IScopedNode _adaptee; + + public ScopedNodeToTypedElementAdapter(IScopedNode adaptee) + { + _adaptee = adaptee; + } + + public string Location => throw new System.NotImplementedException(); + + public IElementDefinitionSummary Definition => throw new System.NotImplementedException(); + + public string Name => _adaptee.Name; + + public string InstanceType => _adaptee.InstanceType; + + public object Value => _adaptee.Value; + + public IEnumerable Children(string? name = null) => + _adaptee.Children(name).Select(n => new ScopedNodeToTypedElementAdapter(n)); + } +} + +#nullable restore \ No newline at end of file diff --git a/test/Firely.Fhir.Validation.Compilation.Tests.Shared/ResourceSchemaValidationTests.cs b/test/Firely.Fhir.Validation.Compilation.Tests.Shared/ResourceSchemaValidationTests.cs index b460e3dc..f38aebdf 100644 --- a/test/Firely.Fhir.Validation.Compilation.Tests.Shared/ResourceSchemaValidationTests.cs +++ b/test/Firely.Fhir.Validation.Compilation.Tests.Shared/ResourceSchemaValidationTests.cs @@ -87,7 +87,7 @@ public void AvoidsRedoingProfileValidation() vc.ResolveExternalReference = resolveTestData; var validationState = new ValidationState(); - var result = schemaElement!.Validate(new ScopedNode(all.ToTypedElement()), vc, validationState); + var result = schemaElement!.Validate(new ScopedNode(all.ToTypedElement()).AsScopedNode(), vc, validationState); result.Result.Should().Be(ValidationResult.Failure); var issues = result.Evidence.OfType().ToList(); issues.Count.Should().Be(1); // Bundle.entry[2].resource[0] is validated twice against different profiles. From bafae0711d88191917b71bc524a5075dd1c22931 Mon Sep 17 00:00:00 2001 From: Marco Visser Date: Tue, 12 Dec 2023 16:13:26 +0100 Subject: [PATCH 2/3] Moved IScopedNode from firely-net-sdk to here. --- firely-validator-api-tests.props | 2 +- firely-validator-api.props | 2 +- .../Impl/FhirPathValidator.cs | 12 +++------ .../Impl/ReferencedInstanceValidator.cs | 5 +--- .../Schema/ValueElementNode.cs | 3 --- .../Support/IScopedNode.cs | 5 +++- .../Support/IScopedNodeExtensions.cs | 15 +++++++++-- .../Support/ScopedNodeExtended.cs | 24 ----------------- .../Support/ScopedNodeExtensions.cs | 6 ++--- .../TypedElementToIScopedNodeToAdapter.cs | 27 +++++++++++++++++++ .../Impl/ReferencedInstanceValidatorTests.cs | 2 +- 11 files changed, 55 insertions(+), 48 deletions(-) delete mode 100644 src/Firely.Fhir.Validation/Support/ScopedNodeExtended.cs create mode 100644 src/Firely.Fhir.Validation/Support/TypedElementToIScopedNodeToAdapter.cs diff --git a/firely-validator-api-tests.props b/firely-validator-api-tests.props index 3586eccb..645d2df6 100644 --- a/firely-validator-api-tests.props +++ b/firely-validator-api-tests.props @@ -10,7 +10,7 @@ - 5.4.1-20231212.1232-mv + 5.4.1-20231212.3 5.1.0 diff --git a/firely-validator-api.props b/firely-validator-api.props index 9e7aa8aa..4b960aec 100644 --- a/firely-validator-api.props +++ b/firely-validator-api.props @@ -19,7 +19,7 @@ - 5.4.1-20231212.1232-mv + 5.4.1-20231212.3 diff --git a/src/Firely.Fhir.Validation/Impl/FhirPathValidator.cs b/src/Firely.Fhir.Validation/Impl/FhirPathValidator.cs index 25742747..713f107d 100644 --- a/src/Firely.Fhir.Validation/Impl/FhirPathValidator.cs +++ b/src/Firely.Fhir.Validation/Impl/FhirPathValidator.cs @@ -100,14 +100,12 @@ protected override (bool, ResultReport?) RunInvariant(IScopedNode input, Validat { try { -#pragma warning disable CS0618 // Type or member is obsolete - var node = input as ScopedNode ?? new ScopedNode(input.AsTypedElement()); -#pragma warning restore CS0618 // Type or member is obsolete + ScopedNode node = input.ToScopedNode(); var context = new FhirEvaluationContext(node.ResourceContext) { TerminologyService = new ValidateCodeServiceToTerminologyServiceAdapter(vc.ValidateCodeService) }; - return (predicate(input, context, vc), null); + return (predicate(node, context, vc), null); } catch (Exception e) { @@ -153,14 +151,12 @@ private CompiledExpression getDefaultCompiledExpression(FhirPathCompiler compile } } - private bool predicate(IScopedNode input, EvaluationContext context, ValidationContext vc) + private bool predicate(ScopedNode input, EvaluationContext context, ValidationContext vc) { var compiler = vc?.FhirPathCompiler ?? DefaultCompiler; var compiledExpression = getDefaultCompiledExpression(compiler); -#pragma warning disable CS0618 // Type or member is obsolete - return compiledExpression.IsTrue(input.AsTypedElement(), context); -#pragma warning restore CS0618 // Type or member is obsolete + return compiledExpression.IsTrue(input, context); } /// diff --git a/src/Firely.Fhir.Validation/Impl/ReferencedInstanceValidator.cs b/src/Firely.Fhir.Validation/Impl/ReferencedInstanceValidator.cs index 6cf9bc99..6aed5833 100644 --- a/src/Firely.Fhir.Validation/Impl/ReferencedInstanceValidator.cs +++ b/src/Firely.Fhir.Validation/Impl/ReferencedInstanceValidator.cs @@ -115,11 +115,8 @@ private record ResolutionResult(ITypedElement? ReferencedResource, AggregationMo ResolutionResult resolution = new(null, null, null); List evidence = new(); - if (input is not ScopedNode instance) - throw new InvalidOperationException($"Cannot validate because input is not of type {nameof(ScopedNode)}."); - // First, try to resolve within this instance (in contained, Bundle.entry) - evidence.Add(resolveLocally(instance, reference, s, out resolution)); + evidence.Add(resolveLocally(input.ToScopedNode(), reference, s, out resolution)); // Now that we have tried to fetch the reference locally, we have also determined the kind of // reference we are dealing with, so check it for aggregation and versioning rules. diff --git a/src/Firely.Fhir.Validation/Schema/ValueElementNode.cs b/src/Firely.Fhir.Validation/Schema/ValueElementNode.cs index 1e056d67..cda1b951 100644 --- a/src/Firely.Fhir.Validation/Schema/ValueElementNode.cs +++ b/src/Firely.Fhir.Validation/Schema/ValueElementNode.cs @@ -4,7 +4,6 @@ * via any medium is strictly prohibited. */ -using Hl7.Fhir.ElementModel; using Hl7.Fhir.Language; using System.Collections.Generic; using System.Linq; @@ -20,8 +19,6 @@ public ValueElementNode(IScopedNode wrapped) _wrapped = wrapped; } - public IScopedNode? Parent => _wrapped.Parent; - public string Name => "value"; public string InstanceType => TypeSpecifier.ForNativeType(_wrapped.Value.GetType()).FullName; diff --git a/src/Firely.Fhir.Validation/Support/IScopedNode.cs b/src/Firely.Fhir.Validation/Support/IScopedNode.cs index 82e1cb83..c53512bb 100644 --- a/src/Firely.Fhir.Validation/Support/IScopedNode.cs +++ b/src/Firely.Fhir.Validation/Support/IScopedNode.cs @@ -23,10 +23,13 @@ namespace Firely.Fhir.Validation internal interface IScopedNode : IBaseElementNavigator #pragma warning restore CS0618 // Type or member is obsolete { + /* + * /// /// The parent node of this node, or null if this is the root node. /// - IScopedNode? Parent { get; } + IScopedNode? Parent { get; } // We don't need this probably. + */ } } diff --git a/src/Firely.Fhir.Validation/Support/IScopedNodeExtensions.cs b/src/Firely.Fhir.Validation/Support/IScopedNodeExtensions.cs index 942bd840..b610368e 100644 --- a/src/Firely.Fhir.Validation/Support/IScopedNodeExtensions.cs +++ b/src/Firely.Fhir.Validation/Support/IScopedNodeExtensions.cs @@ -29,8 +29,19 @@ internal static class IScopedNodeExtensions [Obsolete("WARNING! For internal API use only. Turning an IScopedNode into an ITypedElement will cause problems for" + "Location and Definitions. Those properties are not implemented using this method and can cause problems " + "elsewhere. Please don't use this method unless you know what you are doing.")] - public static ITypedElement AsTypedElement(this IScopedNode node) => - node is ITypedElement ite ? ite : new ScopedNodeToTypedElementAdapter(node); + public static ITypedElement AsTypedElement(this IScopedNode node) => node switch + { + TypedElementToIScopedNodeToAdapter adapter => adapter.ScopedNode, + ITypedElement ite => ite, + _ => new ScopedNodeToTypedElementAdapter(node) + }; + //node is ITypedElement ite ? ite : new ScopedNodeToTypedElementAdapter(node); + + public static ScopedNode ToScopedNode(this IScopedNode node) => node switch + { + TypedElementToIScopedNodeToAdapter adapter => adapter.ScopedNode, + _ => throw new ArgumentException("The node is not a TypedElementToIScopedNodeToAdapter") + }; /// /// Returns the parent resource of this node, or null if this node is not part of a resource. diff --git a/src/Firely.Fhir.Validation/Support/ScopedNodeExtended.cs b/src/Firely.Fhir.Validation/Support/ScopedNodeExtended.cs deleted file mode 100644 index 75d28834..00000000 --- a/src/Firely.Fhir.Validation/Support/ScopedNodeExtended.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Hl7.Fhir.ElementModel; -using System.Collections.Generic; - -namespace Firely.Fhir.Validation.Support -{ - internal class ScopedNodeExtended : ScopedNode, IScopedNode - { - private readonly ScopedNodeExtended? _parent; - - public ScopedNodeExtended(ITypedElement wrapped, string? instanceUri = null) : base(wrapped, instanceUri) - { - } - - protected ScopedNodeExtended(ScopedNodeExtended parentNode, ScopedNode? parentResource, ITypedElement wrapped, string? fullUrl) : base(parentNode, parentResource, wrapped, fullUrl) - { - _parent = parentNode; - } - - IScopedNode? IScopedNode.Parent => _parent; - - IEnumerable IBaseElementNavigator.Children(string? name) => - childrenInternal(name); - } -} diff --git a/src/Firely.Fhir.Validation/Support/ScopedNodeExtensions.cs b/src/Firely.Fhir.Validation/Support/ScopedNodeExtensions.cs index 939e3c21..dfc767c6 100644 --- a/src/Firely.Fhir.Validation/Support/ScopedNodeExtensions.cs +++ b/src/Firely.Fhir.Validation/Support/ScopedNodeExtensions.cs @@ -1,5 +1,4 @@ -using Firely.Fhir.Validation.Support; -using Hl7.Fhir.ElementModel; +using Hl7.Fhir.ElementModel; using Hl7.Fhir.Introspection; using Hl7.Fhir.Model; using Hl7.Fhir.Specification; @@ -21,7 +20,8 @@ internal static class ScopedNodeExtensions /// /// An /// - public static IScopedNode AsScopedNode(this ITypedElement node) => node is ScopedNodeExtended sne ? sne : new ScopedNodeExtended(node); + public static IScopedNode AsScopedNode(this ITypedElement node) + => new TypedElementToIScopedNodeToAdapter(node.ToScopedNode()); /// /// diff --git a/src/Firely.Fhir.Validation/Support/TypedElementToIScopedNodeToAdapter.cs b/src/Firely.Fhir.Validation/Support/TypedElementToIScopedNodeToAdapter.cs new file mode 100644 index 00000000..b855ce63 --- /dev/null +++ b/src/Firely.Fhir.Validation/Support/TypedElementToIScopedNodeToAdapter.cs @@ -0,0 +1,27 @@ +using Hl7.Fhir.ElementModel; +using System.Collections.Generic; +using System.Linq; + +namespace Firely.Fhir.Validation +{ + internal class TypedElementToIScopedNodeToAdapter : IScopedNode + { + private readonly ScopedNode _adaptee; + + public TypedElementToIScopedNodeToAdapter(ScopedNode adaptee) + { + _adaptee = adaptee; + } + + public ScopedNode ScopedNode => _adaptee; + + public string Name => _adaptee.Name; + + public string InstanceType => _adaptee.InstanceType; + + public object Value => _adaptee.Value; + + IEnumerable IBaseElementNavigator.Children(string? name) => + _adaptee.Children(name).Cast().Select(n => new TypedElementToIScopedNodeToAdapter(n)); + } +} diff --git a/test/Firely.Fhir.Validation.Tests/Impl/ReferencedInstanceValidatorTests.cs b/test/Firely.Fhir.Validation.Tests/Impl/ReferencedInstanceValidatorTests.cs index 1a3a1df8..63c48120 100644 --- a/test/Firely.Fhir.Validation.Tests/Impl/ReferencedInstanceValidatorTests.cs +++ b/test/Firely.Fhir.Validation.Tests/Impl/ReferencedInstanceValidatorTests.cs @@ -101,7 +101,7 @@ public void ValidateInstance(object instance, object testeeo, bool success, stri static ResultReport test(object instance, IAssertion testee, ValidationContext vc) { - var te = new ScopedNode(instance.ToTypedElement()); + var te = instance.ToTypedElement().AsScopedNode(); var asserter = te.Children("entry").First().Children("resource").Children("asserter").Single(); return testee.Validate(asserter, vc); } From 10ac1c85d37f632b3ce3309a6e7a48a7c3e0cb3a Mon Sep 17 00:00:00 2001 From: Marco Visser Date: Wed, 13 Dec 2023 13:31:47 +0100 Subject: [PATCH 3/3] After review EK: avoid casting at Children() function, but do it at poperty ScopedNode. This is better for the performance. --- .../Support/TypedElementToIScopedNodeToAdapter.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Firely.Fhir.Validation/Support/TypedElementToIScopedNodeToAdapter.cs b/src/Firely.Fhir.Validation/Support/TypedElementToIScopedNodeToAdapter.cs index b855ce63..f2502f84 100644 --- a/src/Firely.Fhir.Validation/Support/TypedElementToIScopedNodeToAdapter.cs +++ b/src/Firely.Fhir.Validation/Support/TypedElementToIScopedNodeToAdapter.cs @@ -6,14 +6,18 @@ namespace Firely.Fhir.Validation { internal class TypedElementToIScopedNodeToAdapter : IScopedNode { - private readonly ScopedNode _adaptee; + private readonly ITypedElement _adaptee; - public TypedElementToIScopedNodeToAdapter(ScopedNode adaptee) + public TypedElementToIScopedNodeToAdapter(ScopedNode adaptee) : this(adaptee as ITypedElement) + { + } + + private TypedElementToIScopedNodeToAdapter(ITypedElement adaptee) { _adaptee = adaptee; } - public ScopedNode ScopedNode => _adaptee; + public ScopedNode ScopedNode => (ScopedNode)_adaptee; // we know that this is always a ScopedNode public string Name => _adaptee.Name; @@ -22,6 +26,6 @@ public TypedElementToIScopedNodeToAdapter(ScopedNode adaptee) public object Value => _adaptee.Value; IEnumerable IBaseElementNavigator.Children(string? name) => - _adaptee.Children(name).Cast().Select(n => new TypedElementToIScopedNodeToAdapter(n)); + _adaptee.Children(name).Select(n => new TypedElementToIScopedNodeToAdapter(n)); } }