Exemplo n.º 1
0
        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);
            }
        }