/// <summary> /// Search for Resources of a certain type that match the given criteria /// </summary> /// <param name="criteria">Optional. The search parameters to filter the resources on. Each /// given string is a combined key/value pair (separated by '=')</param> /// <param name="includes">Optional. A list of include paths</param> /// <param name="pageSize">Optional. Asks server to limit the number of entries per page returned</param> /// <param name="summary">Optional. Whether to include only return a summary of the resources in the Bundle</param> /// <typeparam name="TResource">The type of resource to list</typeparam> /// <returns>A Bundle with all resources found by the search, or an empty Bundle if none were found.</returns> /// <remarks>All parameters are optional, leaving all parameters empty will return an unfiltered list /// of all resources of the given Resource type</remarks> public Bundle Search <TResource>(string[] criteria = null, string[] includes = null, int?pageSize = null, SummaryType?summary = null) where TResource : Resource, new() { // [WMR 20160421] GetResourceNameForType is obsolete // return Search(ModelInfo.GetResourceNameForType(typeof(TResource)), criteria, includes, pageSize, summary); return(Search(ModelInfo.GetFhirTypeNameForType(typeof(TResource)), criteria, includes, pageSize, summary)); }
public IHttpActionResult GetTemplates( [FromUri(Name = "_id")] int?templateId = null, [FromUri(Name = "name")] string name = null, [FromUri(Name = "_summary")] SummaryType?summary = null) { var uri = HttpContext.Current != null && HttpContext.Current.Request != null ? HttpContext.Current.Request.Url : new Uri(AppSettings.DefaultBaseUrl); var templates = this.tdb.Templates.Where(y => y.TemplateType.ImplementationGuideType == this.implementationGuideType); StructureDefinitionExporter exporter = new StructureDefinitionExporter(this.tdb, uri.Scheme, uri.Authority); if (!CheckPoint.Instance.IsDataAdmin) { User currentUser = CheckPoint.Instance.GetUser(this.tdb); templates = (from t in templates join vtp in this.tdb.ViewTemplatePermissions on t.Id equals vtp.TemplateId where vtp.UserId == currentUser.Id select t); } if (templateId != null) { templates = templates.Where(y => y.Id == templateId); } if (!string.IsNullOrEmpty(name)) { templates = templates.Where(y => y.Name.ToLower().Contains(name.ToLower())); } Bundle bundle = new Bundle() { Type = Bundle.BundleType.BatchResponse }; foreach (var template in templates) { SimpleSchema schema = SimplifiedSchemaContext.GetSimplifiedSchema(HttpContext.Current, template.ImplementationGuideType); schema = schema.GetSchemaFromContext(template.PrimaryContextType); bool isMatch = true; StructureDefinition strucDef = exporter.Convert(template, schema, summary); var fullUrl = string.Format("{0}://{1}/api/FHIR2/StructureDefinition/{2}", this.Request.RequestUri.Scheme, this.Request.RequestUri.Authority, template.Id); // Skip adding the structure definition to the response if a criteria rules it out foreach (var queryParam in this.Request.GetQueryNameValuePairs()) { if (queryParam.Key == "_id" || queryParam.Key == "name" || queryParam.Key == "_format" || queryParam.Key == "_summary") { continue; } if (queryParam.Key.Contains(".")) { throw new NotSupportedException(App_GlobalResources.TrifoliaLang.FHIRSearchCriteriaNotSupported); } var propertyDef = strucDef.GetType().GetProperty(queryParam.Key, System.Reflection.BindingFlags.IgnoreCase | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); if (propertyDef == null) { continue; } var value = propertyDef.GetValue(strucDef); var valueString = value != null?value.ToString() : string.Empty; if (valueString != queryParam.Value) { isMatch = false; } } if (isMatch) { bundle.AddResourceEntry(strucDef, fullUrl); } } return(Content <Bundle>(HttpStatusCode.OK, bundle)); }
private SearchParams toQuery(string[] criteria, string[] includes, int?pageSize, SummaryType?summary) { var q = new SearchParams(); q.Count = pageSize; if (includes != null) { foreach (var inc in includes) { q.Include.Add(inc); } } if (criteria != null) { foreach (var crit in criteria) { var keyVal = crit.SplitLeft('='); q.Add(keyVal.Item1, keyVal.Item2); } } if (summary != null) { q.Summary = summary.Value; } return(q); }
/// <summary> /// Converts a Trifolia ValueSet model to a FHIR ValueSet model. /// </summary> /// <param name="valueSet">The Trifolia ValueSet model to convert to a FHIR model</param> /// <param name="summaryType">Does not populate certain fields when a summaryType is specified.</param> /// <param name="publishedValueSets">Optional list of ValueSets that are used by a published implementation guide. If not specified, queries the database for implementation guides that this value set may be published under.</param> /// <returns>A FHIR ValueSet model</returns> public FhirValueSet Convert(ValueSet valueSet, SummaryType?summaryType = null, IEnumerable <ValueSet> publishedValueSets = null, string baseUrl = null) { bool usedByPublishedIgs = false; if (publishedValueSets == null) { var implementationGuides = (from tc in valueSet.Constraints join t in this.tdb.Templates on tc.TemplateId equals t.Id select t.OwningImplementationGuide); usedByPublishedIgs = implementationGuides.Count(y => y.PublishStatus != null && y.PublishStatus.IsPublished) > 0; } else { usedByPublishedIgs = publishedValueSets.Contains(valueSet); } FhirValueSet fhirValueSet = new FhirValueSet() { Meta = new Meta() { ElementId = valueSet.Id.ToString() }, Id = valueSet.GetFhirId(), Name = valueSet.Name, Status = usedByPublishedIgs ? PublicationStatus.Active : PublicationStatus.Draft, Description = new Markdown(valueSet.Description), Url = valueSet.GetIdentifier(ValueSetIdentifierTypes.HTTP) }; // Handle urn:oid: and urn:hl7ii: identifiers differently if a base url is provided // baseUrl is most likely provided when within the context of an implementation guide if (fhirValueSet.Url != null) { if (fhirValueSet.Url.StartsWith("urn:oid:") && !string.IsNullOrEmpty(baseUrl)) { fhirValueSet.Url = baseUrl.TrimEnd('/') + "/ValueSet/" + fhirValueSet.Url.Substring(8); } else if (fhirValueSet.Url.StartsWith("urn:hl7ii:") && !string.IsNullOrEmpty(baseUrl)) { fhirValueSet.Url = baseUrl.TrimEnd('/') + "/ValueSet/" + fhirValueSet.Url.Substring(10); } } List <ValueSetMember> activeMembers = valueSet.GetActiveMembers(DateTime.Now); if (activeMembers.Count > 0) { // If the value set was created in Trifolia, then Trifolia contains the definition // and it should be represented by <compose> if (valueSet.ImportSource == null) { // Compose var compose = new FhirValueSet.ComposeComponent(); fhirValueSet.Compose = compose; foreach (var groupedMember in activeMembers.GroupBy(y => y.CodeSystem, y => y)) { var include = new FhirValueSet.ConceptSetComponent(); compose.Include.Add(include); include.System = groupedMember.Key.Oid; foreach (var member in groupedMember) { include.Concept.Add(new FhirValueSet.ConceptReferenceComponent() { Code = member.Code, Display = member.DisplayName }); } } } else { // If the value set was imported, then we have the expansion, // but we don't have the defintion (the <compose>). var expansion = new FhirValueSet.ExpansionComponent(); fhirValueSet.Expansion = expansion; expansion.Identifier = fhirValueSet.Url; expansion.Total = activeMembers.Count; if (valueSet.LastUpdate != null) { expansion.TimestampElement = new FhirDateTime(valueSet.LastUpdate.Value); } else { expansion.TimestampElement = new FhirDateTime(DateTime.Now); } expansion.Contains = (from m in activeMembers select new FhirValueSet.ContainsComponent() { System = m.CodeSystem.Oid, Code = m.Code, Display = m.DisplayName }).ToList(); } } return(fhirValueSet); }
private SearchParams toQuery(string[] criteria, string[] includes, int?pageSize, SummaryType?summary, string[] revIncludes) { var q = new SearchParams() { Count = pageSize }; if (includes != null) { foreach (var inc in includes) { q.Include.Add(inc); } } if (revIncludes != null) { foreach (var revInc in revIncludes) { q.RevInclude.Add(revInc); } } if (criteria != null) { foreach (var crit in criteria) { var keyVal = crit.SplitLeft('='); if (string.IsNullOrEmpty(keyVal.Item1) || string.IsNullOrEmpty(keyVal.Item2)) { throw Error.Argument("criteria", "Argument should be of the form <key>=<value>"); } q.Add(keyVal.Item1, keyVal.Item2); } } if (summary != null) { q.Summary = summary.Value; } return(q); }
public Bundle GetImplementationGuides(SummaryType?summary = null, string include = null, int?implementationGuideId = null, string name = null) { // TODO: Should not be using constant string for IG type name to find templates... Not sure how else to identify FHIR DSTU1 templates though var implementationGuides = this.tdb.ImplementationGuides.Where(y => y.ImplementationGuideTypeId == this.implementationGuideType.Id); if (!CheckPoint.Instance.IsDataAdmin) { User currentUser = CheckPoint.Instance.GetUser(this.tdb); implementationGuides = (from ig in implementationGuides join igp in this.tdb.ImplementationGuidePermissions on ig.Id equals igp.UserId where igp.UserId == currentUser.Id select ig); } if (implementationGuideId != null) { implementationGuides = implementationGuides.Where(y => y.Id == implementationGuideId); } if (!string.IsNullOrEmpty(name)) { implementationGuides = implementationGuides.Where(y => y.Name.ToLower().Contains(name.ToLower())); } Bundle bundle = new Bundle() { Type = Bundle.BundleType.BatchResponse }; foreach (var ig in implementationGuides) { FhirImplementationGuide fhirImplementationGuide = Convert(ig, summary); // Add the IG before the templates bundle.AddResourceEntry(fhirImplementationGuide, this.GetFullUrl(ig)); // TODO: Need to implement a more sophisticated approach to parsing "_include" if (!string.IsNullOrEmpty(include) && include == "ImplementationGuide:resource") { List <Template> templates = ig.GetRecursiveTemplates(this.tdb, inferred: true); /* * // TODO: Add additional query parameters for indicating parent template ids and categories? * IGSettingsManager igSettings = new IGSettingsManager(this.tdb, ig.Id); * string templateBundleXml = FHIRExporter.GenerateExport(this.tdb, templates, igSettings); * Bundle templateBundle = (Bundle)FhirParser.ParseResourceFromXml(templateBundleXml); * * var templateEntries = templateBundle.Entry.Where(y => * y.Resource.ResourceType != ResourceType.ImplementationGuide && * y.Resource.Id != fhirImplementationGuide.Id); * * // TODO: Make sure that if multiple IGs are returned, that there are distinct bundle entries * // (no duplicate template/profile entries that are referenced by two separate IGs) * bundle.Entry.AddRange(templateEntries); */ StructureDefinitionExporter strucDefExporter = new StructureDefinitionExporter(this.tdb, this.scheme, this.authority); foreach (var template in templates) { var templateSchema = this.schema.GetSchemaFromContext(template.PrimaryContextType); var strucDef = strucDefExporter.Convert(template, schema); bundle.AddResourceEntry(strucDef, this.GetFullUrl(template)); } } } return(bundle); }
public StructureDefinition Convert(Template template, SimpleSchema schema, SummaryType?summaryType = null) { var fhirStructureDef = new fhir_latest.Hl7.Fhir.Model.StructureDefinition() { Id = template.FhirId(), Name = template.Name, Description = template.Description != null ? new Markdown(template.Description.RemoveInvalidUtf8Characters()) : null, Kind = template.PrimaryContextType == "Extension" ? StructureDefinition.StructureDefinitionKind.ComplexType : StructureDefinition.StructureDefinitionKind.Resource, Url = template.FhirUrl(), Type = template.TemplateType.RootContextType, Context = new List <string> { template.PrimaryContextType }, ContextType = StructureDefinition.ExtensionContext.Resource, Abstract = false, Derivation = StructureDefinition.TypeDerivationRule.Constraint }; // If this is an extension, determine what uses the extension and list them in the // "context" field so that the extension knows where it can be used. foreach (var extension in template.Extensions) { var fhirExtension = Convert(extension); if (fhirExtension != null) { fhirStructureDef.Extension.Add(fhirExtension); } } // Status if (template.Status == null || template.Status.IsDraft || template.Status.IsBallot) { fhirStructureDef.Status = PublicationStatus.Draft; } else if (template.Status.IsPublished) { fhirStructureDef.Status = PublicationStatus.Active; } else if (template.Status.IsDraft) { fhirStructureDef.Status = PublicationStatus.Retired; } // Publisher and Contact if (template.Author != null) { if (!string.IsNullOrEmpty(template.Author.ExternalOrganizationName)) { fhirStructureDef.Publisher = template.Author.ExternalOrganizationName; } var newContact = new ContactDetail(); newContact.Name = string.Format("{0} {1}", template.Author.FirstName, template.Author.LastName); newContact.Telecom.Add(new ContactPoint() { Value = template.Author.Phone, Use = ContactPoint.ContactPointUse.Work, System = ContactPoint.ContactPointSystem.Phone }); newContact.Telecom.Add(new ContactPoint() { Value = template.Author.Email, Use = ContactPoint.ContactPointUse.Work, System = ContactPoint.ContactPointSystem.Email }); fhirStructureDef.Contact.Add(newContact); } // Base profile if (template.ImpliedTemplate != null) { fhirStructureDef.BaseDefinitionElement = new FhirUri(template.ImpliedTemplate.FhirUrl()); } else { fhirStructureDef.BaseDefinitionElement = new FhirUri(string.Format("http://hl7.org/fhir/StructureDefinition/{0}", template.TemplateType.RootContextType)); } // Constraints if (summaryType == null || summaryType == SummaryType.Data) { var differential = new StructureDefinition.DifferentialComponent(); fhirStructureDef.Differential = differential; // Add base element for resource var rootElement = new ElementDefinition(); rootElement.Path = template.PrimaryContextType; rootElement.ElementId = template.PrimaryContextType; differential.Element.Add(rootElement); var rootConstraints = template.ChildConstraints.Where(y => y.ParentConstraint == null).OrderBy(y => y.Order); foreach (var constraint in rootConstraints) { SimpleSchema.SchemaObject schemaObject = null; if (schema != null) { schemaObject = schema.Children.SingleOrDefault(y => y.Name == constraint.Context); } CreateElementDefinition(fhirStructureDef, constraint, schemaObject); } // Slices var slices = template.ChildConstraints.Where(y => y.IsBranch); var sliceGroups = slices.GroupBy(y => y.GetElementPath(template.TemplateType.RootContextType)); int currentSliceGroupCount = 2; // Adds an element that contains "slicing" information for the branch(es) foreach (var sliceGroup in sliceGroups) { ElementDefinition newElementDef = new ElementDefinition(); //newElementDef.ElementId = string.Format("{0}-{1}", template.Id, currentSliceGroupCount.ToString("00")); newElementDef.Path = sliceGroup.Key; newElementDef.ElementId = sliceGroup.First().GetElementPath(template.PrimaryContextType); foreach (var branchConstraint in sliceGroup) { var igSettings = GetIGSettings(branchConstraint); var constraintFormatter = FormattedConstraintFactory.NewFormattedConstraint(this.tdb, igSettings, this.igTypePlugin, branchConstraint); var branchIdentifiers = branchConstraint.ChildConstraints.Where(y => y.IsBranchIdentifier); newElementDef.Definition = constraintFormatter.GetPlainText(false, false, false); newElementDef.Slicing = new ElementDefinition.SlicingComponent() { Rules = template.IsOpen ? ElementDefinition.SlicingRules.Open : ElementDefinition.SlicingRules.Closed }; if (branchIdentifiers.Count() > 0) { newElementDef.Slicing.Discriminator = (from bi in branchIdentifiers select new ElementDefinition.DiscriminatorComponent() { Type = ElementDefinition.DiscriminatorType.Value, Path = bi.GetElementPath(null, branchConstraint) }).ToList(); } else if (branchConstraint.Context == "extension") { newElementDef.Slicing.Discriminator.Add(new ElementDefinition.DiscriminatorComponent() { Type = ElementDefinition.DiscriminatorType.Value, Path = "url" }); } else // If no discriminators are specified, assume the child SHALL constraints are discriminators { var discriminatorConstraints = branchConstraint.ChildConstraints.Where(y => y.Conformance == "SHALL"); var singleValueDiscriminators = discriminatorConstraints.Where(y => !string.IsNullOrEmpty(y.Value)); // If there are constraints that have specific single-value bindings, prefer those if (singleValueDiscriminators.Count() > 0 && singleValueDiscriminators.Count() != discriminatorConstraints.Count()) { discriminatorConstraints = singleValueDiscriminators; } newElementDef.Slicing.Discriminator = (from d in discriminatorConstraints select new ElementDefinition.DiscriminatorComponent() { Type = ElementDefinition.DiscriminatorType.Value, Path = d.GetElementPath(template.PrimaryContextType, branchConstraint) }).ToList(); } } // Find where to insert the slice in the element list var firstElement = fhirStructureDef.Differential.Element.First(y => y.Path == sliceGroup.Key); var firstElementIndex = fhirStructureDef.Differential.Element.IndexOf(firstElement); differential.Element.Insert(firstElementIndex, newElementDef); currentSliceGroupCount++; } } return(fhirStructureDef); }
/// <summary> /// Search for Resources of a certain type that match the given criteria /// </summary> /// <param name="criteria">Optional. The search parameters to filter the resources on. Each /// given string is a combined key/value pair (separated by '=')</param> /// <param name="includes">Optional. A list of include paths</param> /// <param name="pageSize">Optional. Asks server to limit the number of entries per page returned</param> /// <param name="summary">Optional. Whether to include only return a summary of the resources in the Bundle</param> /// <param name="revIncludes">Optional. A list of reverse include paths</param> /// <typeparam name="TResource">The type of resource to list</typeparam> /// <returns>A Bundle with all resources found by the search, or an empty Bundle if none were found.</returns> /// <remarks>All parameters are optional, leaving all parameters empty will return an unfiltered list /// of all resources of the given Resource type</remarks> public Task <Bundle> SearchUsingPostAsync <TResource>(string[] criteria = null, string[] includes = null, int?pageSize = null, SummaryType?summary = null, string[] revIncludes = null) where TResource : Resource, new() { return(SearchUsingPostAsync(ModelInfo.GetFhirTypeNameForType(typeof(TResource)), criteria, includes, pageSize, summary, revIncludes)); }
/// <summary> /// Search for Resources of a certain type that match the given criteria /// </summary> /// <param name="criteria">Optional. The search parameters to filter the resources on. Each /// given string is a combined key/value pair (separated by '=')</param> /// <param name="includes">Optional. A list of include paths</param> /// <param name="pageSize">Optional. Asks server to limit the number of entries per page returned</param> /// <param name="summary">Optional. Whether to include only return a summary of the resources in the Bundle</param> /// <param name="revIncludes">Optional. A list of reverse include paths</param> /// <typeparam name="TResource">The type of resource to list</typeparam> /// <returns>A Bundle with all resources found by the search, or an empty Bundle if none were found.</returns> /// <remarks>All parameters are optional, leaving all parameters empty will return an unfiltered list /// of all resources of the given Resource type</remarks> public Bundle SearchUsingPost <TResource>(string[] criteria = null, string[] includes = null, int?pageSize = null, SummaryType?summary = null, string[] revIncludes = null) where TResource : Resource, new() { return(SearchUsingPostAsync <TResource>(criteria, includes, pageSize, summary, revIncludes).WaitResult()); }
public StructureDefinition Convert(Template template, SimpleSchema schema, SummaryType?summaryType = null) { StructureDefinition fhirStructureDef = new StructureDefinition() { Name = template.Name, Description = template.Description, Kind = StructureDefinition.StructureDefinitionKind.Resource, Url = template.Oid, ConstrainedType = template.TemplateType.RootContextType, Abstract = false }; // Extensions foreach (var extension in template.Extensions) { var fhirExtension = Convert(extension); if (fhirExtension != null) { fhirStructureDef.Extension.Add(fhirExtension); } } // Status if (template.Status == null || template.Status.IsDraft || template.Status.IsBallot) { fhirStructureDef.Status = ConformanceResourceStatus.Draft; } else if (template.Status.IsPublished) { fhirStructureDef.Status = ConformanceResourceStatus.Active; } else if (template.Status.IsDraft) { fhirStructureDef.Status = ConformanceResourceStatus.Retired; } // Publisher and Contact if (template.Author != null) { if (!string.IsNullOrEmpty(template.Author.ExternalOrganizationName)) { fhirStructureDef.Publisher = template.Author.ExternalOrganizationName; } var newContact = new StructureDefinition.StructureDefinitionContactComponent(); newContact.Name = string.Format("{0} {1}", template.Author.FirstName, template.Author.LastName); newContact.Telecom.Add(new ContactPoint() { Value = template.Author.Phone, Use = ContactPoint.ContactPointUse.Work, System = ContactPoint.ContactPointSystem.Phone }); newContact.Telecom.Add(new ContactPoint() { Value = template.Author.Email, Use = ContactPoint.ContactPointUse.Work, System = ContactPoint.ContactPointSystem.Email }); fhirStructureDef.Contact.Add(newContact); } // Base profile if (template.ImpliedTemplate != null) { fhirStructureDef.Base = string.Format("StructureDefinition/{0}", template.ImpliedTemplate.Id); } else { fhirStructureDef.Base = string.Format("http://hl7.org/fhir/StructureDefinition/{0}", template.TemplateType.RootContextType); } // Constraints if (summaryType == null || summaryType == SummaryType.Data) { fhirStructureDef.Differential = new StructureDefinition.StructureDefinitionDifferentialComponent(); // Add base element for resource fhirStructureDef.Differential.Element.Add(new ElementDefinition() { Path = template.TemplateType.RootContextType }); foreach (var constraint in template.ChildConstraints.Where(y => y.ParentConstraint == null).OrderBy(y => y.Order)) { var schemaObject = schema.Children.SingleOrDefault(y => y.Name == constraint.Context); CreateElementDefinition(fhirStructureDef, constraint, schemaObject); } // Slices var slices = template.ChildConstraints.Where(y => y.IsBranch); var sliceGroups = slices.GroupBy(y => y.GetElementPath(template.TemplateType.RootContextType)); foreach (var sliceGroup in sliceGroups) { ElementDefinition newElementDef = new ElementDefinition(); newElementDef.Path = sliceGroup.Key; foreach (var branchConstraint in sliceGroup) { var branchIdentifiers = branchConstraint.ChildConstraints.Where(y => y.IsBranchIdentifier); newElementDef.Slicing = new ElementDefinition.ElementDefinitionSlicingComponent() { Discriminator = (from bi in branchIdentifiers select bi.GetElementPath(template.TemplateType.RootContextType)), Rules = template.IsOpen ? ElementDefinition.SlicingRules.Open : ElementDefinition.SlicingRules.Closed }; // If no discriminators are specified, assume the child SHALL constraints are discriminators if (newElementDef.Slicing.Discriminator.Count() == 0) { newElementDef.Slicing.Discriminator = (from cc in branchConstraint.ChildConstraints where cc.Conformance == "SHALL" select cc.GetElementPath(template.TemplateType.RootContextType)); } } // Find where to insert the slice in the element list var firstElement = fhirStructureDef.Differential.Element.First(y => y.Path == sliceGroup.Key); var firstElementIndex = fhirStructureDef.Differential.Element.IndexOf(firstElement); fhirStructureDef.Differential.Element.Insert(firstElementIndex, newElementDef); } } return(fhirStructureDef); }
/// <summary> /// Search for Resources of a certain type that match the given criteria /// </summary> /// <param name="type">The type of resource to search for</param> /// <param name="q">Optional. The search parameters to filter the resources on. Each /// given string is a combined key/value pair (separated by '=')</param> /// <param name="includes">Optional. A list of include paths</param> /// <param name="pageSize">Optional. Asks server to limit the number of entries per page returned</param> /// <param name="summary">>Optional. Whether to include only return a summary of the resources in the Bundle</param> /// <returns>A List with all resource Ids found by the search, or an empty List if none were found.</returns> public List <String> FilteredGetIds(string type, int page = 1, string[] q = null, string[] includes = null, int?pageSize = null, SummaryType?summary = null) { List <String> result = new List <String>(); if (string.IsNullOrWhiteSpace(type)) { return(result); } var bundle = _client.Search(type); while (bundle != null) { foreach (var entry in bundle.Entry) { result.Add(entry.Resource.Id); } bundle = _client.Continue(bundle); } return(result); }
public PyroSearchParameters() { this.SummaryType = null; }
public FhirImplementationGuide Convert(ImplementationGuide ig, SummaryType?summaryType = null, bool includeVocabulary = true) { var fhirImplementationGuide = new FhirImplementationGuide() { Id = ig.Id.ToString(), Name = ig.Name, Url = string.Format("ImplementationGuide/{0}", ig.Id) }; // Status if (ig.PublishStatus == PublishStatus.GetPublishedStatus(this.tdb)) { fhirImplementationGuide.Status = ConformanceResourceStatus.Active; } else if (ig.PublishStatus == PublishStatus.GetRetiredStatus(this.tdb) || ig.PublishStatus == PublishStatus.GetDeprecatedStatus(this.tdb)) { fhirImplementationGuide.Status = ConformanceResourceStatus.Retired; } else { fhirImplementationGuide.Status = ConformanceResourceStatus.Draft; } if (summaryType == null || summaryType == SummaryType.Data) { // Package FhirImplementationGuide.PackageComponent package = new FhirImplementationGuide.PackageComponent(); package.Name = "Profiles in this Implementation Guide"; fhirImplementationGuide.Package.Add(package); // Page: Create a page for the implementation guide. This is required by the fhir ig publisher fhirImplementationGuide.Page = new FhirImplementationGuide.PageComponent(); fhirImplementationGuide.Page.Kind = FhirImplementationGuide.GuidePageKind.Page; fhirImplementationGuide.Page.Title = ig.GetDisplayName(); fhirImplementationGuide.Page.Source = string.Format("{0}://{1}/IG/View/{2}", this.scheme, this.authority, ig.Id); // Add profiles to the implementation guide List <Template> templates = ig.GetRecursiveTemplates(this.tdb, inferred: false); var profileResources = (from t in templates select new FhirImplementationGuide.ResourceComponent() { Example = false, Source = new ResourceReference() { Reference = string.Format("StructureDefinition/{0}", t.FhirId()), Display = t.Name } }); package.Resource.AddRange(profileResources); if (includeVocabulary) { // Add value sets to the implementation guide var valueSets = (from t in templates join tc in this.tdb.TemplateConstraints on t.Id equals tc.TemplateId where tc.ValueSet != null select tc.ValueSet).Distinct().ToList(); var valueSetResources = (from vs in valueSets select new FhirImplementationGuide.ResourceComponent() { Example = false, Source = new ResourceReference() { Reference = string.Format("ValueSet/{0}", vs.Id.ToString()), Display = vs.Name } }); package.Resource.AddRange(valueSetResources); } // Add each of the individual FHIR resources added as files to the IG foreach (var file in ig.Files) { var fileData = file.GetLatestData(); Resource resource = null; try { string fileContent = System.Text.Encoding.UTF8.GetString(fileData.Data); if (file.MimeType == "application/xml" || file.MimeType == "text/xml") { resource = FhirParser.ParseResourceFromXml(fileContent); } else if (file.MimeType == "application/json") { resource = FhirParser.ParseResourceFromJson(fileContent); } } catch { } if (resource == null || string.IsNullOrEmpty(resource.Id)) { continue; } var packageFile = new FhirImplementationGuide.ResourceComponent() { Example = false, Source = new ResourceReference() { Reference = string.Format("{0}/{1}", resource.ResourceType, resource.Id), Display = GetResourceName(resource, file.FileName) } }; package.Resource.Add(packageFile); } // Add each of the samples generated for the template/profile var templateExamples = (from t in templates join ts in this.tdb.TemplateSamples on t.Id equals ts.TemplateId select new { Template = t, Sample = ts }); foreach (var templateExample in templateExamples) { Resource resource = null; try { resource = FhirParser.ParseResourceFromXml(templateExample.Sample.XmlSample); } catch { } try { if (resource == null) { resource = FhirParser.ParseResourceFromJson(templateExample.Sample.XmlSample); } } catch { } if (resource == null || string.IsNullOrEmpty(resource.Id)) { continue; } var packageExample = new FhirImplementationGuide.ResourceComponent() { Example = true, Source = new ResourceReference() { Reference = string.Format("{0}/{1}", resource.ResourceType, resource.Id), Display = GetResourceName(resource, templateExample.Sample.Name) } }; package.Resource.Add(packageExample); } } return(fhirImplementationGuide); }
/// <summary> /// Serialize the reply /// </summary> public void SerializeResponse(RestResponseMessage responseMessage, object[] parameters, object result) { try { // Outbound control var httpRequest = RestOperationContext.Current.IncomingRequest; string accepts = httpRequest.Headers["Accept"], contentType = httpRequest.Headers["Content-Type"], formatParm = httpRequest.QueryString["_format"]; var isOutputPretty = httpRequest.QueryString["_pretty"] == "true"; SummaryType?summaryType = SummaryType.False; if (httpRequest.QueryString["_summary"] != null) { summaryType = EnumUtility.ParseLiteral <SummaryType>(httpRequest.QueryString["_summary"], true); } if (accepts == "*/*") // Any = null { accepts = null; } contentType = accepts ?? contentType ?? formatParm; // No specified content type if (string.IsNullOrEmpty(contentType)) { contentType = this.m_configuration.DefaultResponseFormat == FhirResponseFormatConfiguration.Json ? "application/fhir+json" : "application/fhir+xml"; } var charset = ContentType.GetCharSetFromHeaderValue(contentType); var format = ContentType.GetMediaTypeFromHeaderValue(contentType); if (result is Base baseObject) { var ms = new MemoryStream(); // The request was in JSON or the accept is JSON switch (format) { case "application/fhir+xml": using (var xw = XmlWriter.Create(ms, new XmlWriterSettings { Encoding = new UTF8Encoding(false), Indent = isOutputPretty })) { new FhirXmlSerializer().Serialize(baseObject, xw, summaryType.Value); } break; case "application/fhir+json": using (var sw = new StreamWriter(ms, new UTF8Encoding(false), 1024, true)) using (var jw = new JsonTextWriter(sw) { Formatting = isOutputPretty ? Formatting.Indented : Formatting.None, DateFormatHandling = DateFormatHandling.IsoDateFormat }) { new FhirJsonSerializer(new SerializerSettings { Pretty = isOutputPretty }).Serialize(baseObject, jw); } break; default: throw new FhirException((HttpStatusCode)406, OperationOutcome.IssueType.NotSupported, $"{contentType} not supported"); } ms.Seek(0, SeekOrigin.Begin); responseMessage.Body = ms; } else if (result == null) { responseMessage.StatusCode = 204; // no content } else { throw new InvalidOperationException("FHIR return values must inherit from Base"); } RestOperationContext.Current.OutgoingResponse.ContentType = contentType; RestOperationContext.Current.OutgoingResponse.AppendHeader("X-PoweredBy", string.Format("{0} v{1} ({2})", Assembly.GetEntryAssembly().GetName().Name, Assembly.GetEntryAssembly().GetName().Version, Assembly.GetEntryAssembly().GetCustomAttribute <AssemblyInformationalVersionAttribute>()?.InformationalVersion)); RestOperationContext.Current.OutgoingResponse.AppendHeader("X-GeneratedOn", DateTime.Now.ToString("o")); } catch (Exception e) { this.m_traceSource.TraceEvent(EventLevel.Error, e.ToString()); throw; } }
/// <summary> /// Search for Resources of a certain type that match the given criteria /// </summary> /// <param name="resource">The type of resource to search for</param> /// <param name="criteria">Optional. The search parameters to filter the resources on. Each /// given string is a combined key/value pair (separated by '=')</param> /// <param name="includes">Optional. A list of include paths</param> /// <param name="pageSize">Optional. Asks server to limit the number of entries per page returned</param> /// <param name="summary">Optional. Whether to include only return a summary of the resources in the Bundle</param> /// <returns>A Bundle with all resources found by the search, or an empty Bundle if none were found.</returns> /// <remarks>All parameters are optional, leaving all parameters empty will return an unfiltered list /// of all resources of the given Resource type</remarks> public Bundle Search(string resource, string[] criteria = null, string[] includes = null, int?pageSize = null, SummaryType?summary = null) { if (resource == null) { throw Error.ArgumentNull(nameof(resource)); } return(Search(toQuery(criteria, includes, pageSize, summary), resource)); }
/// <summary> /// Search for Resources of a certain type that match the given criteria /// </summary> /// <param name="resource">The type of resource to search for</param> /// <param name="criteria">Optional. The search parameters to filter the resources on. Each /// given string is a combined key/value pair (separated by '=')</param> /// <param name="includes">Optional. A list of include paths</param> /// <param name="pageSize">Optional. Asks server to limit the number of entries per page returned</param> /// <param name="summary">Optional. Whether to include only return a summary of the resources in the Bundle</param> /// <param name="revIncludes">Optional. A list of reverse include paths</param> /// <returns>A Bundle with all resources found by the search, or an empty Bundle if none were found.</returns> /// <remarks>All parameters are optional, leaving all parameters empty will return an unfiltered list /// of all resources of the given Resource type</remarks> public Bundle Search(string resource, string[] criteria = null, string[] includes = null, int?pageSize = null, SummaryType?summary = null, string[] revIncludes = null) { return(SearchAsync(resource, criteria, includes, pageSize, summary, revIncludes).WaitResult()); }
/// <summary> /// Converts a Trifolia ValueSet model to a FHIR ValueSet model. /// </summary> /// <param name="valueSet">The Trifolia ValueSet model to convert to a FHIR model</param> /// <param name="summaryType">Does not populate certain fields when a summaryType is specified.</param> /// <param name="publishedValueSets">Optional list of ValueSets that are used by a published implementation guide. If not specified, queries the database for implementation guides that this value set may be published under.</param> /// <returns>A FHIR ValueSet model</returns> public FhirValueSet Convert(ValueSet valueSet, SummaryType?summaryType = null, IEnumerable <ValueSet> publishedValueSets = null) { bool usedByPublishedIgs = false; if (publishedValueSets == null) { var implementationGuides = (from tc in valueSet.Constraints join t in this.tdb.Templates on tc.TemplateId equals t.Id select t.OwningImplementationGuide); usedByPublishedIgs = implementationGuides.Count(y => y.PublishStatus != null && y.PublishStatus.IsPublished) > 0; } else { usedByPublishedIgs = publishedValueSets.Contains(valueSet); } FhirValueSet fhirValueSet = new FhirValueSet() { Id = valueSet.GetFhirId(), Name = valueSet.Name, Status = usedByPublishedIgs ? ConformanceResourceStatus.Active : ConformanceResourceStatus.Draft, Description = new Markdown(valueSet.Description), Url = valueSet.Oid }; if (summaryType == null || summaryType == SummaryType.Data) { var activeMembers = valueSet.GetActiveMembers(DateTime.Now); if (activeMembers.Count > 0) { // Compose var compose = new FhirValueSet.ComposeComponent(); fhirValueSet.Compose = compose; foreach (var groupedMember in activeMembers.GroupBy(y => y.CodeSystem, y => y)) { var include = new FhirValueSet.ConceptSetComponent(); compose.Include.Add(include); include.System = groupedMember.Key.Oid; foreach (var member in groupedMember) { include.Concept.Add(new FhirValueSet.ConceptReferenceComponent() { Code = member.Code, Display = member.DisplayName }); } } // Expansion var expansion = new FhirValueSet.ExpansionComponent(); expansion.Identifier = string.Format("urn:uuid:{0}", Guid.NewGuid()); expansion.Timestamp = FhirDateTime.Now().ToString(); fhirValueSet.Expansion = expansion; foreach (ValueSetMember vsMember in activeMembers) { var fhirMember = new FhirValueSet.ContainsComponent() { System = STU3Helper.FormatIdentifier(vsMember.CodeSystem.Oid), Code = vsMember.Code, Display = vsMember.DisplayName }; expansion.Contains.Add(fhirMember); } } } return(fhirValueSet); }
/// <summary> /// Search for Resources across the whole server that match the given criteria /// </summary> /// <param name="criteria">Optional. The search parameters to filter the resources on. Each /// given string is a combined key/value pair (separated by '=')</param> /// <param name="includes">Optional. A list of include paths</param> /// <param name="pageSize">Optional. Asks server to limit the number of entries per page returned</param> /// <param name="summary">Optional. Whether to include only return a summary of the resources in the Bundle</param> /// <param name="revIncludes">Optional. A list of reverse include paths</param> /// <returns>A Bundle with all resources found by the search, or an empty Bundle if none were found.</returns> /// <remarks>All parameters are optional, leaving all parameters empty will return an unfiltered list /// of all resources of the given Resource type</remarks> public Task <Bundle> WholeSystemSearchUsingPostAsync(string[] criteria = null, string[] includes = null, int?pageSize = null, SummaryType?summary = null, string[] revIncludes = null) { return(SearchUsingPostAsync(toQuery(criteria, includes, pageSize, summary, revIncludes))); }
public FhirImplementationGuide Convert(ImplementationGuide ig, SummaryType?summaryType = null, bool includeVocabulary = true) { var parserSettings = new fhir_latest.Hl7.Fhir.Serialization.ParserSettings(); parserSettings.AcceptUnknownMembers = true; parserSettings.AllowUnrecognizedEnums = true; parserSettings.DisallowXsiAttributesOnRoot = false; var fhirXmlParser = new FhirXmlParser(parserSettings); var fhirJsonParser = new FhirJsonParser(parserSettings); string url = string.Format("ImplementationGuide/{0}", ig.Id); if (!string.IsNullOrEmpty(ig.Identifier) && (ig.Identifier.StartsWith("http://") || ig.Identifier.StartsWith("https://"))) { url = ig.Identifier.TrimEnd('/') + "/" + url.TrimStart('/'); } var fhirImplementationGuide = new FhirImplementationGuide() { Id = ig.Id.ToString(), Name = ig.Name, Url = url }; // Status if (ig.PublishStatus == PublishStatus.GetPublishedStatus(this.tdb)) { fhirImplementationGuide.Status = PublicationStatus.Active; } else if (ig.PublishStatus == PublishStatus.GetRetiredStatus(this.tdb) || ig.PublishStatus == PublishStatus.GetDeprecatedStatus(this.tdb)) { fhirImplementationGuide.Status = PublicationStatus.Retired; } else { fhirImplementationGuide.Status = PublicationStatus.Draft; } if (summaryType == null || summaryType == SummaryType.Data) { // Package FhirImplementationGuide.PackageComponent package = new FhirImplementationGuide.PackageComponent(); package.Name = "Profiles in this Implementation Guide"; fhirImplementationGuide.Package.Add(package); // Page: Create a page for the implementation guide. This is required by the fhir ig publisher fhirImplementationGuide.Page = new FhirImplementationGuide.PageComponent(); fhirImplementationGuide.Page.Kind = FhirImplementationGuide.GuidePageKind.Page; fhirImplementationGuide.Page.Title = ig.GetDisplayName(); fhirImplementationGuide.Page.Source = string.Format("{0}://{1}/IG/View/{2}", this.scheme, this.authority, ig.Id); // Add profiles to the implementation guide List <Template> templates = ig.GetRecursiveTemplates(this.tdb, inferred: false); var profileResources = (from t in templates.OrderBy(y => y.ImpliedTemplateId) select new FhirImplementationGuide.ResourceComponent() { Example = false, Source = new ResourceReference() { Reference = string.Format("StructureDefinition/{0}", t.FhirId()), Display = t.Name } }); package.Resource.AddRange(profileResources); if (includeVocabulary) { // Add value sets to the implementation guide var valueSetsIds = (from t in templates join tc in this.tdb.TemplateConstraints.AsNoTracking() on t.Id equals tc.TemplateId where tc.ValueSetId != null select tc.ValueSetId) .Distinct() .ToList(); var valueSets = (from vs in this.tdb.ValueSets join vsi in valueSetsIds on vs.Id equals vsi select vs).ToList(); var valueSetResources = (from vs in valueSets where vs.GetIdentifier() != null && !vs.GetIdentifier().StartsWith("http://hl7.org/fhir/ValueSet/") // Ignore value sets in the base spec select new FhirImplementationGuide.ResourceComponent() { Example = false, Source = new ResourceReference() { Reference = string.Format("ValueSet/{0}", vs.GetFhirId()), Display = vs.Name } }); package.Resource.AddRange(valueSetResources); } // Add each of the individual FHIR resources added as files to the IG foreach (var file in ig.Files) { var fileData = file.GetLatestData(); Resource resource = null; try { string fileContent = System.Text.Encoding.UTF8.GetString(fileData.Data); if (file.MimeType == "application/xml" || file.MimeType == "text/xml") { resource = fhirXmlParser.Parse <Resource>(fileContent); } else if (file.MimeType == "application/json") { resource = fhirJsonParser.Parse <Resource>(fileContent); } } catch { } if (resource == null || string.IsNullOrEmpty(resource.Id)) { continue; } var packageFile = new FhirImplementationGuide.ResourceComponent() { Example = false, Source = new ResourceReference() { Reference = string.Format("{0}/{1}", resource.ResourceType, resource.Id), Display = GetResourceName(resource, file.FileName) } }; package.Resource.Add(packageFile); } // Add each of the samples generated for the template/profile var templateExamples = (from t in templates join ts in this.tdb.TemplateSamples on t.Id equals ts.TemplateId select new { Template = t, Sample = ts }); foreach (var templateExample in templateExamples) { Resource resource = null; try { resource = fhirXmlParser.Parse <Resource>(templateExample.Sample.XmlSample); } catch { } try { if (resource == null) { resource = fhirJsonParser.Parse <Resource>(templateExample.Sample.XmlSample); } } catch { } if (resource == null || string.IsNullOrEmpty(resource.Id)) { continue; } var packageExample = new FhirImplementationGuide.ResourceComponent() { Example = true, Source = new ResourceReference() { Reference = string.Format("{0}/{1}", resource.ResourceType, resource.Id), Display = GetResourceName(resource, templateExample.Sample.Name) }, ExampleFor = new ResourceReference() { Reference = string.Format("StructureDefinition/{0}", templateExample.Template.Bookmark), Display = templateExample.Template.Name } }; package.Resource.Add(packageExample); } } return(fhirImplementationGuide); }
/// <summary> /// Search for Resources across the whole server that match the given criteria /// </summary> /// <param name="criteria">Optional. The search parameters to filter the resources on. Each /// given string is a combined key/value pair (separated by '=')</param> /// <param name="includes">Optional. A list of include paths</param> /// <param name="pageSize">Optional. Asks server to limit the number of entries per page returned</param> /// <param name="summary">Optional. Whether to include only return a summary of the resources in the Bundle</param> /// <param name="revIncludes">Optional. A list of reverse include paths</param> /// <returns>A Bundle with all resources found by the search, or an empty Bundle if none were found.</returns> /// <remarks>All parameters are optional, leaving all parameters empty will return an unfiltered list /// of all resources of the given Resource type</remarks> public Bundle WholeSystemSearchUsingPost(string[] criteria = null, string[] includes = null, int?pageSize = null, SummaryType?summary = null, string[] revIncludes = null) { return(WholeSystemSearchUsingPostAsync(criteria, includes, pageSize, summary, revIncludes).WaitResult()); }
/// <summary> /// Search for Resources across the whol server that match the given criteria /// </summary> /// <param name="criteria">Optional. The search parameters to filter the resources on. Each /// given string is a combined key/value pair (separated by '=')</param> /// <param name="includes">Optional. A list of include paths</param> /// <param name="pageSize">Optional. Asks server to limit the number of entries per page returned</param> /// <param name="summary">Optional. Whether to include only return a summary of the resources in the Bundle</param> /// <returns>A Bundle with all resources found by the search, or an empty Bundle if none were found.</returns> /// <remarks>All parameters are optional, leaving all parameters empty will return an unfiltered list /// of all resources of the given Resource type</remarks> public Bundle WholeSystemSearch(string[] criteria = null, string[] includes = null, int?pageSize = null, SummaryType?summary = null) { return(Search(toQuery(criteria, includes, pageSize, summary))); }
public StructureDefinition Convert(Template template, SimpleSchema schema, SummaryType?summaryType = null) { string id = template.Id.ToString(); if (template.Oid.StartsWith("http://") || template.Oid.StartsWith("https://")) { id = template.Oid.Substring(template.Oid.LastIndexOf("/") + 1); } var fhirStructureDef = new fhir_stu3.Hl7.Fhir.Model.StructureDefinition() { Id = id, Name = template.Name, Description = !string.IsNullOrEmpty(template.Description) ? new Markdown(template.Description) : null, Kind = StructureDefinition.StructureDefinitionKind.Resource, Url = template.Oid, Type = template.TemplateType.RootContextType, Context = new List <string> { template.PrimaryContextType }, ContextType = template.PrimaryContextType == "Extension" ? StructureDefinition.ExtensionContext.Extension : StructureDefinition.ExtensionContext.Resource, Abstract = false, Derivation = StructureDefinition.TypeDerivationRule.Constraint }; // Extensions foreach (var extension in template.Extensions) { var fhirExtension = Convert(extension); if (fhirExtension != null) { fhirStructureDef.Extension.Add(fhirExtension); } } // Status if (template.Status == null || template.Status.IsDraft || template.Status.IsBallot) { fhirStructureDef.Status = ConformanceResourceStatus.Draft; } else if (template.Status.IsPublished) { fhirStructureDef.Status = ConformanceResourceStatus.Active; } else if (template.Status.IsDraft) { fhirStructureDef.Status = ConformanceResourceStatus.Retired; } // Publisher and Contact if (template.Author != null) { if (!string.IsNullOrEmpty(template.Author.ExternalOrganizationName)) { fhirStructureDef.Publisher = template.Author.ExternalOrganizationName; } var newContact = new StructureDefinition.ContactComponent(); newContact.Name = string.Format("{0} {1}", template.Author.FirstName, template.Author.LastName); newContact.Telecom.Add(new ContactPoint() { Value = template.Author.Phone, Use = ContactPoint.ContactPointUse.Work, System = ContactPoint.ContactPointSystem.Phone }); newContact.Telecom.Add(new ContactPoint() { Value = template.Author.Email, Use = ContactPoint.ContactPointUse.Work, System = ContactPoint.ContactPointSystem.Email }); fhirStructureDef.Contact.Add(newContact); } // Base profile if (template.ImpliedTemplate != null) { fhirStructureDef.BaseDefinitionElement = new FhirUri(template.ImpliedTemplate.Oid); } else { fhirStructureDef.BaseDefinitionElement = new FhirUri(string.Format("http://hl7.org/fhir/StructureDefinition/{0}", template.TemplateType.RootContextType)); } // Constraints if (summaryType == null || summaryType == SummaryType.Data) { var differential = new StructureDefinition.DifferentialComponent(); fhirStructureDef.Differential = differential; // Add base element for resource differential.Element.Add(new ElementDefinition() { ElementId = string.Format("{0}-00001", template.Id.ToString()), Path = template.PrimaryContextType }); foreach (var constraint in template.ChildConstraints.Where(y => y.ParentConstraint == null).OrderBy(y => y.Order)) { var schemaObject = schema.Children.SingleOrDefault(y => y.Name == constraint.Context); CreateElementDefinition(fhirStructureDef, constraint, schemaObject); } // Slices var slices = template.ChildConstraints.Where(y => y.IsBranch); var sliceGroups = slices.GroupBy(y => y.GetElementPath(template.TemplateType.RootContextType)); int currentSliceGroupCount = 2; foreach (var sliceGroup in sliceGroups) { ElementDefinition newElementDef = new ElementDefinition(); newElementDef.ElementId = string.Format("{0}-{1}", template.Id, currentSliceGroupCount.ToString("00000")); newElementDef.Path = sliceGroup.Key; foreach (var branchConstraint in sliceGroup) { var igSettings = GetIGSettings(branchConstraint); var constraintFormatter = FormattedConstraintFactory.NewFormattedConstraint(this.tdb, igSettings, branchConstraint); var branchIdentifiers = branchConstraint.ChildConstraints.Where(y => y.IsBranchIdentifier); newElementDef.Definition = constraintFormatter.GetPlainText(false, false, false); newElementDef.Slicing = new ElementDefinition.SlicingComponent() { Discriminator = (from bi in branchIdentifiers select bi.GetElementPath(template.TemplateType.RootContextType)), Rules = template.IsOpen ? ElementDefinition.SlicingRules.Open : ElementDefinition.SlicingRules.Closed }; // If no discriminators are specified, assume the child SHALL constraints are discriminators if (newElementDef.Slicing.Discriminator.Count() == 0) { var discriminatorConstraints = branchConstraint.ChildConstraints.Where(y => y.Conformance == "SHALL"); // If the slice referencing a contained template, use the constraints of the contained template instead of the // direct constraints of the branch if (branchConstraint.ContainedTemplate != null) { discriminatorConstraints = branchConstraint.ContainedTemplate.ChildConstraints.Where(y => y.ParentConstraint == null & y.Conformance == "SHALL"); } var singleValueDiscriminators = discriminatorConstraints.Where(y => !string.IsNullOrEmpty(y.Value)); // If there are constraints that have specific single-value bindings, prefer those if (singleValueDiscriminators.Count() > 0 && singleValueDiscriminators.Count() != discriminatorConstraints.Count()) { discriminatorConstraints = singleValueDiscriminators; } newElementDef.Slicing.Discriminator = discriminatorConstraints.Select(y => y.GetElementPath(template.PrimaryContextType)); } } // Find where to insert the slice in the element list var firstElement = fhirStructureDef.Differential.Element.First(y => y.Path == sliceGroup.Key); var firstElementIndex = fhirStructureDef.Differential.Element.IndexOf(firstElement); differential.Element.Insert(firstElementIndex, newElementDef); } } return(fhirStructureDef); }