public void KeepsAnnotations() { var patient = createPatient(); ITypedElement identifier = patient["active"][0]; Assert.Equal("a string annotation", identifier.Annotation <string>()); }
private void addChildren(ITypedElement node, JObject parent) { var resourceTypeIndicator = node.Annotation <IResourceTypeSupplier>()?.ResourceType; var isResource = node.Definition?.IsResource ?? resourceTypeIndicator != null; var containedResourceType = isResource ? (node.InstanceType ?? resourceTypeIndicator) : null; if (containedResourceType != null) { parent.AddFirst(new JProperty(JsonSerializationDetails.RESOURCETYPE_MEMBER_NAME, containedResourceType)); } foreach (var nameGroup in node.Children().GroupBy(n => n.Name)) { var members = nameGroup.ToList(); // serialization info should be the same for each element in an // array - but do not explicitly check that if (!MustSerializeMember(members[0], out var generalInfo)) { break; } bool hasTypeInfo = generalInfo != null; // If we have type information, we know whather we need an array. // failing that, check whether this is a roundtrip and we have the information // about arrays in the serialization deails. Failing that, assume the default: // for unknown properties is to use an array - safest bet. var generalJsonDetails = members[0].GetJsonSerializationDetails(); var hasIndex = generalJsonDetails?.ArrayIndex != null; var needsArray = generalInfo?.IsCollection ?? hasIndex; var children = members.Select(m => buildNode(m)) .Where(c => !(c.first == null && c.second == null)).ToList(); // Don't add empty nodes to the parent if (!children.Any()) { continue; } var needsMainProperty = children.Any(c => c.first != null); var needsShadowProperty = children.Any(c => c.second != null); var propertyName = generalInfo?.IsChoiceElement == true ? members[0].Name + members[0].InstanceType.Capitalize() : members[0].Name; if (needsMainProperty) { parent.Add(new JProperty(propertyName, needsArray ? new JArray(children.Select(c => c.first ?? JValue.CreateNull())) : children[0].first)); } if (needsShadowProperty) { parent.Add(new JProperty("_" + propertyName, needsArray ? new JArray(children.Select(c => (JToken)c.second ?? JValue.CreateNull())) : (JToken)children[0].second)); } } }
public MaskingNode(ITypedElement source, MaskingNodeSettings settings = null) { if (source == null) { throw Error.ArgumentNull(nameof(source)); } if (source.Annotation <ScopedNode>() == null) { throw Error.Argument("MaskingNavigator can only be used on a navigator chain that contains a ScopedNavigator", nameof(source)); } Source = source; _settings = settings?.Clone() ?? new MaskingNodeSettings(); if (Source is IExceptionSource ies && ies.ExceptionHandler == null) { ies.ExceptionHandler = (o, a) => ExceptionHandler.NotifyOrThrow(o, a); } }
public static void CanReadThroughNavigator(ITypedElement n, bool typed) { Assert.AreEqual("Patient", n.Name); Assert.AreEqual("Patient", n.Annotation <IResourceTypeSupplier>()?.ResourceType); if (typed) { Assert.AreEqual("Patient", n.InstanceType); } var nav = n.Children().GetEnumerator(); Assert.IsTrue(nav.MoveNext()); Assert.AreEqual("id", nav.Current.Name); Assert.AreEqual("pat1", nav.Current.Value); if (typed) { Assert.AreEqual("id", nav.Current.InstanceType); } Assert.IsFalse(nav.Current.Children().Any()); Assert.IsTrue(nav.MoveNext()); Assert.AreEqual("text", nav.Current.Name); if (typed) { Assert.AreEqual("Narrative", nav.Current.InstanceType); } var text = n.Children("text").Children().GetEnumerator(); Assert.IsTrue(text.MoveNext()); // status if (typed) { Assert.AreEqual("code", text.Current.InstanceType); } Assert.AreEqual("generated", text.Current.Value); Assert.IsTrue(text.MoveNext()); Assert.AreEqual("div", text.Current.Name); Assert.IsTrue(((string)text.Current.Value).StartsWith("<div xmlns=")); // special handling of xhtml if (typed) { Assert.AreEqual("xhtml", text.Current.InstanceType); } Assert.IsFalse(text.Current.Children().Any()); // cannot move into xhtml Assert.AreEqual("div", text.Current.Name); // still on xhtml <div> var b = text.MoveNext(); Assert.IsFalse(b); // nothing more in <text> Assert.IsTrue(nav.MoveNext()); // contained Assert.AreEqual("contained", nav.Current.Name); Assert.AreEqual("Patient", nav.Current.Annotation <IResourceTypeSupplier>().ResourceType); if (typed) { Assert.AreEqual("Patient", nav.Current.InstanceType); } var contained = nav.Current.Children().GetEnumerator(); Assert.IsTrue(contained.MoveNext()); // id if (typed) { Assert.AreEqual("id", contained.Current.InstanceType); } Assert.IsTrue(contained.MoveNext()); // identifier Assert.AreEqual("identifier", contained.Current.Name); if (typed) { Assert.AreEqual("Identifier", contained.Current.InstanceType); } var identifier = contained.Current.Children().GetEnumerator(); Assert.IsTrue(identifier.MoveNext()); // system Assert.IsTrue(identifier.MoveNext()); // value var ic = identifier.Current; Assert.IsFalse(identifier.MoveNext()); // still value Assert.AreEqual("value", ic.Name); Assert.IsFalse(ic.Children().Any()); Assert.AreEqual("444222222", ic.Value); // tests whether strings are trimmed var name = n.Children("contained").First().Children("name").First(); Assert.AreEqual("name", name.Name); var inname = name.Children().ToList(); Assert.IsTrue(inname.Any()); Assert.AreEqual("id", inname[0].Name); Assert.AreEqual("firstname", inname[0].Value); Assert.AreEqual("use", inname[1].Name); var bd = n.Children("birthDate").Single(); if (typed) { Assert.AreEqual("date", bd.InstanceType); Assert.AreEqual(PartialDateTime.Parse("1974-12-25"), bd.Value); } else { Assert.AreEqual("1974-12-25", bd.Value); } if (typed) { var dec = n.Children("deceased").Single(); Assert.AreEqual("boolean", dec.InstanceType); Assert.AreEqual(false, dec.Value); } else { var dec = n.Children("deceasedBoolean").Single(); Assert.AreEqual("false", dec.Value); } }
private void build(ITypedElement source, XContainer parent) { var xmlDetails = source.GetXmlSerializationDetails(); var sourceComments = (source as IAnnotated)?.Annotation <SourceComments>(); if (!MustSerializeMember(source, out var serializationInfo)) { return; } bool hasTypeInfo = serializationInfo != null; var value = source.Value != null? PrimitiveTypeConverter.ConvertTo <string>(source.Value) : null; if (_settings.TrimWhitespaces) { value = value?.Trim(); } // xhtml children require special treament: // - They don't use an xml "value" attribute to represent the value, instead their Value is inserted verbatim into the parent // - They cannot have child nodes - the "Value" on the node contains all children as raw xml text var isXhtml = source.InstanceType == "xhtml" || serializationInfo?.Representation == XmlRepresentation.XHtml || xmlDetails?.Namespace?.GetName("div") == XmlNs.XHTMLDIV; if (isXhtml && !String.IsNullOrWhiteSpace(value)) { // The value *should* be valid xhtml - however if people just provide a plain // string, lets add a <div> around it. if (!value.TrimStart().StartsWith("<div")) { value = $"<div xmlns='http://www.w3.org/1999/xhtml'>{value}</div>"; } var sanitized = SerializationUtil.SanitizeXml(value); XElement xe = XElement.Parse(sanitized); // The div should be in the XHTMLNS namespace, correct if it // is not the case. xe.Name = XmlNs.XHTMLNS + xe.Name.LocalName; parent.Add(xe); //using (var divWriter = parent.CreateWriter()) //using (var nodeReader = SerializationUtil.XmlReaderFromXmlText(value)) // divWriter.WriteNode(nodeReader, false); return; } var usesAttribute = serializationInfo?.Representation == XmlRepresentation.XmlAttr || (xmlDetails?.NodeType == XmlNodeType.Attribute); var ns = serializationInfo?.NonDefaultNamespace ?? xmlDetails?.Namespace.NamespaceName ?? (usesAttribute ? "" : XmlNs.FHIR); bool atRoot = parent is XDocument; var localName = serializationInfo?.IsChoiceElement == true ? source.Name + source.InstanceType.Capitalize() : source.Name; // If the node is represented by an attribute (e.g. an "id" child), write // an attribute with the child's name + the child's Value into the parent if (usesAttribute && !String.IsNullOrWhiteSpace(value) && !atRoot) { parent.Add(new XAttribute(XName.Get(localName, ns), value)); return; } // else: fall through - value will be serialized as an element var me = new XElement(XName.Get(localName, ns)); if (xmlDetails?.SchemaLocation != null) { me.Add(new XAttribute(XmlNs.XSCHEMALOCATION, xmlDetails.SchemaLocation)); } // If the node has a value, add the standard FHIR value attribute if (value != null) { me.Add(new XAttribute("value", value)); } // If this needs to be serialized as a contained resource, do so var containedResourceType = atRoot ? null : (serializationInfo?.IsResource == true ? source.InstanceType : source.Annotation <IResourceTypeSupplier>()?.ResourceType); XElement containedResource = null; if (containedResourceType != null) { containedResource = new XElement(XName.Get(containedResourceType, ns)); } var childParent = containedResource ?? me; // Now, do the same for the children // xml requires a certain order, so let's make sure we serialize in the right order var orderedChildren = source.Children().OrderBy(c => c.Definition?.Order ?? 0); foreach (var child in orderedChildren) { build(child, childParent); } if (serializationInfo?.Representation == XmlRepresentation.XmlText || xmlDetails?.NodeText != null) { childParent.Add(new XText(value ?? xmlDetails.NodeText)); } if (sourceComments?.ClosingComments != null) { writeComments(sourceComments.ClosingComments, me); } // Only really add this contained resource to me when it has contents if (containedResource != null && (containedResource.HasAttributes || containedResource.HasElements)) { me.Add(containedResource); } // Only add myself to my parent if I have content, or I am the root if (value != null || me.HasElements || atRoot) { if (sourceComments?.CommentsBefore != null) { writeComments(sourceComments.CommentsBefore, parent); } parent.Add(me); } if (atRoot && parent.Elements().Any() && sourceComments?.DocumentEndComments != null) { writeComments(sourceComments.DocumentEndComments, parent); } }
private ScopedNode getScope(ITypedElement node) => node.Annotation <ScopedNode>();