diff --git a/src/Hl7.Fhir.Base/CompatibilitySuppressions.xml b/src/Hl7.Fhir.Base/CompatibilitySuppressions.xml
index f79ce1c7ea..beb25c62eb 100644
--- a/src/Hl7.Fhir.Base/CompatibilitySuppressions.xml
+++ b/src/Hl7.Fhir.Base/CompatibilitySuppressions.xml
@@ -185,49 +185,91 @@
CP0002
- M:Hl7.Fhir.Serialization.IFhirSerializationEngine.SerializeToXml(Hl7.Fhir.Model.Resource)
+ M:Hl7.Fhir.Serialization.BaseFhirJsonPocoSerializer.Serialize(System.Collections.Generic.IReadOnlyDictionary{System.String,System.Object},System.Text.Json.Utf8JsonWriter)
lib/net8.0/Hl7.Fhir.Base.dll
lib/net8.0/Hl7.Fhir.Base.dll
true
CP0002
- M:Hl7.Fhir.Serialization.SerializationEngineExtensions.SerializeReaderToXml(Hl7.Fhir.Serialization.IFhirSerializationEngine,System.Xml.XmlReader)
+ M:Hl7.Fhir.Serialization.BaseFhirJsonPocoSerializer.SerializeToString(System.Collections.Generic.IReadOnlyDictionary{System.String,System.Object})
lib/net8.0/Hl7.Fhir.Base.dll
lib/net8.0/Hl7.Fhir.Base.dll
true
CP0002
- M:Hl7.Fhir.Serialization.SerializationEngineExtensions.SerializeToXmlWriter(Hl7.Fhir.Serialization.IFhirSerializationEngine,Hl7.Fhir.Model.Resource,System.Xml.XmlWriter)
+ M:Hl7.Fhir.Serialization.BaseFhirXmlPocoSerializer.Serialize(System.Collections.Generic.IReadOnlyDictionary{System.String,System.Object},System.Xml.XmlWriter,Hl7.Fhir.Serialization.SerializationFilter)
lib/net8.0/Hl7.Fhir.Base.dll
lib/net8.0/Hl7.Fhir.Base.dll
true
CP0002
- M:Hl7.Fhir.Utility.ReflectionHelper.IsTypedCollection(System.Type)
+ M:Hl7.Fhir.Serialization.BaseFhirXmlPocoSerializer.SerializeToString(System.Collections.Generic.IReadOnlyDictionary{System.String,System.Object},Hl7.Fhir.Serialization.SerializationFilter)
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)
+ M:Hl7.Fhir.Serialization.FhirJsonConverter`1.#ctor(Hl7.Fhir.Introspection.ModelInspector)
lib/net8.0/Hl7.Fhir.Base.dll
lib/net8.0/Hl7.Fhir.Base.dll
true
- CP0006
- M:Hl7.Fhir.ElementModel.ITypedElement.Children(System.String)
+ CP0002
+ M:Hl7.Fhir.Serialization.FhirJsonConverter`1.#ctor(Hl7.Fhir.Serialization.BaseFhirJsonPocoDeserializer,Hl7.Fhir.Serialization.BaseFhirJsonPocoSerializer)
+ lib/net8.0/Hl7.Fhir.Base.dll
+ lib/net8.0/Hl7.Fhir.Base.dll
+ true
+
+
+ CP0002
+ M:Hl7.Fhir.Serialization.FhirJsonConverter`1.#ctor(System.Reflection.Assembly,Hl7.Fhir.Serialization.FhirJsonPocoSerializerSettings,Hl7.Fhir.Serialization.FhirJsonPocoDeserializerSettings,System.Predicate{Hl7.Fhir.Utility.CodedException})
+ lib/net8.0/Hl7.Fhir.Base.dll
+ lib/net8.0/Hl7.Fhir.Base.dll
+ true
+
+
+ CP0002
+ M:Hl7.Fhir.Serialization.FhirJsonConverter`1.#ctor(System.Reflection.Assembly)
+ lib/net8.0/Hl7.Fhir.Base.dll
+ lib/net8.0/Hl7.Fhir.Base.dll
+ true
+
+
+ CP0002
+ M:Hl7.Fhir.Serialization.SerializationEngineExtensions.SerializeReaderToJson(Hl7.Fhir.Serialization.IFhirSerializationEngine,System.Text.Json.Utf8JsonReader@)
+ lib/net8.0/Hl7.Fhir.Base.dll
+ lib/net8.0/Hl7.Fhir.Base.dll
+ true
+
+
+ CP0002
+ M:Hl7.Fhir.Serialization.SerializationEngineExtensions.SerializeReaderToXml(Hl7.Fhir.Serialization.IFhirSerializationEngine,System.Xml.XmlReader)
+ 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.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
CP0006
- M:Hl7.Fhir.Serialization.IFhirSerializationEngine.SerializeToXml(Hl7.Fhir.Model.Base)
+ M:Hl7.Fhir.ElementModel.ITypedElement.Children(System.String)
lib/net8.0/Hl7.Fhir.Base.dll
lib/net8.0/Hl7.Fhir.Base.dll
true
@@ -288,6 +330,13 @@
lib/net8.0/Hl7.Fhir.Base.dll
true
+
+ CP0009
+ T:Hl7.Fhir.Serialization.FhirJsonConverter`1
+ lib/net8.0/Hl7.Fhir.Base.dll
+ lib/net8.0/Hl7.Fhir.Base.dll
+ true
+
PKV006
.NETStandard,Version=v2.0
diff --git a/src/Hl7.Fhir.Base/Model/Base.Dictionary.cs b/src/Hl7.Fhir.Base/Model/Base.Dictionary.cs
index 50703025f5..5c55ebe274 100644
--- a/src/Hl7.Fhir.Base/Model/Base.Dictionary.cs
+++ b/src/Hl7.Fhir.Base/Model/Base.Dictionary.cs
@@ -3,6 +3,8 @@
using System.Collections.Generic;
using System.Linq;
+#nullable enable
+
namespace Hl7.Fhir.Model;
public abstract partial class Base: IReadOnlyDictionary, IDictionary
diff --git a/src/Hl7.Fhir.Base/Serialization/BaseFhirJsonPocoSerializer.cs b/src/Hl7.Fhir.Base/Serialization/BaseFhirJsonPocoSerializer.cs
index cdbd553228..caedb9f664 100644
--- a/src/Hl7.Fhir.Base/Serialization/BaseFhirJsonPocoSerializer.cs
+++ b/src/Hl7.Fhir.Base/Serialization/BaseFhirJsonPocoSerializer.cs
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (c) 2021, Firely (info@fire.ly) and contributors
* See the file CONTRIBUTORS for details.
*
@@ -20,314 +20,310 @@
using System.Text;
using System.Text.Json;
-namespace Hl7.Fhir.Serialization
+namespace Hl7.Fhir.Serialization;
+
+///
+/// Serializes the contents of an IReadOnlyDictionary[string,object] according to the rules of FHIR Json serialization.
+///
+/// The serializer uses the format documented in https://www.hl7.org/fhir/json.html. Since all POCOs included
+/// in the SDK implement IReadOnlyDictionary, these methods can be used to serialize POCOs to Json.
+///
+public class BaseFhirJsonPocoSerializer
{
///
- /// Serializes the contents of an IReadOnlyDictionary[string,object] according to the rules of FHIR Json serialization.
+ /// Construct a new serializer for a specific release of FHIR.
///
- /// The serializer uses the format documented in https://www.hl7.org/fhir/json.html. Since all POCOs included
- /// in the SDK implement IReadOnlyDictionary, these methods can be used to serialize POCOs to Json.
- ///
- public class BaseFhirJsonPocoSerializer
+ public BaseFhirJsonPocoSerializer(FhirRelease release) : this(release, new())
{
- ///
- /// Construct a new serializer for a specific release of FHIR.
- ///
- public BaseFhirJsonPocoSerializer(FhirRelease release) : this(release, new())
- {
- // nothing
- }
+ // nothing
+ }
- ///
- /// Construct a new serializer for a specific release of FHIR.
- ///
- public BaseFhirJsonPocoSerializer(FhirRelease release, FhirJsonPocoSerializerSettings settings)
- {
- Release = release;
- Settings = settings;
- }
+ ///
+ /// Construct a new serializer for a specific release of FHIR.
+ ///
+ public BaseFhirJsonPocoSerializer(FhirRelease release, FhirJsonPocoSerializerSettings settings)
+ {
+ Release = release;
+ Settings = settings;
+ }
- ///
- /// The release of FHIR for which this serializer is configured.
- ///
- public FhirRelease Release { get; }
-
- ///
- /// The settings that were passed to the constructor.
- ///
- public FhirJsonPocoSerializerSettings Settings { get; }
-
- ///
- /// Serializes the given dictionary with FHIR data into Json.
- ///
- public void Serialize(IReadOnlyDictionary members, Utf8JsonWriter writer) =>
- serializeInternal(members, writer, skipValue: false);
-
- ///
- /// Serializes the given dictionary with FHIR data into a Json string.
- ///
- public string SerializeToString(IReadOnlyDictionary members)
- {
- var stream = new MemoryStream();
- var writer = new Utf8JsonWriter(stream);
- serializeInternal(members, writer, skipValue: false);
- writer.Flush();
- return Encoding.UTF8.GetString(stream.ToArray());
- }
+ ///
+ /// The release of FHIR for which this serializer is configured.
+ ///
+ public FhirRelease Release { get; }
- ///
- /// Serializes the given dictionary with FHIR data into Json, optionally skipping the "value" element.
- ///
- /// Not serializing the "value" element is useful when serializing FHIR primitives into two properties, one
- /// with just the value, and one with the id/extensions.
- private void serializeInternal(
- IReadOnlyDictionary members,
- Utf8JsonWriter writer,
- bool skipValue)
- {
- writer.WriteStartObject();
- var filter = Settings.SummaryFilter;
+ ///
+ /// The settings that were passed to the constructor.
+ ///
+ public FhirJsonPocoSerializerSettings Settings { get; }
+
+ ///
+ /// Serializes the given dictionary with FHIR data into Json.
+ ///
+ public void Serialize(Base element, Utf8JsonWriter writer) =>
+ serializeInternal(element, writer, skipValue: false);
+
+ ///
+ /// Serializes the given dictionary with FHIR data into a Json string.
+ ///
+ public string SerializeToString(Base element)
+ {
+ var stream = new MemoryStream();
+ var writer = new Utf8JsonWriter(stream);
+ serializeInternal(element, writer, skipValue: false);
+ writer.Flush();
+ return Encoding.UTF8.GetString(stream.ToArray());
+ }
+
+ ///
+ /// Serializes the given dictionary with FHIR data into Json, optionally skipping the "value" element.
+ ///
+ /// Not serializing the "value" element is useful when serializing FHIR primitives into two properties, one
+ /// with just the value, and one with the id/extensions.
+ private void serializeInternal(
+ Base element,
+ Utf8JsonWriter writer,
+ bool skipValue)
+ {
+ writer.WriteStartObject();
+ var filter = Settings.SummaryFilter;
- if (members is Resource r)
- writer.WriteString("resourceType", r.TypeName);
+ if (element is Resource r)
+ writer.WriteString("resourceType", r.TypeName);
- // Only throw if we don't have a mapping where we are expected to: when this is a subclass of Base.
- if (!ClassMapping.TryGetMappingForType(members.GetType(), Release, out var mapping) && members is Base)
- throw new InvalidOperationException($"Encountered type {members.GetType()}, which is a support POCO for FHIR, but does not " +
- $"have sufficient metadata to be used by the serializer.");
+ // Only throw if we don't have a mapping where we are expected to: when this is a subclass of Base.
+ if (!ClassMapping.TryGetMappingForType(element.GetType(), Release, out var mapping))
+ throw new InvalidOperationException($"Encountered type {element.GetType()}, which is a support POCO for FHIR, but does not " +
+ $"have sufficient metadata to be used by the serializer.");
- filter?.EnterObject(members, mapping);
+ filter?.EnterObject(element, mapping);
- foreach (var member in members)
- {
- if (skipValue && member.Key == "value") continue;
+ foreach (var member in element)
+ {
+ if (skipValue && member.Key == "value") continue;
- var propertyMapping = mapping?.FindMappedElementByName(member.Key);
+ var propertyMapping = mapping?.FindMappedElementByName(member.Key);
- if (filter?.TryEnterMember(member.Key, member.Value, propertyMapping) == false)
- continue;
+ if (filter?.TryEnterMember(member.Key, member.Value, propertyMapping) == false)
+ continue;
- var propertyName = propertyMapping?.Choice == ChoiceType.DatatypeChoice ?
- addSuffixToElementName(member.Key, member.Value) : member.Key;
+ var propertyName = propertyMapping?.Choice == ChoiceType.DatatypeChoice ?
+ addSuffixToElementName(member.Key, member.Value) : member.Key;
- // do we have more possible types (choiceType), then the required type is dependent on the type of the member.Value (is it Integer64 or not?),
- // otherwise we will use the Fhirtype of the propertyMapping.
- var requiredType = (propertyMapping?.FhirType.Length > 1)
- ? (member.Value is Integer64 ? typeof(Integer64) : null)
- : propertyMapping?.FhirType.FirstOrDefault();
+ // do we have more possible types (choiceType), then the required type is dependent on the type of the member.Value (is it Integer64 or not?),
+ // otherwise we will use the Fhirtype of the propertyMapping.
+ var requiredType = (propertyMapping?.FhirType.Length > 1)
+ ? (member.Value is Integer64 ? typeof(Integer64) : null)
+ : propertyMapping?.FhirType.FirstOrDefault();
- if (member.Value is PrimitiveType pt)
- serializeFhirPrimitive(propertyName, pt, writer, requiredType);
- else if (member.Value is IReadOnlyCollection pts)
- serializeFhirPrimitiveList(propertyName, pts, writer, requiredType);
- else
- {
- writer.WritePropertyName(propertyName);
+ if (member.Value is PrimitiveType pt)
+ serializeFhirPrimitive(propertyName, pt, writer, requiredType);
+ else if (member.Value is IReadOnlyCollection pts)
+ serializeFhirPrimitiveList(propertyName, pts, writer, requiredType);
+ else
+ {
+ writer.WritePropertyName(propertyName);
- if (member.Value is ICollection coll && member.Value is not byte[])
- {
- writer.WriteStartArray();
+ if (member.Value is ICollection coll and not byte[])
+ {
+ writer.WriteStartArray();
- foreach (var value in coll)
- serializeMemberValue(value, writer, requiredType);
+ foreach (var value in coll)
+ serializeMemberValue(value, writer, requiredType);
- writer.WriteEndArray();
- }
- else
- serializeMemberValue(member.Value, writer, requiredType);
+ writer.WriteEndArray();
}
-
- filter?.LeaveMember(member.Key, member.Value, propertyMapping);
+ else
+ serializeMemberValue(member.Value, writer, requiredType);
}
- filter?.LeaveObject(members, mapping);
- writer.WriteEndObject();
+ filter?.LeaveMember(member.Key, member.Value, propertyMapping);
}
- private static string addSuffixToElementName(string elementName, object elementValue)
+ filter?.LeaveObject(element, mapping);
+ writer.WriteEndObject();
+ }
+
+ private static string addSuffixToElementName(string elementName, object elementValue)
+ {
+ var typeName = elementValue switch
{
- var typeName = elementValue switch
- {
- IEnumerable ib => ib.FirstOrDefault()?.TypeName,
- Base b => b.TypeName,
- _ => null
- };
+ IEnumerable ib => ib.FirstOrDefault()?.TypeName,
+ Base b => b.TypeName,
+ _ => null
+ };
- return typeName is null ? elementName : elementName + char.ToUpperInvariant(typeName[0]) + typeName.Substring(1);
- }
+ return typeName is null ? elementName : elementName + char.ToUpperInvariant(typeName[0]) + typeName.Substring(1);
+ }
- private void serializeMemberValue(object value, Utf8JsonWriter writer, Type? requiredType = null)
- {
- if (value is IReadOnlyDictionary complex)
- serializeInternal(complex, writer, skipValue: false);
- else
- SerializePrimitiveValue(value, writer, requiredType);
- }
+ private void serializeMemberValue(object value, Utf8JsonWriter writer, Type? requiredType = null)
+ {
+ if (value is Base complex)
+ serializeInternal(complex, writer, skipValue: false);
+ else
+ SerializePrimitiveValue(value, writer, requiredType);
+ }
- ///
- /// Serializes a list of FHIR primitives into an array element with the given name
- ///
- /// FHIR primitives are handled separately here since they may require
- /// serialization into two Json properties called "elementName" and "_elementName" and
- /// may use Json nulls as placeholders.
- private void serializeFhirPrimitiveList(
- string elementName,
- IReadOnlyCollection values,
- Utf8JsonWriter writer,
- Type? requiredType = null)
- {
- if (values is null) throw new ArgumentNullException(nameof(values));
+ ///
+ /// Serializes a list of FHIR primitives into an array element with the given name
+ ///
+ /// FHIR primitives are handled separately here since they may require
+ /// serialization into two Json properties called "elementName" and "_elementName" and
+ /// may use Json nulls as placeholders.
+ private void serializeFhirPrimitiveList(
+ string elementName,
+ IReadOnlyCollection values,
+ Utf8JsonWriter writer,
+ Type? requiredType = null)
+ {
+ if(values is null) throw new ArgumentNullException(nameof(values));
- // Don't serialize empty collections.
- if (values.Count == 0) return;
+ // Don't serialize empty collections.
+ if (values.Count == 0) return;
- // We should not write a "elementName" property until we encounter an actual
- // value. If we do, we should "catch up", by creating the property starting
- // with a json array that contains 'null' for each of the elements we encountered
- // until now that did not have a value id/extensions.
- bool wroteStartArray = false;
- int numNullsMissed = 0;
+ // We should not write a "elementName" property until we encounter an actual
+ // value. If we do, we should "catch up", by creating the property starting
+ // with a json array that contains 'null' for each of the elements we encountered
+ // until now that did not have a value id/extensions.
+ bool wroteStartArray = false;
+ int numNullsMissed = 0;
- foreach (var value in values)
+ foreach (var value in values)
+ {
+ if (value?.ObjectValue is not null)
{
- if (value?.ObjectValue is not null)
+ if (!wroteStartArray)
{
- if (!wroteStartArray)
- {
- wroteStartArray = true;
- writeStartArray(elementName, numNullsMissed, writer);
- }
-
- SerializePrimitiveValue(value!.ObjectValue, writer, requiredType);
+ wroteStartArray = true;
+ writeStartArray(elementName, numNullsMissed, writer);
}
+
+ SerializePrimitiveValue(value!.ObjectValue, writer, requiredType);
+ }
+ else
+ {
+ if (wroteStartArray)
+ writer.WriteNullValue();
else
- {
- if (wroteStartArray)
- writer.WriteNullValue();
- else
- numNullsMissed += 1;
- }
+ numNullsMissed += 1;
}
+ }
- if (wroteStartArray) writer.WriteEndArray();
+ if (wroteStartArray) writer.WriteEndArray();
- // We should not write a "_elementName" property until we encounter an actual
- // id/extension. If we do, we should "catch up", by creating the property starting
- // with a json array that contains 'null' for each of the elements we encountered
- // until now that did not have id/extensions etc.
- wroteStartArray = false;
- numNullsMissed = 0;
+ // We should not write a "_elementName" property until we encounter an actual
+ // id/extension. If we do, we should "catch up", by creating the property starting
+ // with a json array that contains 'null' for each of the elements we encountered
+ // until now that did not have id/extensions etc.
+ wroteStartArray = false;
+ numNullsMissed = 0;
- foreach (var value in values)
+ foreach (var value in values)
+ {
+ if (value?.HasElements == true)
{
- if (value?.HasElements == true)
+ if (!wroteStartArray)
{
- if (!wroteStartArray)
- {
- wroteStartArray = true;
- writeStartArray("_" + elementName, numNullsMissed, writer);
- }
-
- serializeInternal(value, writer, skipValue: true);
+ wroteStartArray = true;
+ writeStartArray("_" + elementName, numNullsMissed, writer);
}
+
+ serializeInternal(value, writer, skipValue: true);
+ }
+ else
+ {
+ if (wroteStartArray)
+ writer.WriteNullValue();
else
- {
- if (wroteStartArray)
- writer.WriteNullValue();
- else
- numNullsMissed += 1;
- }
+ numNullsMissed += 1;
}
-
- if (wroteStartArray) writer.WriteEndArray();
}
- private static void writeStartArray(string propName, int numNulls, Utf8JsonWriter writer)
- {
- writer.WriteStartArray(propName);
+ if (wroteStartArray) writer.WriteEndArray();
+ }
- for (int i = 0; i < numNulls; i++)
- writer.WriteNullValue();
- }
+ private static void writeStartArray(string propName, int numNulls, Utf8JsonWriter writer)
+ {
+ writer.WriteStartArray(propName);
+ for (int i = 0; i < numNulls; i++)
+ writer.WriteNullValue();
+ }
- ///
- /// Serializes a FHIR primitive into an element with the given name
- ///
- /// FHIR primitives are handled separately here since they may require
- /// serialization into two Json properties called "elementName" and "_elementName".
- private void serializeFhirPrimitive(string elementName, PrimitiveType value, Utf8JsonWriter writer, Type? requiredType = null)
- {
- if (value is null) throw new ArgumentNullException(nameof(value));
- if (value.ObjectValue is not null)
- {
- // Write a property with 'elementName'
- writer.WritePropertyName(elementName);
- SerializePrimitiveValue(value.ObjectValue, writer, requiredType);
- }
+ ///
+ /// Serializes a FHIR primitive into an element with the given name
+ ///
+ /// FHIR primitives are handled separately here since they may require
+ /// serialization into two Json properties called "elementName" and "_elementName".
+ private void serializeFhirPrimitive(string elementName, PrimitiveType value, Utf8JsonWriter writer, Type? requiredType = null)
+ {
+ if (value is null) throw new ArgumentNullException(nameof(value));
- if (value.HasElements)
- {
- // Write a property with '_elementName'
- writer.WritePropertyName("_" + elementName);
- serializeInternal(value, writer, skipValue: true);
- }
+ if (value.ObjectValue is not null)
+ {
+ // Write a property with 'elementName'
+ writer.WritePropertyName(elementName);
+ SerializePrimitiveValue(value.ObjectValue, writer, requiredType);
}
- ///
- /// Serialize a primitive .NET value that may occur in the POCOs into Json.
- ///
- ///
- /// To allow for future additions to the POCOs the list of primitives supported here
- /// is larger than the set used by the current POCOs. Note that DateTimeOffsetc> and
- /// byte[] are considered to be "primitive" values here (used as the value in
- /// and ).
- ///
- /// Note that the current version of System.Text.Json only allows numbers
- /// to be written that fit in .NET's type, which may be less
- /// precision than required by the FHIR specification (http://hl7.org/fhir/json.html#primitive).
- ///
- protected virtual void SerializePrimitiveValue(object value, Utf8JsonWriter writer, Type? requiredType)
+ if (value.HasElements)
{
- switch (value)
- {
- case int i32: writer.WriteNumberValue(i32); break;
- case uint ui32: writer.WriteNumberValue(ui32); break;
- case long i64:
- {
- // in case of Integer64, then the value must be serialized as a string due to
- // issues with precision in floating point libraries.
- if (requiredType == typeof(Integer64))
- writer.WriteStringValue(i64.ToString());
- else
- writer.WriteNumberValue(i64);
- break;
- }
- case ulong ui64: writer.WriteNumberValue(ui64); break;
- case float si: writer.WriteNumberValue(si); break;
- case double dbl: writer.WriteNumberValue(dbl); break;
- case decimal dec: writer.WriteNumberValue(dec); break;
- // A little note about trimming and whitespaces. The spec says:
- // "(...) In JSON and Turtle whitespace in string values is always significant. Primitive types other than
- // string SHALL NOT have leading or trailing whitespace."
- // Based on this, we are not trimming whitespace here. Validation is not a part of the responsibilities of
- // the serializer, and string-based types (like code and uri) should make sure their values are valid,
- // so should not have trailing spaces to begin with. strings are allowed to have trailing spaces, but should
- // not just be spaces. The serializer will, however, not serialize an element with only whitespace
- // (or an empty byte[]).
- case string s: writer.WriteStringValue(s); break;
- case bool b: writer.WriteBooleanValue(b); break;
- case DateTimeOffset dto: writer.WriteStringValue(ElementModel.Types.DateTime.FormatDateTimeOffset(dto)); break;
- case Enum e: writer.WriteStringValue(e.GetLiteral()); break;
- case byte[] bytes: writer.WriteStringValue(Convert.ToBase64String(bytes)); break;
- case null: writer.WriteNullValue(); break;
- default:
- throw new FormatException($"There is no known serialization for type {value.GetType()} into a Json primitive property value.");
- }
+ // Write a property with '_elementName'
+ writer.WritePropertyName("_" + elementName);
+ serializeInternal(value, writer, skipValue: true);
}
}
-}
-
-#nullable restore
+ ///
+ /// Serialize a primitive .NET value that may occur in the POCOs into Json.
+ ///
+ ///
+ /// To allow for future additions to the POCOs the list of primitives supported here
+ /// is larger than the set used by the current POCOs. Note that DateTimeOffsetc> and
+ /// byte[] are considered to be "primitive" values here (used as the value in
+ /// and ).
+ ///
+ /// Note that the current version of System.Text.Json only allows numbers
+ /// to be written that fit in .NET's type, which may be less
+ /// precision than required by the FHIR specification (http://hl7.org/fhir/json.html#primitive).
+ ///
+ protected virtual void SerializePrimitiveValue(object value, Utf8JsonWriter writer, Type? requiredType)
+ {
+ switch (value)
+ {
+ case int i32: writer.WriteNumberValue(i32); break;
+ case uint ui32: writer.WriteNumberValue(ui32); break;
+ case long i64:
+ {
+ // in case of Integer64, then the value must be serialized as a string due to
+ // issues with precision in floating point libraries.
+ if (requiredType == typeof(Integer64))
+ writer.WriteStringValue(i64.ToString());
+ else
+ writer.WriteNumberValue(i64);
+ break;
+ }
+ case ulong ui64: writer.WriteNumberValue(ui64); break;
+ case float si: writer.WriteNumberValue(si); break;
+ case double dbl: writer.WriteNumberValue(dbl); break;
+ case decimal dec: writer.WriteNumberValue(dec); break;
+ // A little note about trimming and whitespaces. The spec says:
+ // "(...) In JSON and Turtle whitespace in string values is always significant. Primitive types other than
+ // string SHALL NOT have leading or trailing whitespace."
+ // Based on this, we are not trimming whitespace here. Validation is not a part of the responsibilities of
+ // the serializer, and string-based types (like code and uri) should make sure their values are valid,
+ // so should not have trailing spaces to begin with. strings are allowed to have trailing spaces, but should
+ // not just be spaces. The serializer will, however, not serialize an element with only whitespace
+ // (or an empty byte[]).
+ case string s: writer.WriteStringValue(s); break;
+ case bool b: writer.WriteBooleanValue(b); break;
+ case DateTimeOffset dto: writer.WriteStringValue(ElementModel.Types.DateTime.FormatDateTimeOffset(dto)); break;
+ case Enum e: writer.WriteStringValue(e.GetLiteral()); break;
+ case byte[] bytes: writer.WriteStringValue(Convert.ToBase64String(bytes)); break;
+ case null: writer.WriteNullValue(); break;
+ default:
+ throw new FormatException($"There is no known serialization for type {value.GetType()} into a Json primitive property value.");
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Hl7.Fhir.Base/Serialization/BaseFhirXmlPocoSerializer.cs b/src/Hl7.Fhir.Base/Serialization/BaseFhirXmlPocoSerializer.cs
index 86490a6442..37b4091342 100644
--- a/src/Hl7.Fhir.Base/Serialization/BaseFhirXmlPocoSerializer.cs
+++ b/src/Hl7.Fhir.Base/Serialization/BaseFhirXmlPocoSerializer.cs
@@ -19,188 +19,178 @@
using System.Linq;
using System.Xml;
-namespace Hl7.Fhir.Serialization
+namespace Hl7.Fhir.Serialization;
+
+///
+/// Serializes the contents of a POCO according to the rules of FHIR Xml serialization.
+///
+/// The serializer uses the format documented in https://www.hl7.org/fhir/xml.html.
+///
+public class BaseFhirXmlPocoSerializer
{
///
- /// Serializes the contents of an IReadOnlyDictionary[string,object] according to the rules of FHIR Xml serialization.
+ /// The release of FHIR for which this serializer is configured.
///
- /// The serializer uses the format documented in https://www.hl7.org/fhir/xml.html. Since all POCOs included
- /// in the SDK implement IReadOnlyDictionary, these methods can be used to serialize POCOs to Xml.
- ///
- public class BaseFhirXmlPocoSerializer
+ public FhirRelease Release { get; }
+
+ ///
+ /// Construct a new serializer for a specific release of FHIR.
+ ///
+ public BaseFhirXmlPocoSerializer(FhirRelease release)
{
- ///
- /// The release of FHIR for which this serializer is configured.
- ///
- public FhirRelease Release { get; }
-
- ///
- /// Construct a new serializer for a specific release of FHIR.
- ///
- public BaseFhirXmlPocoSerializer(FhirRelease release)
- {
- Release = release;
- }
+ Release = release;
+ }
- ///
- /// Serializes the given dictionary with FHIR data into Json.
- ///
- public void Serialize(IReadOnlyDictionary members, XmlWriter writer, SerializationFilter? summary = default)
+ ///
+ /// Serializes the given dictionary with FHIR data into Json.
+ ///
+ public void Serialize(
+ Base element,
+ XmlWriter writer,
+ SerializationFilter? summary = default)
+ {
+ writer.WriteStartDocument();
+
+ // If we are serializing a non-resource, or we are serializing a nested resource,
+ // we need to pick a name for the root element.
+ var pickElementName = element is not Resource or IScopedNode { Parent: not null };
+ if (pickElementName)
{
- writer.WriteStartDocument();
+ // If we are an element with a name, pick that, otherwise us the name of the type.
+ var nodeName = element is ITypedElement ite ? ite.Name : element.TypeName;
- var simulateRoot = ((IScopedNode)members).Parent is not null || members is not Resource;
- if (simulateRoot)
- {
- // Serialization in XML of non-resources is problematic, since there's no root.
- // It's a common usecase though, so "invent" a root that's the name of the element's type.
- var rootElementName = members is Base b ? ((ITypedElement)b).Name : members.GetType().Name;
- writer.WriteStartElement(rootElementName, XmlNs.FHIR);
- }
+ writer.WriteStartElement(nodeName, XmlNs.FHIR);
+ }
- serializeInternal(members, writer, summary);
+ serializeInternal(element, writer, summary);
- if (simulateRoot) writer.WriteEndElement();
- writer.WriteEndDocument();
- }
+ if (pickElementName) writer.WriteEndElement();
+ writer.WriteEndDocument();
+ }
- ///
- /// Serializes the given dictionary with FHIR data into UTF8 encoded Json.
- ///
- public string SerializeToString(IReadOnlyDictionary members, SerializationFilter? summary = default) =>
- SerializationUtil.WriteXmlToString(w => Serialize(members, w, summary));
-
- ///
- /// Serializes the given dictionary with FHIR data into Json, optionally skipping the "value" element.
- ///
- /// Not serializing the "value" element is useful when serializing FHIR primitives into two properties, one
- /// with just the value, and one with the id/extensions.
- private void serializeInternal(
- IReadOnlyDictionary members,
- XmlWriter writer,
- SerializationFilter? filter)
- {
- if (members is Resource r)
- writer.WriteStartElement(r.TypeName, XmlNs.FHIR);
+ ///
+ /// Serializes the given dictionary with FHIR data into UTF8 encoded Json.
+ ///
+ public string SerializeToString(
+ Base element,
+ SerializationFilter? summary = default) =>
+ SerializationUtil.WriteXmlToString(element, (o,w) => Serialize(o, w, summary));
- // Only throw if we don't have a mapping where we are expected to: when this is a subclass of Base.
- if (!ClassMapping.TryGetMappingForType(members.GetType(), Release, out var mapping) && members is Base)
- throw new InvalidOperationException($"Encountered type {members.GetType()}, which is a support POCO for FHIR, but does not " +
- $"have sufficient metadata to be used by the serializer.");
+ ///
+ /// Serializes the given dictionary with FHIR data into Json, optionally skipping the "value" element.
+ ///
+ /// Not serializing the "value" element is useful when serializing FHIR primitives into two properties, one
+ /// with just the value, and one with the id/extensions.
+ private void serializeInternal(
+ Base element,
+ XmlWriter writer,
+ SerializationFilter? filter)
+ {
+ if (element is Resource r)
+ writer.WriteStartElement(r.TypeName, XmlNs.FHIR);
- filter?.EnterObject(members, mapping);
+ // Only throw if we don't have a mapping where we are expected to: when this is a subclass of Base.
+ if (!ClassMapping.TryGetMappingForType(element.GetType(), Release, out var mapping))
+ throw new InvalidOperationException($"Encountered type {element.GetType()}, which is a support POCO for FHIR, but does not " +
+ $"have sufficient metadata to be used by the serializer.");
- serializeElement(members, writer, filter, mapping);
+ filter?.EnterObject(element, mapping);
- filter?.LeaveObject(members, mapping);
+ serializeElement(element, writer, filter, mapping);
- if (members is Resource) writer.WriteEndElement();
- }
+ filter?.LeaveObject(element, mapping);
- private void serializeElement(IReadOnlyDictionary members, XmlWriter writer, SerializationFilter? filter, ClassMapping? mapping)
- {
- // Make sure that elements with attributes are serialized first.
- var orderedMembers = members
- .Select(m => (m, mapping: mapping?.FindMappedElementByName(m.Key)))
- .OrderBy(p => p.mapping?.SerializationHint != XmlRepresentation.XmlAttr);
+ if (element is Resource) writer.WriteEndElement();
+ }
- foreach (var ((mKey, mValue), propertyMapping) in orderedMembers)
- {
- if (filter?.TryEnterMember(mKey, mValue, propertyMapping) == false)
- continue;
+ private void serializeElement(Base element, XmlWriter writer, SerializationFilter? filter, ClassMapping? mapping)
+ {
+ // Make sure that elements with attributes are serialized first.
+ var orderedMembers = element
+ .Select(m => (m, mapping: mapping?.FindMappedElementByName(m.Key)))
+ .OrderBy(p => p.mapping?.SerializationHint != XmlRepresentation.XmlAttr);
- var elementName = propertyMapping?.Choice == ChoiceType.DatatypeChoice ?
- addSuffixToElementName(mKey, mValue) : mKey;
+ foreach (var ((mKey, mValue), propertyMapping) in orderedMembers)
+ {
+ if (filter?.TryEnterMember(mKey, mValue, propertyMapping) == false)
+ continue;
- if (mValue is ICollection coll and not byte[])
- {
- foreach (var value in coll)
- serializeMemberValue(elementName, value, writer, filter);
- }
- else
- serializeMemberValue(elementName, mValue, writer, filter);
+ var elementName = propertyMapping?.Choice == ChoiceType.DatatypeChoice ?
+ addSuffixToElementName(mKey, mValue) : mKey;
- filter?.LeaveMember(mKey, mValue, propertyMapping);
+ if (mValue is ICollection coll and not byte[])
+ {
+ foreach (var value in coll)
+ serializeMemberValue(elementName, value, writer, filter);
}
+ else
+ serializeMemberValue(elementName, mValue, writer, filter);
+
+ filter?.LeaveMember(mKey, mValue, propertyMapping);
}
+ }
- private static string addSuffixToElementName(string elementName, object elementValue)
+ private static string addSuffixToElementName(string elementName, object elementValue)
+ {
+ var typeName = elementValue switch
{
- var typeName = elementValue switch
- {
- IEnumerable ib => ib.FirstOrDefault()?.TypeName,
- Base b => b.TypeName,
- _ => null
- };
+ IEnumerable ib => ib.FirstOrDefault()?.TypeName,
+ Base b => b.TypeName,
+ _ => null
+ };
- return typeName is null ? elementName : elementName + char.ToUpperInvariant(typeName[0]) + typeName.Substring(1);
- }
+ return typeName is null ? elementName : elementName + char.ToUpperInvariant(typeName[0]) + typeName[1..];
+ }
- private void serializeMemberValue(string elementName, object value, XmlWriter writer, SerializationFilter? filter)
+ private void serializeMemberValue(string elementName, object value, XmlWriter writer, SerializationFilter? filter)
+ {
+ switch (value)
{
- if (value is XHtml xhtml)
- {
+ case XHtml xhtml:
writer.WriteRaw(xhtml.Value);
- }
- else if (value is IReadOnlyDictionary complex)
- {
+ break;
+ case Base complex:
writer.WriteStartElement(elementName, XmlNs.FHIR);
serializeInternal(complex, writer, filter);
writer.WriteEndElement();
- }
- else
+ break;
+ default:
SerializePrimitiveValue(elementName, value, writer);
- }
-
- ///
- /// Serialize a primitive .NET value that may occur in the POCOs into XML.
- ///
- ///
- /// To allow for future additions to the POCOs the list of primitives supported here
- /// is larger than the set used by the current POCOs. Note that DateTimeOffsetc> and
- /// byte[] are considered to be "primitive" values here (used as the value in
- /// and ).
- ///
- protected virtual void SerializePrimitiveValue(string elementName, object value, XmlWriter writer)
- {
- if (value is null) return; // Don't write a null property
-
- var literal = value switch
- {
- int i32 => XmlConvert.ToString(i32),
- uint ui32 => XmlConvert.ToString(ui32),
- long i64 => XmlConvert.ToString(i64),
- ulong ui64 => XmlConvert.ToString(ui64),
- float si => XmlConvert.ToString(si),
- double dbl => XmlConvert.ToString(dbl),
- decimal dec => XmlConvert.ToString(dec),
- // A little note about trimming and whitespaces. The spec says:
- // "Implementers SHOULD trim leading and trailing whitespace before writing and SHOULD trim leading
- // and trailing whitespace when reading attribute values (for XML schema conformance)"
- string s => s.Trim(),
- bool b => XmlConvert.ToString(b),
- DateTimeOffset dto => ElementModel.Types.DateTime.FormatDateTimeOffset(dto),
- byte[] bytes => Convert.ToBase64String(bytes),
- _ => throw new FormatException($"There is no known serialization for type {value.GetType()} into an Xml primitive property value.")
- };
-
- writer.WriteAttributeString(elementName, ns: null, value: literal);
+ break;
}
}
-}
-
-#if NETSTANDARD
-file static class KvpExtensions
-{
- public static void Deconstruct(this KeyValuePair kvp, out TKey key, out TValue value)
+ ///
+ /// Serialize a primitive .NET value that may occur in the POCOs into XML.
+ ///
+ ///
+ /// To allow for future additions to the POCOs the list of primitives supported here
+ /// is larger than the set used by the current POCOs. Note that DateTimeOffsetc> and
+ /// byte[] are considered to be "primitive" values here (used as the value in
+ /// and ).
+ ///
+ protected virtual void SerializePrimitiveValue(string elementName, object value, XmlWriter writer)
{
- key = kvp.Key;
- value = kvp.Value;
+ var literal = value switch
+ {
+ int i32 => XmlConvert.ToString(i32),
+ uint ui32 => XmlConvert.ToString(ui32),
+ long i64 => XmlConvert.ToString(i64),
+ ulong ui64 => XmlConvert.ToString(ui64),
+ float si => XmlConvert.ToString(si),
+ double dbl => XmlConvert.ToString(dbl),
+ decimal dec => XmlConvert.ToString(dec),
+ // A little note about trimming and whitespaces. The spec says:
+ // "Implementers SHOULD trim leading and trailing whitespace before writing and SHOULD trim leading
+ // and trailing whitespace when reading attribute values (for XML schema conformance)"
+ string s => s.Trim(),
+ bool b => XmlConvert.ToString(b),
+ DateTimeOffset dto => ElementModel.Types.DateTime.FormatDateTimeOffset(dto),
+ byte[] bytes => Convert.ToBase64String(bytes),
+ _ => throw new FormatException($"There is no known serialization for type {value.GetType()} into an Xml primitive property value.")
+ };
+
+ writer.WriteAttributeString(elementName, ns: null, value: literal);
}
-}
-
-#endif
-
-#nullable restore
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/src/Hl7.Fhir.Base/Serialization/FhirJsonConverter.cs b/src/Hl7.Fhir.Base/Serialization/FhirJsonConverter.cs
index 39fc6a161d..c8b4f2541a 100644
--- a/src/Hl7.Fhir.Base/Serialization/FhirJsonConverter.cs
+++ b/src/Hl7.Fhir.Base/Serialization/FhirJsonConverter.cs
@@ -85,50 +85,6 @@ private FhirJsonConverter(IFhirSerializationEngine engine)
this._engine = (PocoSerializationEngine)engine;
}
- ///
- /// Constructs a that (de)serializes FHIR json for the
- /// POCOs in a given assembly.
- ///
- /// The assembly containing classes to be used for deserialization.
- [Obsolete("Using this directly is not recommended. Instead, try creating a converter using the .ForFhir static method of the JsonSerializerOptions class")]
- public FhirJsonConverter(
- Assembly assembly) : this(ModelInspector.ForAssembly(assembly))
- {
- // nothing
- }
-
- [Obsolete("Using this directly is not recommended. Instead, try creating a converter using the .ForFhir static method of the JsonSerializerOptions class")]
- public FhirJsonConverter(
- Assembly assembly, FhirJsonPocoSerializerSettings? serializerSettings = null, FhirJsonPocoDeserializerSettings? deserializerSettings = null,
- Predicate? ignoreFilter = null) :
- this(FhirSerializationEngineFactory.Custom(ModelInspector.ForAssembly(assembly), ignoreFilter ?? (_ => false), deserializerSettings, serializerSettings))
- { }
-
- ///
- /// Constructs a that (de)serializes FHIR json for the
- /// POCOs in a given assembly.
- ///
- /// The containing classes to be used for deserialization.
- [Obsolete("Using this directly is not recommended. Instead, try creating a converter using the .ForFhir static method of the JsonSerializerOptions class")]
- public FhirJsonConverter(
- ModelInspector inspector) : this(FhirSerializationEngineFactory.Strict(inspector))
- {
- }
-
- ///
- /// Constructs a that (de)serializes FHIR json for the
- /// POCOs in a given assembly.
- ///
- /// A custom deserializer to be used by the json converter.
- /// A customer serializer to be used by the json converter.
- /// Since the standard serializer/deserializer will allow you to override its behaviour to produce
- /// custom behaviour, this constructor will allow the developer to use such custom serializers/deserializers instead
- /// of the defaults.
- [Obsolete("Using this directly is not recommended. Instead, try creating a converter using the .ForFhir static method of the JsonSerializerOptions class")]
- public FhirJsonConverter(BaseFhirJsonPocoDeserializer deserializer, BaseFhirJsonPocoSerializer serializer) : this(FhirSerializationEngineFactory.WithCustomJsonSerializers(deserializer, serializer))
- {
- }
-
///
/// Determines whether the specified type can be converted.
///
diff --git a/src/Hl7.Fhir.Base/Serialization/FhirXmlBuilderExtensions.cs b/src/Hl7.Fhir.Base/Serialization/FhirXmlBuilderExtensions.cs
index df7521861a..2329074192 100644
--- a/src/Hl7.Fhir.Base/Serialization/FhirXmlBuilderExtensions.cs
+++ b/src/Hl7.Fhir.Base/Serialization/FhirXmlBuilderExtensions.cs
@@ -71,10 +71,14 @@ public static async Task ToXmlAsync(this ISourceNode source, FhirXmlSeri
public static string ToXml(this ITypedElement source, FhirXmlSerializationSettings settings = null)
{
if (source is not Base b)
- return SerializationUtil.WriteXmlToString(writer => source.WriteTo(writer, settings), settings?.Pretty ?? false, settings?.AppendNewLine ?? false);
-
- var engine = FhirSerializationEngineFactory.Strict(ModelInspector.ForType(b.GetType()));
- return ((PocoSerializationEngine)engine).SerializeToXml(b);
+ return SerializationUtil.WriteXmlToString(source, (s,w) => s.WriteTo(w, settings),
+ settings?.Pretty ?? false, settings?.AppendNewLine ?? false);
+
+ // Note that this code is temporary, as we the above code will be re-instated here. It's therefore
+ // allowed to instantiate the serializer with a ModelInspector.ForType here, while we know this has
+ // problems (e.g. if the type is from Base or Conformance, it will not deduce the correct FHIR version).
+ var serializer = new BaseFhirXmlPocoSerializer(ModelInspector.ForType(b.GetType()).FhirRelease);
+ return serializer.SerializeToString(b);
}
[TemporarilyChanged]
@@ -84,8 +88,11 @@ public static async Task ToXmlAsync(this ITypedElement source, FhirXmlSe
return await SerializationUtil.WriteXmlToStringAsync(async writer => await source.WriteToAsync(writer, settings).ConfigureAwait(false), settings?.Pretty ?? false,
settings?.AppendNewLine ?? false).ConfigureAwait(false);
- var engine = FhirSerializationEngineFactory.Strict(ModelInspector.ForType(b.GetType()));
- return ((PocoSerializationEngine)engine).SerializeToXml(b);
+ // Note that this code is temporary, as we the above code will be re-instated here. It's therefore
+ // allowed to instantiate the serializer with a ModelInspector.ForType here, while we know this has
+ // problems (e.g. if the type is from Base or Conformance, it will not deduce the correct FHIR version).
+ var serializer = new BaseFhirXmlPocoSerializer(ModelInspector.ForType(b.GetType()).FhirRelease);
+ return serializer.SerializeToString(b);
}
///
@@ -95,4 +102,4 @@ public static byte[] ToXmlBytes(this ITypedElement source, FhirXmlSerializationS
public static async Task ToXmlBytesAsync(this ITypedElement source, FhirXmlSerializationSettings settings = null)
=> await SerializationUtil.WriteXmlToBytesAsync(async writer => await source.WriteToAsync(writer, settings).ConfigureAwait(false)).ConfigureAwait(false);
}
-}
+}
\ No newline at end of file
diff --git a/src/Hl7.Fhir.Base/Serialization/engine/ElementModelSerializationEngine.cs b/src/Hl7.Fhir.Base/Serialization/engine/ElementModelSerializationEngine.cs
index f9e14f092e..26bf0baa30 100644
--- a/src/Hl7.Fhir.Base/Serialization/engine/ElementModelSerializationEngine.cs
+++ b/src/Hl7.Fhir.Base/Serialization/engine/ElementModelSerializationEngine.cs
@@ -16,88 +16,70 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
-using System.Net.Http.Headers;
using System.Runtime.CompilerServices;
-namespace Hl7.Fhir.Serialization
+namespace Hl7.Fhir.Serialization;
+
+///
+/// This is an implementation of which uses the
+/// "old" TypedElement-based parser and serializer. It is used as a switchable serialization
+/// in the BaseFhirClient.
+///
+internal class ElementModelSerializationEngine(
+ ModelInspector inspector,
+ FhirXmlParsingSettings xmlSettings,
+ FhirJsonParsingSettings jsonSettings,
+ PocoBuilderSettings pocoSettings)
+ : IFhirSerializationEngine
{
- ///
- /// This is an implementation of which uses the
- /// "old" TypedElement-based parser and serializer. It is used as a switchable serialization
- /// in the BaseFhirClient.
- ///
- internal class ElementModelSerializationEngine : IFhirSerializationEngine
+ public static bool TryUnpackElementModelException(DeserializationFailedException dfe, [NotNullWhen(true)] out FormatException? fe)
{
- private readonly ModelInspector _inspector;
- private readonly FhirXmlParsingSettings _xmlSettings;
- private readonly FhirJsonParsingSettings _jsonSettings;
- private readonly PocoBuilderSettings _pocoSettings;
-
- public ElementModelSerializationEngine(
- ModelInspector inspector,
- FhirXmlParsingSettings xmlSettings,
- FhirJsonParsingSettings jsonSettings,
- PocoBuilderSettings pocoSettings)
+ if (dfe.Exceptions.Count == 1 && dfe.Exceptions.Single() is ElementModelParserException empe)
{
- _inspector = inspector;
- _xmlSettings = xmlSettings;
- _jsonSettings = jsonSettings;
- _pocoSettings = pocoSettings;
+ fe = (FormatException)empe.InnerException!;
+ return true;
}
-
- public static bool TryUnpackElementModelException(DeserializationFailedException dfe, [NotNullWhen(true)] out FormatException? fe)
+ else
{
- if (dfe.Exceptions.Count == 1 && dfe.Exceptions.Single() is ElementModelParserException empe)
- {
- fe = (FormatException)empe.InnerException!;
- return true;
- }
- else
- {
- fe = null;
- return false;
- }
+ fe = null;
+ return false;
}
+ }
- internal Base DeserializeBaseFromXml(string data) => deserialize(() => FhirXmlNode.Parse(data, settings: _xmlSettings));
- public Resource DeserializeFromXml(string data) => deserialize(() => FhirXmlNode.Parse(data, settings: _xmlSettings));
+ public Resource DeserializeFromXml(string data) => deserialize(() => FhirXmlNode.Parse(data, settings: xmlSettings));
- public Resource DeserializeFromJson(string data) => deserialize(() => FhirJsonNode.Parse(data, settings: _jsonSettings));
+ public Resource DeserializeFromJson(string data) => deserialize(() => FhirJsonNode.Parse(data, settings: jsonSettings));
- private Resource deserialize(Func deserializer)
+ private Resource deserialize(Func deserializer)
+ {
+ try
+ {
+ return (Resource)deserializer().ToPoco(inspector, null, pocoSettings);
+ }
+ catch (FormatException fe)
{
- try
- {
- return (Resource)deserializer().ToPoco(_inspector, null, _pocoSettings);
- }
- catch (FormatException fe)
- {
- // Note: this will catch StructuralTypeException as well, since that is a subclass of FormatException.
- throw new DeserializationFailedException(null, new ElementModelParserException(fe));
- }
- catch (InvalidOperationException ioe)
- {
- // Unfortunately, our ElementModel parsers treats resources without a type indicator with an InvalidOperationException.
- // This should have been a parsing error, so let's turn it into one.
- var fmt = new FormatException(ioe.Message);
- throw new DeserializationFailedException(null, new ElementModelParserException(fmt));
- }
+ // Note: this will catch StructuralTypeException as well, since that is a subclass of FormatException.
+ throw new DeserializationFailedException(null, new ElementModelParserException(fe));
}
+ catch (InvalidOperationException ioe)
+ {
+ // Unfortunately, our ElementModel parsers treats resources without a type indicator with an InvalidOperationException.
+ // This should have been a parsing error, so let's turn it into one.
+ var fmt = new FormatException(ioe.Message);
+ throw new DeserializationFailedException(null, new ElementModelParserException(fmt));
+ }
+ }
- [TemporarilyChanged]
- public string SerializeToXml(Base instance) => new CommonFhirXmlSerializer(_inspector).SerializeToString(instance);
+ public string SerializeToXml(Resource instance) => new CommonFhirXmlSerializer(inspector).SerializeToString(instance);
- public string SerializeToJson(Resource instance) => new CommonFhirJsonSerializer(_inspector).SerializeToString(instance);
+ public string SerializeToJson(Resource instance) => new CommonFhirJsonSerializer(inspector).SerializeToString(instance);
- internal class ElementModelParserException : CodedException
- {
- public const string ELEMENTMODEL_PARSER_EXCEPTION = "EMP001";
+ internal class ElementModelParserException(FormatException fe)
+ : CodedException(ELEMENTMODEL_PARSER_EXCEPTION, fe.Message, fe)
+ {
+ public const string ELEMENTMODEL_PARSER_EXCEPTION = "EMP001";
- public ElementModelParserException(FormatException fe) : base(ELEMENTMODEL_PARSER_EXCEPTION, fe.Message, fe)
- {
- // Nothing
- }
- }
+ // Nothing
}
}
diff --git a/src/Hl7.Fhir.Base/Serialization/engine/IFhirSerializationEngine.cs b/src/Hl7.Fhir.Base/Serialization/engine/IFhirSerializationEngine.cs
index cc6b82f894..8a9a7eb458 100644
--- a/src/Hl7.Fhir.Base/Serialization/engine/IFhirSerializationEngine.cs
+++ b/src/Hl7.Fhir.Base/Serialization/engine/IFhirSerializationEngine.cs
@@ -10,111 +10,36 @@
#nullable enable
using Hl7.Fhir.Model;
-using System;
using System.Diagnostics.CodeAnalysis;
-using System.Runtime.CompilerServices;
-using System.Text.Json;
-using System.Xml;
-namespace Hl7.Fhir.Serialization
+namespace Hl7.Fhir.Serialization;
+
+///
+/// Represents an object that can serialize/deserialize FHIR data from the supported
+/// serialization formats.
+///
+public interface IFhirSerializationEngine
{
///
- /// Represents an object that can serialize/deserialize FHIR data from the supported
- /// serialization formats.
+ /// Serialize a FHIR Resource POCO into a string of Json.
///
- public interface IFhirSerializationEngine
- {
- ///
- /// Serialize a FHIR Resource POCO into a string of Json.
- ///
- public string SerializeToJson(Resource instance);
-
- ///
- /// Deserialize a Json string to a FHIR Resource POCO.
- ///
- /// Thrown when the deserializer encountered one or more errors in the FHIR Json format.
- public Resource? DeserializeFromJson(string data);
-
- ///
- /// Deserialize an XML string to a FHIR Resource POCO.
- ///
- /// Thrown when the deserializer encountered one or more errors in the FHIR Xml format.
- /// Null if the data did not contain a resource, but another FHIR datatype.
- public Resource? DeserializeFromXml(string data);
-
- ///
- /// Serialize a FHIR Resource POCO into a string of Xml.
- ///
- [TemporarilyChanged]
- public string SerializeToXml(Base instance);
- }
+ public string SerializeToJson(Resource instance);
///
- /// Extension methods for the interface when the underlying engine is NOT a legacy engine.
+ /// Deserialize a Json string to a FHIR Resource POCO.
///
- public static class SerializationEngineExtensions
- {
- ///
- /// Deserialize a FHIR Resource from a JSON reader.
- ///
- /// The resource, or null if the operation failed
- /// Thrown if the underlying engine is a legacy engine
- /// Thrown if a FHIR error was encountered in the data
- public static Resource? SerializeReaderToJson(this IFhirSerializationEngine engine, ref Utf8JsonReader reader)
- {
- if (engine is not PocoSerializationEngine pse)
- {
- throw new InvalidOperationException("stream reading is not supported by legacy engines");
- }
-
- return pse.DeserializeFromJson(ref reader);
- }
-
- ///
- /// Deserialize a FHIR Resource from an XML reader.
- ///
- /// Thrown if the underlying engine is a legacy engine
- /// Thrown if a FHIR error was encountered in the data
- [TemporarilyChanged]
- public static Base? SerializeReaderToXml(this IFhirSerializationEngine engine, XmlReader reader)
- {
- if (engine is not PocoSerializationEngine pse)
- {
- throw new InvalidOperationException("stream reading is not supported by legacy engines");
- }
-
- return pse.DeserializeFromXml(reader);
- }
+ /// Thrown when the deserializer encountered one or more errors in the FHIR Json format.
+ public Resource? DeserializeFromJson(string data);
- ///
- /// Serialize a FHIR Resource to a JSON writer.
- ///
- ///
- public static void SerializeToJsonWriter(this IFhirSerializationEngine engine, Resource instance, Utf8JsonWriter writer)
- {
- if (engine is not PocoSerializationEngine pse)
- {
- throw new InvalidOperationException("stream writing is not supported by legacy engines");
- }
-
- pse.SerializeToJsonWriter(instance, writer);
- }
-
- ///
- /// Serialize a FHIR Resource to an XML writer.
- ///
- /// Thrown if the underlying engine is a legacy engine
- [TemporarilyChanged]
- public static void SerializeToXmlWriter(this IFhirSerializationEngine engine, Base instance, XmlWriter writer)
- {
- if (engine is not PocoSerializationEngine pse)
- {
- throw new InvalidOperationException("stream writing is not supported by legacy engines");
- }
-
- pse.SerializeToXmlWriter(instance, writer);
- }
- }
-}
+ ///
+ /// Deserialize an XML string to a FHIR Resource POCO.
+ ///
+ /// Thrown when the deserializer encountered one or more errors in the FHIR Xml format.
+ /// Null if the data did not contain a resource, but another FHIR datatype.
+ public Resource? DeserializeFromXml(string data);
-#nullable restore
+ ///
+ /// Serialize a FHIR Resource POCO into a string of Xml.
+ ///
+ public string SerializeToXml(Resource instance);
+}
\ No newline at end of file
diff --git a/src/Hl7.Fhir.Base/Serialization/engine/PocoSerializationEngine.cs b/src/Hl7.Fhir.Base/Serialization/engine/PocoSerializationEngine.cs
index 5ae6925590..82c3fa789f 100644
--- a/src/Hl7.Fhir.Base/Serialization/engine/PocoSerializationEngine.cs
+++ b/src/Hl7.Fhir.Base/Serialization/engine/PocoSerializationEngine.cs
@@ -16,48 +16,47 @@
using System.Linq;
using System.Reflection;
-namespace Hl7.Fhir.Serialization
+namespace Hl7.Fhir.Serialization;
+
+///
+/// This is an implementation of which uses the
+/// new Poco-based parser and serializer, initialized with the default settings.
+///
+internal partial class PocoSerializationEngine : IFhirSerializationEngine
{
- ///
- /// This is an implementation of which uses the
- /// new Poco-based parser and serializer, initialized with the default settings.
- ///
- internal partial class PocoSerializationEngine : IFhirSerializationEngine
- {
- private delegate (Base?, IEnumerable) TryDeserializer();
+ private delegate (Base?, IEnumerable) TryDeserializer();
- private readonly ModelInspector _inspector;
- internal Predicate IgnoreFilter { get; set; }
+ private readonly ModelInspector _inspector;
+ internal Predicate IgnoreFilter { get; set; }
- internal PocoSerializationEngine(ModelInspector inspector, Predicate? ignoreFilter = null, FhirJsonPocoDeserializerSettings? jsonDeserializerSettings = null, FhirJsonPocoSerializerSettings? jsonSerializerSettings = null, FhirXmlPocoDeserializerSettings? xmlSettings = null)
- {
- _inspector = inspector;
- IgnoreFilter = ignoreFilter ?? (_ => false);
- _jsonDeserializerSettings = jsonDeserializerSettings ?? new FhirJsonPocoDeserializerSettings();
- _jsonSerializerSettings = jsonSerializerSettings ?? new FhirJsonPocoSerializerSettings();
- _xmlSettings = xmlSettings ?? new FhirXmlPocoDeserializerSettings();
- }
+ internal PocoSerializationEngine(ModelInspector inspector, Predicate? ignoreFilter = null, FhirJsonPocoDeserializerSettings? jsonDeserializerSettings = null, FhirJsonPocoSerializerSettings? jsonSerializerSettings = null, FhirXmlPocoDeserializerSettings? xmlSettings = null)
+ {
+ _inspector = inspector;
+ IgnoreFilter = ignoreFilter ?? (_ => false);
+ _jsonDeserializerSettings = jsonDeserializerSettings ?? new FhirJsonPocoDeserializerSettings();
+ _jsonSerializerSettings = jsonSerializerSettings ?? new FhirJsonPocoSerializerSettings();
+ _xmlSettings = xmlSettings ?? new FhirXmlPocoDeserializerSettings();
+ }
- internal PocoSerializationEngine(BaseFhirJsonPocoDeserializer deserializer,
- BaseFhirJsonPocoSerializer serializer)
- {
- _jsonDeserializer = deserializer;
- _jsonSerializer = serializer;
- // dirty, but this constructor is really not supposed to be supported for much longer
- var inspectorfield =
- typeof(BaseFhirJsonPocoDeserializer).GetField("_inspector", BindingFlags.NonPublic | BindingFlags.Instance);
- _inspector = (inspectorfield!.GetValue(_jsonDeserializer) as ModelInspector)!;
- IgnoreFilter = _ => false;
- _xmlSettings = new FhirXmlPocoDeserializerSettings();
- }
+ internal PocoSerializationEngine(BaseFhirJsonPocoDeserializer deserializer,
+ BaseFhirJsonPocoSerializer serializer)
+ {
+ _jsonDeserializer = deserializer;
+ _jsonSerializer = serializer;
+ // dirty, but this constructor is really not supposed to be supported for much longer
+ var inspectorfield =
+ typeof(BaseFhirJsonPocoDeserializer).GetField("_inspector", BindingFlags.NonPublic | BindingFlags.Instance);
+ _inspector = (inspectorfield!.GetValue(_jsonDeserializer) as ModelInspector)!;
+ IgnoreFilter = _ => false;
+ _xmlSettings = new FhirXmlPocoDeserializerSettings();
+ }
- private Base deserializeAndFilterErrors(TryDeserializer deserializer)
- {
- var (instance, issues) = deserializer();
- var relevantIssues = issues.Where(i => !IgnoreFilter(i)).ToList();
+ private Base deserializeAndFilterErrors(TryDeserializer deserializer)
+ {
+ var (instance, issues) = deserializer();
+ var relevantIssues = issues.Where(i => !IgnoreFilter(i)).ToList();
- return relevantIssues.Any() ? throw new DeserializationFailedException(instance, relevantIssues) : instance!;
- }
+ return relevantIssues.Any() ? throw new DeserializationFailedException(instance, relevantIssues) : instance!;
}
}
diff --git a/src/Hl7.Fhir.Base/Serialization/engine/PocoSerializationEngine_Xml.cs b/src/Hl7.Fhir.Base/Serialization/engine/PocoSerializationEngine_Xml.cs
index d6fe543858..385ff53e97 100644
--- a/src/Hl7.Fhir.Base/Serialization/engine/PocoSerializationEngine_Xml.cs
+++ b/src/Hl7.Fhir.Base/Serialization/engine/PocoSerializationEngine_Xml.cs
@@ -34,18 +34,11 @@ public Resource DeserializeFromXml(string data)
});
}
- internal Base DeserializeBaseFromXml(string data)
- {
- return deserializeAndFilterErrors(() =>
- {
- _ = getXmlDeserializer().TryDeserializeResource(data, out var instance, out var issues);
- return (instance, issues);
- });
- }
-
///
- [TemporarilyChanged]
- public string SerializeToXml(Base instance) => getXmlSerializer().SerializeToString(instance);
+ public string SerializeToXml(Resource instance) => getXmlSerializer().SerializeToString(instance);
+
+
+ internal string SerializeElementToXml(Base instance) => getXmlSerializer().SerializeToString(instance);
///
/// Deserializes a resource from an XML reader
@@ -61,26 +54,11 @@ public Resource DeserializeFromXml(XmlReader reader)
});
}
- ///
- /// Deserializes an element from an XML reader
- ///
- /// The target type of the object
- /// The XML reader
- /// A POCO representation of the input read by the reader
- public Base DeserializeElementFromXml(Type targetType, XmlReader reader)
- {
- return deserializeAndFilterErrors(() =>
- {
- _ = getXmlDeserializer().TryDeserializeElement(targetType, reader, out var instance, out var issues);
- return (instance, issues);
- });
- }
-
+
///
/// Serializes an element to the supplied writer
///
/// An instance of Base or any of its children
/// The XML writer
- [TemporarilyChanged]
- public void SerializeToXmlWriter(Base instance, XmlWriter writer) => getXmlSerializer().Serialize(instance, writer);
+ internal void SerializeToXmlWriter(Base instance, XmlWriter writer) => getXmlSerializer().Serialize(instance, writer);
}
\ No newline at end of file
diff --git a/src/Hl7.Fhir.Base/Serialization/engine/SerializationEngineExtensions.cs b/src/Hl7.Fhir.Base/Serialization/engine/SerializationEngineExtensions.cs
new file mode 100644
index 0000000000..6e85fca356
--- /dev/null
+++ b/src/Hl7.Fhir.Base/Serialization/engine/SerializationEngineExtensions.cs
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2024, 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.Model;
+using System;
+using System.Runtime.CompilerServices;
+using System.Text.Json;
+using System.Xml;
+
+namespace Hl7.Fhir.Serialization;
+
+///
+/// Extension methods for the interface when the underlying engine is NOT a legacy engine.
+///
+public static class SerializationEngineExtensions
+{
+ ///
+ /// Deserialize a FHIR Resource from a .
+ ///
+ /// The resource, or null if the operation failed
+ /// Thrown if the underlying engine is a legacy engine
+ /// Thrown if a FHIR error was encountered in the data
+ public static Resource DeserializeFromJsonReader(this IFhirSerializationEngine engine, ref Utf8JsonReader reader)
+ {
+ if (engine is not PocoSerializationEngine pse)
+ {
+ throw new InvalidOperationException("stream reading is not supported by legacy engines");
+ }
+
+ return pse.DeserializeFromJson(ref reader);
+ }
+
+ ///
+ /// Deserialize a FHIR Resource from an .
+ ///
+ /// Thrown if the underlying engine is a legacy engine
+ /// Thrown if a FHIR error was encountered in the data
+ public static Resource DeserializeFromXmlReader(this IFhirSerializationEngine engine, XmlReader reader)
+ {
+ if (engine is not PocoSerializationEngine pse)
+ {
+ throw new InvalidOperationException("stream reading is not supported by legacy engines");
+ }
+
+ return pse.DeserializeFromXml(reader);
+ }
+
+ ///
+ /// Serialize a FHIR Resource to a JSON writer.
+ ///
+ ///
+ public static void SerializeToJsonWriter(this IFhirSerializationEngine engine, Resource instance, Utf8JsonWriter writer)
+ {
+ if (engine is not PocoSerializationEngine pse)
+ {
+ throw new InvalidOperationException("stream writing is not supported by legacy engines");
+ }
+
+ pse.SerializeToJsonWriter(instance, writer);
+ }
+
+ ///
+ /// Serialize a FHIR Resource to an .
+ ///
+ /// Thrown if the underlying engine is a legacy engine
+ public static void SerializeToXmlWriter(this IFhirSerializationEngine engine, Resource instance, XmlWriter writer)
+ {
+ if (engine is not PocoSerializationEngine pse)
+ {
+ throw new InvalidOperationException("stream writing is not supported by legacy engines");
+ }
+
+ pse.SerializeToXmlWriter(instance, writer);
+ }
+
+ ///
+ /// Serialize an element (a child of a resource) to a .
+ ///
+ /// This method allows you to serialize
+ /// a subtree of data to XML, which can be useful for debug and display purposes. Note that the
+ /// FHIR standard does not prescribe how this is done, so the output of this function is by definition
+ /// non standard and should not be used for production purposes.
+ public static void SerializeElementToXmlWriter(this IFhirSerializationEngine engine, Base instance, XmlWriter writer)
+ {
+ if (engine is not PocoSerializationEngine pse)
+ {
+ throw new InvalidOperationException("stream writing is not supported by legacy engines");
+ }
+
+ pse.SerializeToXmlWriter(instance, writer);
+ }
+
+ ///
+ /// Serialize an element (a child of a resource) to a string of Xml.
+ ///
+ /// This method allows you to serialize
+ /// a subtree of data to XML, which can be useful for debug and display purposes. Note that the
+ /// FHIR standard does not prescribe how this is done, so the output of this function is by definition
+ /// non standard and should not be used for production purposes.
+ public static void SerializeElementToXml(this IFhirSerializationEngine engine, Base instance)
+ {
+ if (engine is not PocoSerializationEngine pse)
+ {
+ throw new InvalidOperationException("stream writing is not supported by legacy engines");
+ }
+
+ pse.SerializeElementToXml(instance);
+ }
+}
\ No newline at end of file
diff --git a/src/Hl7.Fhir.Serialization.R4.Tests/RoundtripSignature.cs b/src/Hl7.Fhir.Serialization.R4.Tests/RoundtripSignature.cs
index d023af4d2b..002abae8f5 100644
--- a/src/Hl7.Fhir.Serialization.R4.Tests/RoundtripSignature.cs
+++ b/src/Hl7.Fhir.Serialization.R4.Tests/RoundtripSignature.cs
@@ -58,11 +58,11 @@ public void TypedElementHasCorrectInfo()
}
[TestMethod]
- [Ignore("These should not be exactly equal!")]
- [TemporarilyChanged]
+ [Ignore("Doesn't work for our ModelInspector.ForType() hack")]
+ [TemporarilyChanged]
public void WorksWithTypedElementSerializers()
{
- var sig = new Bundle() { Signature = new Signature() { Who = new ResourceReference("http://nu.nl") } };
+ var sig = new Bundle { Signature = new Signature() { Who = new ResourceReference("http://nu.nl") } };
var json = sig.ToTypedElement().ToJson();
//json.Should().Contain("\"who\"");
var sig2 = FhirJsonNode.Parse(json).ToPoco();
@@ -85,4 +85,4 @@ public void WorksWithPocoSerializers()
}
}
-}
+}
\ No newline at end of file
diff --git a/src/Hl7.Fhir.Serialization.Shared.Tests/SerializePartialTree.cs b/src/Hl7.Fhir.Serialization.Shared.Tests/SerializePartialTree.cs
index a56322f628..a2a2bc58f9 100644
--- a/src/Hl7.Fhir.Serialization.Shared.Tests/SerializePartialTree.cs
+++ b/src/Hl7.Fhir.Serialization.Shared.Tests/SerializePartialTree.cs
@@ -52,12 +52,6 @@ public async Tasks.Task CanSerializeSubtree()
var subnavPoco = navPoco.Children("photo").First();
await testSubtree(subnavXml, subnavJson, subnavPoco);
- // And on a child that's a primitive datatype
- //subnavXml = navXml.Children("id").First();
- //subnavJson = navJson.Children("id").First();
- //subnavPoco = navPoco.Children("id").First();
- //testSubtree(subnavXml, subnavJson, subnavPoco);
-
// And on a contained resource
subnavXml = navXml.Children("contained").First();
subnavJson = navJson.Children("contained").First();
@@ -147,4 +141,4 @@ public static ITypedElement ParseToTypedElement(string xml, string type, IStruct
}
-}
+}
\ No newline at end of file
diff --git a/src/Hl7.Fhir.Shared.Tests/ElementModel/PocoTypedElementTests.cs b/src/Hl7.Fhir.Shared.Tests/ElementModel/PocoTypedElementTests.cs
index 316a89f2ad..08ba78d656 100644
--- a/src/Hl7.Fhir.Shared.Tests/ElementModel/PocoTypedElementTests.cs
+++ b/src/Hl7.Fhir.Shared.Tests/ElementModel/PocoTypedElementTests.cs
@@ -197,7 +197,8 @@ public async Tasks.Task ValidateFiveWs()
[TestMethod]
- [Ignore("This design is still under discussion")]
+ [Ignore("We implemented ITypedElement on top of Base, but that does not track which version of FHIR the element is from," +
+ "so we cannot select the right type of the elements here since they diverge between versions.")]
[TemporarilyChanged]
public void CheckTypeOfElementDefinitionMembers()
{
@@ -233,4 +234,4 @@ public void CheckTypeOfElementDefinitionMembers()
}
}
-}
+}
\ No newline at end of file
diff --git a/src/Hl7.Fhir.Shims.STU3AndUp/ElementModel/TypedElementExtensions.cs b/src/Hl7.Fhir.Shims.STU3AndUp/ElementModel/TypedElementExtensions.cs
index 002593d951..dce33d8288 100644
--- a/src/Hl7.Fhir.Shims.STU3AndUp/ElementModel/TypedElementExtensions.cs
+++ b/src/Hl7.Fhir.Shims.STU3AndUp/ElementModel/TypedElementExtensions.cs
@@ -9,11 +9,13 @@
#nullable enable
using Hl7.Fhir.Model;
+using System.Runtime.CompilerServices;
namespace Hl7.Fhir.ElementModel
{
public static class TypedElementExtensions
{
+ [TemporarilyChanged] // This should be restored to use the original ITE stack.
public static ITypedElement ToTypedElement(this Base @base, string? rootName = null)
=> @base.WithScopeInfo(@base.BuildRoot(rootName));
}
diff --git a/src/Hl7.Fhir.Support.Poco.Tests/NewPocoSerializers/FhirXmlDeserializationTests.cs b/src/Hl7.Fhir.Support.Poco.Tests/NewPocoSerializers/FhirXmlDeserializationTests.cs
index c01b1a23e0..5a39ae7433 100644
--- a/src/Hl7.Fhir.Support.Poco.Tests/NewPocoSerializers/FhirXmlDeserializationTests.cs
+++ b/src/Hl7.Fhir.Support.Poco.Tests/NewPocoSerializers/FhirXmlDeserializationTests.cs
@@ -506,22 +506,24 @@ static void test(IDeserializationValidator validator)
[TestMethod]
public void TestNewXmlParserNarrativeParsing()
{
- var patient = new Patient { Id = "example" };
- patient.Text = new Narrative() { Status = Narrative.NarrativeStatus.Generated, Div = "some test data
" };
- var serializer = new BaseFhirXmlPocoSerializer(Specification.FhirRelease.STU3);
- var actual = SerializationUtil.WriteXmlToString(patient, (o, w) => serializer.Serialize(o, w));
+ var patient = new Patient
+ {
+ Id = "example",
+ Text = new Narrative()
+ {
+ Status = Narrative.NarrativeStatus.Generated,
+ Div = "some test data
"
+ }
+ };
- //// now parse this back out with the old parser
- //var op = new Hl7.Fhir.Serialization.FhirXmlParser().Parse(patientXML);
- //Assert.AreEqual(patient.Text.Div, op.Text.Div, "Old narrative should be the same");
+ var serializer = new BaseFhirXmlPocoSerializer(Specification.FhirRelease.STU3);
+ var actual = serializer.SerializeToString(patient);
// now parse this back out with the new parser
- BaseFhirXmlPocoDeserializer ds = getTestDeserializer(new());
- using (var reader = SerializationUtil.XmlReaderFromXmlText(actual))
- {
- var np = ds.DeserializeResource(reader) as Patient;
- Assert.AreEqual(patient.Text.Div, np.Text.Div, "New narrative should be the same");
- }
+ BaseFhirXmlPocoDeserializer ds = getTestDeserializer(new FhirXmlPocoDeserializerSettings());
+
+ var np = ds.DeserializeResource(actual).Should().BeOfType().Subject;
+ Assert.AreEqual(patient.Text.Div, np.Text.Div, "New narrative should be the same");
}
[TestMethod]
diff --git a/src/firely-net-sdk.props b/src/firely-net-sdk.props
index 6088dd6c00..e120a9edae 100644
--- a/src/firely-net-sdk.props
+++ b/src/firely-net-sdk.props
@@ -66,4 +66,3 @@
-