コード例 #1
0
        /// <summary>
        /// Creates a differential structure with all "skipped" parents filled in.
        /// </summary>
        /// <param name="differential"></param>
        /// <returns>The full tree structure representing the differential</returns>
        /// <remarks>This operation will not touch the source differential, but instead will return a new structure.</remarks>
        public Profile.ConstraintComponent MakeTree()
        {
            var diff = (Profile.ConstraintComponent)_source.DeepCopy();   // We're going to modify the differential

            if (diff.Element == null || diff.Element.Count == 0)
            {
                return(diff);                                                        // nothing to do
            }
            var index    = 0;
            var elements = diff.Element;

            while (index < elements.Count)
            {
                var thisPath = elements[index].Path;
                var prevPath = index > 0 ? elements[index - 1].Path : String.Empty;

                if (thisPath.IndexOf('.') == -1)
                {
                    // I am a root node, just one segment of path, I need to be the first element
                    if (index != 0)
                    {
                        throw Error.InvalidOperation("Differential has multiple roots");
                    }

                    // Else, I am fine, proceed
                    index++;
                }
                else if (ElementNavigator.IsSibling(thisPath, prevPath) || ElementNavigator.IsDirectChildPath(prevPath, thisPath))
                {
                    // The previous path is a sibling, or my direct parent, so everything is alright, proceed to next node
                    index++;
                }
                else
                {
                    var parentPath = ElementNavigator.GetParentPath(thisPath);

                    if (prevPath == String.Empty || !prevPath.StartsWith(parentPath + "."))
                    {
                        // We're missing a path part, insert an empty parent
                        var parentElement = new Profile.ElementComponent()
                        {
                            Path = parentPath
                        };
                        elements.Insert(index, parentElement);

                        // Now, we're not sure this parent has parents, so proceed by checking the parent we have just inserted
                        // so -> index is untouched
                    }
                    else
                    {
                        // So, my predecessor an I share ancestry, of which I am sure it has been inserted by this algorithm
                        // before because of my predecessor, so we're fine.
                        index++;
                    }
                }
            }

            return(diff);
        }
コード例 #2
0
        // [WMR 20160720] Merge custom element type profiles, e.g. Patient.name with type.profile = "MyHumanName"
        // Also for extensions, i.e. an extension element in a profile inherits constraints from the extension definition
        // Specifically, the profile extension element inherits the cardinality from the extension definition root element (unless overridden in differential)
        //
        // Controversial - see GForge #9791
        //
        // How to merge elements with a custom type profile constraint?
        //
        // Example 1: Patient.Address with type.profile = AddressNL
        //            A. Merge constraints from base profile element Patient.Address
        //            B. Merge constraints from external profile AddressNL
        //
        // Example 2: slice value[x] + valueQuantity(Age)
        //            A. Merge constraints from value[x] into valueQuantity
        //            B. Merge constraints from Age profile into valueQuantity
        //
        // Ewout: no clear answer, valid use cases exist for both options
        //
        // Following logic is configurable
        // By default, use strategy (A): ignore custom type profile, merge from base
        // If ExpandTypeProfiles is enabled, then first merge custom type profile before merging base
        private void ExpandTypeProfiles(ElementNavigator snap, ElementNavigator diff)
        {
            // [WMR 20160721] Note that we also try to resolve and expand extension definitions!
            var primaryDiffType = diff.Current.Type.FirstOrDefault();

            if (primaryDiffType != null && primaryDiffType.Code != FHIRDefinedType.Reference)
            {
                var primaryDiffTypeProfile = primaryDiffType.Profile.FirstOrDefault();
                var primarySnapType        = snap.Current.Type.FirstOrDefault();
                var primarySnapTypeProfile = primarySnapType != null?primarySnapType.Profile.FirstOrDefault() : null;

                if (!string.IsNullOrEmpty(primaryDiffTypeProfile) && primaryDiffTypeProfile != primarySnapTypeProfile)
                {
                    // Debug.Print("Path = '{0}' - Merge custom type profile '{1}'".FormatWith(diff.Path, primaryTypeProfile));

                    // cf. ExpandElement

                    // [WMR 20160721] NEW: Handle type profiles with name references
                    // e.g. profile "http://hl7.org/fhir/StructureDefinition/qicore-adverseevent"
                    // Extension element "cause" => "http://hl7.org/fhir/StructureDefinition/qicore-adverseevent-cause"
                    // Constraint on extension child element "certainty" => "http://hl7.org/fhir/StructureDefinition/qicore-adverseevent-cause#certainty"
                    // This means:
                    // - First inherit child element constraints from extension definition, element with name "certainty"
                    // - Then override inherited constraints by explicit element constraints in profile differential

                    string profileUrl, elementName;
                    var    isComplex = IsComplexProfileReference(primaryDiffTypeProfile, out profileUrl, out elementName);
                    if (isComplex)
                    {
                        primaryDiffTypeProfile = profileUrl;
                    }

                    var baseType = _resolver.GetStructureDefinition(primaryDiffTypeProfile);

                    if (baseType != null)
                    {
                        if (baseType.Snapshot != null)
                        {
                            // Clone and rebase
                            baseType = (StructureDefinition)baseType.DeepCopy();

                            var rebasePath = diff.Path;
                            if (isComplex)
                            {
                                rebasePath = ElementNavigator.GetParentPath(rebasePath);
                            }
                            baseType.Snapshot.Rebase(rebasePath);

                            generateBaseElements(baseType.Snapshot.Element);
                            var baseNav = new ElementNavigator(baseType.Snapshot.Element);

                            if (elementName == null)
                            {
                                baseNav.MoveToFirstChild();
                            }
                            else
                            {
                                if (!baseNav.JumpToNameReference(elementName))
                                {
                                    throw Error.InvalidOperation("Found type profile with invalid name reference '{0}' - the base profile does not contain an element with name '{1}'".FormatWith(primaryDiffTypeProfile, elementName));
                                }
                            }

                            // Merge the external type profile
                            if (diff.HasChildren)
                            {
                                // Recursively merge the full profile, then merge overriding constraints from differential
                                mergeElement(snap, baseNav);
                            }
                            else
                            {
                                // Only merge the profile root element; no need to expand children
                                (new ElementDefnMerger(_settings.MarkChanges)).Merge(snap.Current, baseNav.Current);
                            }
                        }
                        else if (!_settings.IgnoreMissingTypeProfiles)
                        {
                            throw Error.NotSupported("Found definition of type profile '{0}', but is does not contain a snapshot representation.".FormatWith(primaryDiffTypeProfile));
                        }
                    }
                    else
                    {
                        Debug.Print("Warning! Unresolved external type profile reference: '{0}' - Ignore, skip expansion...".FormatWith(primaryDiffTypeProfile));
                        if (!_settings.IgnoreMissingTypeProfiles)
                        {
                            // throw Error.NotSupported("Trying to navigate down a node that has a declared type profile of '{0}', which is unknown".FormatWith(primaryDiffTypeProfile));
                            throw Error.ResourceReferenceNotFoundException(
                                      primaryDiffTypeProfile,
                                      "The profile contains an unresolved reference to an external type profile with url '{0}'".FormatWith(primaryDiffTypeProfile)
                                      );
                        }
                    }
                }
            }
        }