private static IEnumerable <MissingValidationIssue> VerifyMaxOrMinValueIsSet(Questionnaire.ItemComponent item) { if (!(item.Type == Questionnaire.QuestionnaireItemType.Date || item.Type == Questionnaire.QuestionnaireItemType.DateTime || item.Type == Questionnaire.QuestionnaireItemType.Time || item.Type == Questionnaire.QuestionnaireItemType.Integer || item.Type == Questionnaire.QuestionnaireItemType.Decimal)) { return(new MissingValidationIssue[0]); } // If this is a read-only field and it contains a fhirpath for data extraction do not suggest any validation if (item.ReadOnly == true && item.GetExtensions(Constants.FhirPathUri).Any()) { return(new MissingValidationIssue[0]); } var issues = new List <MissingValidationIssue>(); if (item.GetExtensions(Constants.MaxValueUri).Count() == 0 || item.GetExtensions(Constants.MinValueUri).Count() == 0) { issues.Add(new MissingValidationIssue { LinkId = item.LinkId, Severity = MissingValidationSeverityEnum.Information, Details = $"Consider setting the 'maxValue' and 'minValue' attribute for items of type '{item.Type}'." }); } return(issues); }
private int DiveV1(int index, int level, List <Questionnaire.ItemComponent> itemComponents, QuestionnaireItem[] questionnaireItems) { int currentIndex = index; Questionnaire.ItemComponent item = null; for (; currentIndex < questionnaireItems.Length; currentIndex++) { QuestionnaireItem questionnaireItem = questionnaireItems[currentIndex]; _logger.LogDebug($"Questionnaire Item: {questionnaireItem.LinkId} - {questionnaireItem.Type} - {questionnaireItem.Text}"); int currentLevel = questionnaireItem.LinkId.Split('.').Length - 1; if (currentLevel == level) { item = CreateItemComponentV1(questionnaireItem); itemComponents.Add(item); } else if (currentLevel > level) { if (item == null) { throw new Exception("LinkId cannot bypass a level, i.e. jumping from 1.1 to 1.1.1.1"); } currentIndex = DiveV1(currentIndex, currentLevel, item.Item, questionnaireItems); } else if (currentLevel < level) { // If current level is less than the entry level then break out of loop and return from recursion level. break; } } return(currentIndex - 1); }
private static IEnumerable <Issue> VerifyRepeatingItemValidation(Questionnaire.ItemComponent item) { var issues = new List <Issue>(); if (item.Repeats == true) { if (item.GetExtensions(Constants.MaxOccursUri).Count() == 0) { issues.Add(new Issue { LinkId = item.LinkId, Severity = IssueSeverityEnum.Warning, Details = $"An item where the attribute 'repeats' is set to 'true' a 'maxOccurs' is recommended to be set." }); } } return(issues); }
private static IEnumerable <Issue> VerifyAttachmentValidation(Questionnaire.ItemComponent item) { if (item.Type != Questionnaire.QuestionnaireItemType.Attachment) { return(new Issue[0]); } var issues = new List <Issue>(); if (item.GetExtensions(Constants.QuestionnaireAttachmentMaxSize).Count() == 0) { issues.Add(new Issue { LinkId = item.LinkId, Severity = IssueSeverityEnum.Warning, Details = $"An item of type '{item.Type}' is missing the 'maxSize' attribute. Consider setting the 'maxSize' attribute." }); } return(issues); }
public static bool IsItemControlOfType(this Questionnaire.ItemComponent item, params string[] itemControlType) { EnsureArg.IsNotNull(itemControlType, nameof(itemControlType)); IEnumerable <Extension> extensions = item.GetExtensions(Constants.ItemControlUri); foreach (Extension extension in extensions) { if (!(extension.Value is CodeableConcept codeableConcept)) { continue; } foreach (Coding coding in codeableConcept.Coding) { if (itemControlType.Contains(coding.Code)) { return(true); } } } return(false); }
/// <summary>Builds a questionnaire.</summary> /// <exception cref="ArgumentNullException">Thrown when one or more required arguments are null.</exception> /// <param name="format">Describes the format to use.</param> /// <returns>A Questionnaire.</returns> private static Questionnaire BuildQuestionnaire( IReportingFormat format) { if (format == null) { throw new ArgumentNullException(nameof(format)); } if (string.IsNullOrEmpty(format.Name)) { throw new ArgumentNullException(nameof(format), $"Invalid IReportingFormat.Name: {format.Name}"); } if ((format.Fields == null) || (format.Fields.Count == 0)) { throw new ArgumentNullException(nameof(format), $"Invalid IReportingFormat.Fields: {format.Fields}"); } if ((format.QuestionnaireSections == null) || (format.QuestionnaireSections.Count == 0)) { throw new ArgumentNullException(nameof(format), $"Invalid IReportingFormat.QuestionnaireSections: {format.QuestionnaireSections}"); } Questionnaire questionnaire = new Questionnaire() { Meta = new Meta() { Profile = new string[] { FhirSystems.Questionnaire, }, }, Id = format.Name, Name = format.Name, Url = $"{CanonicalUrl}/Questionnaire/{format.Name}", Version = QuestionnaireVersion, Title = format.Title, Description = new Markdown(format.Description), Status = PublicationStatus.Draft, Date = PublicationDate, Publisher = Publisher, Jurisdiction = new List <CodeableConcept>() { FhirTriplet.UnitedStates.GetConcept(), }, UseContext = new List <UsageContext>() { new UsageContext() { Code = FhirTriplet.GetCode(FhirSystems.UsageContextType, CommonLiterals.ContextFocus), Value = FhirTriplet.SctCovid.GetConcept(), }, }, Item = new List <Questionnaire.ItemComponent>(), }; int sectionNumber = -1; int itemNumber = 0; foreach (QuestionnaireSection questionnaireSection in format.QuestionnaireSections) { sectionNumber++; itemNumber = 0; Questionnaire.ItemComponent section = new Questionnaire.ItemComponent() { LinkId = $"section_{sectionNumber}", Type = Questionnaire.QuestionnaireItemType.Group, Item = new List <Questionnaire.ItemComponent>(), Repeats = false, }; #if false // 2020.05.13 - Argonaut extensions aren't valid in R4 yet section.AddExtension( "http://fhir.org/guides/argonaut/questionnaire/StructureDefinition/extension-itemOrder", new FhirDecimal(sectionNumber)); #endif if (format.Fields.ContainsKey(questionnaireSection.Title)) { section.Text = $"{format.Fields[questionnaireSection.Title].Title}: {format.Fields[questionnaireSection.Title].Description}"; } else { section.Text = questionnaireSection.Title; } foreach (QuestionnaireQuestion question in questionnaireSection.Fields) { Questionnaire.ItemComponent component = ComponentFromQuestion( format, question, ref itemNumber); if (component == null) { continue; } section.Item.Add(component); } questionnaire.Item.Add(section); } return(questionnaire); }
/// <summary>Component from question.</summary> /// <param name="format"> Describes the format to use.</param> /// <param name="question"> The question.</param> /// <param name="itemOrder">[in,out] The item order.</param> /// <returns>A Questionnaire.ItemComponent.</returns> private static Questionnaire.ItemComponent ComponentFromQuestion( IReportingFormat format, QuestionnaireQuestion question, ref int itemOrder) { if (!format.Fields.ContainsKey(question.ValueFieldName)) { return(null); } FormatField valueField = format.Fields[question.ValueFieldName]; FormatField displayField; if (string.IsNullOrEmpty(question.DisplayFieldName) || (!format.Fields.ContainsKey(question.DisplayFieldName))) { displayField = valueField; } else { displayField = format.Fields[question.DisplayFieldName]; } Questionnaire.ItemComponent component = new Questionnaire.ItemComponent() { LinkId = valueField.Name, Required = valueField.IsRequired == true, Repeats = false, }; if (!string.IsNullOrEmpty(question.FieldSystem)) { component.Code = new List <Coding>() { new Coding(question.FieldSystem, valueField.Name), }; } #if false // 2020.05.13 - Argonaut extensions aren't valid in R4 yet component.AddExtension( "http://fhir.org/guides/argonaut/questionnaire/StructureDefinition/extension-itemOrder", new FhirDecimal(itemOrder++)); #endif if (question.UseTitleOnly) { component.Text = $"{displayField.Title}"; } else { component.Text = $"{displayField.Title}: {displayField.Description}"; } int optionOrder = 0; switch (valueField.Type) { case FormatField.FieldType.Date: component.Type = Questionnaire.QuestionnaireItemType.Date; break; case FormatField.FieldType.Count: component.Type = Questionnaire.QuestionnaireItemType.Integer; break; case FormatField.FieldType.Percentage: component.Type = Questionnaire.QuestionnaireItemType.Decimal; break; case FormatField.FieldType.Boolean: component.Type = Questionnaire.QuestionnaireItemType.Boolean; break; case FormatField.FieldType.Choice: component.Type = Questionnaire.QuestionnaireItemType.Choice; component.AnswerOption = new List <Questionnaire.AnswerOptionComponent>(); component.AddExtension( "http://hl7.org/fhir/StructureDefinition/questionnaire-optionExclusive", new FhirBoolean(true), true); foreach (FormatFieldOption option in valueField.Options) { Element element = new FhirString(option.Text); #if false // 2020.05.13 - Argonaut extensions aren't valid in R4 yet element.AddExtension( "http://fhir.org/guides/argonaut/questionnaire/StructureDefinition/extension-itemOrder", new FhirDecimal(optionOrder++)); #endif component.AnswerOption.Add(new Questionnaire.AnswerOptionComponent() { Value = element, }); } break; case FormatField.FieldType.MultiSelectChoice: component.Type = Questionnaire.QuestionnaireItemType.Choice; component.AnswerOption = new List <Questionnaire.AnswerOptionComponent>(); foreach (FormatFieldOption option in valueField.Options) { Element element = new FhirString(option.Text); #if false // 2020.05.13 - Argonaut extensions aren't valid in R4 yet element.AddExtension( "http://fhir.org/guides/argonaut/questionnaire/StructureDefinition/extension-itemOrder", new FhirDecimal(optionOrder++)); #endif component.AnswerOption.Add(new Questionnaire.AnswerOptionComponent() { Value = element, }); } break; case FormatField.FieldType.Text: component.Type = Questionnaire.QuestionnaireItemType.Text; break; case FormatField.FieldType.ShortString: component.Type = Questionnaire.QuestionnaireItemType.String; break; case FormatField.FieldType.Display: default: component.Type = Questionnaire.QuestionnaireItemType.Display; break; } return(component); }
private static IEnumerable <MissingValidationIssue> VerifyOptionsReferenceExists(Questionnaire questionnaire, Questionnaire.ItemComponent item) { if (item.Type != Questionnaire.QuestionnaireItemType.Choice && item.Type != Questionnaire.QuestionnaireItemType.OpenChoice) { return(new MissingValidationIssue[0]); } if (item.Options == null) { return(new MissingValidationIssue[0]); } var issues = new List <MissingValidationIssue>(); if (!questionnaire.HasContainedValueSet(item.Options)) { issues.Add(new MissingValidationIssue { LinkId = item.LinkId, Severity = MissingValidationSeverityEnum.Error, Details = $"Cannot find the reference to ValueSet {item.Options?.Reference}" }); } return(issues); }
public static IEnumerable <MissingValidationIssue> VerifyItemValidation(this Questionnaire questionnaire, Questionnaire.ItemComponent item) { EnsureArg.IsNotNull(item, nameof(item)); var issues = new List <MissingValidationIssue>(); issues.AddRange(VerifyStringAndTextValidation(item)); issues.AddRange(VerifyRepeatingItemValidation(item)); issues.AddRange(VerifyMaxOrMinValueIsSet(item)); issues.AddRange(VerifyAttachmentValidation(item)); issues.AddRange(VerifyOptionsReferenceExists(questionnaire, item)); foreach (Questionnaire.ItemComponent itm in item.Item) { issues.AddRange(questionnaire.VerifyItemValidation(itm)); } return(issues); }
private static IEnumerable <MissingValidationIssue> VerifyStringAndTextValidation(Questionnaire.ItemComponent item) { if ((item.Type != Questionnaire.QuestionnaireItemType.String && item.Type != Questionnaire.QuestionnaireItemType.Text) || !item.IsItemControlOfType("help", "help-link", "inline")) { return(new MissingValidationIssue[0]); } // If this is a read-only field and it contains a fhirpath for data extraction do not suggest any validation if (item.ReadOnly == true && item.GetExtensions(Constants.FhirPathUri).Any()) { return(new MissingValidationIssue[0]); } var issues = new List <MissingValidationIssue>(); // Issues an error if a maxLength has NOT been set if (!item.MaxLength.HasValue) { issues.Add(new MissingValidationIssue { LinkId = item.LinkId, Severity = MissingValidationSeverityEnum.Error, Details = $"An item of type '{item.Type}' must have the 'maxLength' attribute set." }); } // Issues an error if a regex has NOT been set if (item.GetExtensions(Constants.RegexUri).Count() == 0) { issues.Add(new MissingValidationIssue { LinkId = item.LinkId, Severity = MissingValidationSeverityEnum.Error, Details = $"An item of type '{item.Type}' must have the 'regex' attribute set." }); } if (item.Type == Questionnaire.QuestionnaireItemType.String) { // Issues an error for ItemType == 'string' if a maxLength of no more than 250 characters has been set. if (item.MaxLength.HasValue && item.MaxLength.Value > 250) { issues.Add(new MissingValidationIssue { LinkId = item.LinkId, Severity = MissingValidationSeverityEnum.Error, Details = $"An item of type '{item.Type}' must have a 'maxLength' of no more than 250 characters." }); } } if (item.Type == Questionnaire.QuestionnaireItemType.Text) { // Issues a warning for ItemType == 'text' if a maxLength of more than 2500 characters has been set. if (item.MaxLength.HasValue && item.MaxLength.Value > 2500) { issues.Add(new MissingValidationIssue { LinkId = item.LinkId, Severity = MissingValidationSeverityEnum.Warning, Details = $"Item field of '{item.Type}' has a 'maxLength' of more than 2500 characters. This is allowed, but not recommended." }); } } return(issues); }
private IList <Questionnaire> GetQuestionnairesFromFlatFileFormatV2(string path) { if (string.IsNullOrWhiteSpace(path)) { throw new ArgumentNullException(nameof(path)); } if (!File.Exists(path)) { throw new FileNotFoundException($"File not found: '{path}'", path); } IList <Questionnaire> questionnaires = new List <Questionnaire>(); var engine = new MasterDetailEngine <QuestionnaireHeader2, QuestionnaireItem2>(new MasterDetailSelector(RecordSelector)) { Encoding = new UTF8Encoding() }; MasterDetails <QuestionnaireHeader2, QuestionnaireItem2>[] masterDetails = engine.ReadFile(path); foreach (MasterDetails <QuestionnaireHeader2, QuestionnaireItem2> masterDetail in masterDetails) { _logger.LogDebug($"Questionnaire: {masterDetail.Master.Name} - {masterDetail.Master.Title}"); Questionnaire questionnaire = new Questionnaire { Meta = new Meta { Profile = new string[] { Constants.QuestionnaireProfileUri } }, Id = string.IsNullOrWhiteSpace(masterDetail.Master.Id) ? null : masterDetail.Master.Id, Url = string.IsNullOrWhiteSpace(masterDetail.Master.Url) ? null : masterDetail.Master.Url, Version = string.IsNullOrWhiteSpace(masterDetail.Master.Version) ? null : masterDetail.Master.Version, Name = string.IsNullOrWhiteSpace(masterDetail.Master.Name) ? null : masterDetail.Master.Name, Title = string.IsNullOrWhiteSpace(masterDetail.Master.Title) ? null : masterDetail.Master.Title, Status = string.IsNullOrWhiteSpace(masterDetail.Master.Status) ? null : EnumUtility.ParseLiteral <PublicationStatus>(masterDetail.Master.Status) }; if (!string.IsNullOrWhiteSpace(masterDetail.Master.Date)) { if (!DateUtility.IsValidFhirDateTime(masterDetail.Master.Date)) { throw new Exception($"The date {masterDetail.Master.Date} is not conforming to the expected format: 'yyyy-MM-dd'"); } questionnaire.DateElement = new FhirDateTime(masterDetail.Master.Date); } questionnaire.Publisher = string.IsNullOrWhiteSpace(masterDetail.Master.Publisher) ? null : masterDetail.Master.Publisher; questionnaire.Description = string.IsNullOrWhiteSpace(masterDetail.Master.Description) ? null : new Markdown(masterDetail.Master.Description); questionnaire.Purpose = string.IsNullOrWhiteSpace(masterDetail.Master.Purpose) ? null : new Markdown(masterDetail.Master.Purpose); if (!string.IsNullOrWhiteSpace(masterDetail.Master.ApprovalDate)) { if (!DateUtility.IsValidFhirDate(masterDetail.Master.ApprovalDate)) { throw new Exception($"The date {masterDetail.Master.ApprovalDate} is not conforming to the expected format: 'yyyy-MM-dd'"); } questionnaire.ApprovalDateElement = new Date(masterDetail.Master.ApprovalDate); } if (!string.IsNullOrWhiteSpace(masterDetail.Master.ApprovalDate)) { if (!DateUtility.IsValidFhirDate(masterDetail.Master.LastReviewDate)) { throw new Exception($"The date {masterDetail.Master.LastReviewDate} is not conforming to the expected format: 'yyyy-MM-dd'"); } questionnaire.LastReviewDateElement = new Date(masterDetail.Master.LastReviewDate); } questionnaire.Contact = string.IsNullOrWhiteSpace(masterDetail.Master.ContactName) ? null : new List <ContactDetail> { new ContactDetail { Name = masterDetail.Master.ContactName } }; questionnaire.Copyright = string.IsNullOrWhiteSpace(masterDetail.Master.Copyright) ? null : new Markdown(masterDetail.Master.Copyright); if (!string.IsNullOrWhiteSpace(masterDetail.Master.SubjectType)) { IList <ResourceType?> resourceTypes = new List <ResourceType?>(); string[] subjectTypes = masterDetail.Master.SubjectType.Split('|'); foreach (string subjectType in subjectTypes) { ResourceType?resourceType = EnumUtility.ParseLiteral <ResourceType>(subjectType); if (resourceType.HasValue) { resourceTypes.Add(resourceType); } } questionnaire.SubjectType = resourceTypes; } if (!string.IsNullOrWhiteSpace(masterDetail.Master.Language)) { questionnaire.Language = masterDetail.Master.Language; string displayName = CultureInfo.GetCultureInfo(LanguageCodeUtility.GetLanguageCode(questionnaire.Language))?.NativeName.UpperCaseFirstCharacter(); questionnaire.Meta.Tag.Add(new Coding("urn:ietf:bcp:47", questionnaire.Language, displayName == null ? string.Empty : displayName)); } if (!string.IsNullOrWhiteSpace(masterDetail.Master.UseContext)) { questionnaire.UseContext = ParseUsageContext(masterDetail.Master.UseContext); } if (!string.IsNullOrWhiteSpace(masterDetail.Master.Endpoint)) { questionnaire.SetExtension(Constants.EndPointUri, new ResourceReference(masterDetail.Master.Endpoint)); } if (!string.IsNullOrWhiteSpace(masterDetail.Master.AuthenticationRequirement)) { questionnaire.SetExtension(Constants.AuthenticationRequirementUri, new Coding(Constants.AuthenticationRequirementSystem, masterDetail.Master.AuthenticationRequirement)); } if (!string.IsNullOrWhiteSpace(masterDetail.Master.AccessibilityToResponse)) { questionnaire.SetExtension(Constants.AccessibilityToResponseUri, new Coding(Constants.AccessibilityToResponseSystem, masterDetail.Master.AccessibilityToResponse)); } if (!string.IsNullOrWhiteSpace(masterDetail.Master.CanBePerformedBy)) { questionnaire.SetExtension(Constants.CanBePerformedByUri, new Coding(Constants.CanBePerformedBySystem, masterDetail.Master.CanBePerformedBy)); } if (!string.IsNullOrWhiteSpace(masterDetail.Master.Discretion)) { questionnaire.SetExtension(Constants.DiscretionUri, new Coding(Constants.DiscretionSystem, masterDetail.Master.Discretion)); } if (masterDetail.Master.GeneratePdf.HasValue) { questionnaire.SetExtension(Constants.GeneratePdfUri, new FhirBoolean(masterDetail.Master.GeneratePdf.Value)); } else { questionnaire.SetExtension(Constants.GeneratePdfUri, new FhirBoolean(true)); } if (masterDetail.Master.GenerateNarrative.HasValue) { questionnaire.SetExtension(Constants.GenerateNarrativeUri, new FhirBoolean(masterDetail.Master.GenerateNarrative.Value)); } else { questionnaire.SetExtension(Constants.GenerateNarrativeUri, new FhirBoolean(true)); } if (!string.IsNullOrWhiteSpace(masterDetail.Master.PresentationButtons)) { questionnaire.SetExtension(Constants.PresentationButtonsUri, new Coding(Constants.PresentationButtonsSystem, masterDetail.Master.PresentationButtons)); } else { questionnaire.SetExtension(Constants.PresentationButtonsUri, new Coding(Constants.PresentationButtonsSystem, "sticky")); } if (!string.IsNullOrWhiteSpace(masterDetail.Master.Code)) { questionnaire.Code = ParseArrayOfCoding(masterDetail.Master.Code); } if (!string.IsNullOrWhiteSpace(masterDetail.Master.QuestionaireNavigatorState)) { questionnaire.SetExtension(Constants.QuestionaireNavigatorStateUri, new CodeableConcept { Coding = new List <Coding> { new Coding { System = Constants.NavigatorStateSystem, Code = masterDetail.Master.QuestionaireNavigatorState, } } }); } if (!string.IsNullOrWhiteSpace(masterDetail.Master.QuestionnairePrintVersionReference)) { questionnaire.SetExtension(Constants.QuestionnairePrintVersionUri, new ResourceReference(masterDetail.Master.QuestionnairePrintVersionReference)); } IList <string> linkIds = new List <string>(); Questionnaire.ItemComponent item = null; for (int i = 0; i < masterDetail.Details.Length; i++) { QuestionnaireItem2 questionnaireItem = masterDetail.Details[i]; if (linkIds.IndexOf(questionnaireItem.LinkId) > 0) { throw new DuplicateLinkIdException(questionnaireItem.LinkId); } _logger.LogDebug($"Questionnaire Item: {questionnaireItem.LinkId} - {questionnaireItem.Type} - {questionnaireItem.Text}"); int level = questionnaireItem.LinkId.Split('.').Length - 1; if (level > 0) { // item could be null if a line in the .txt-file is empty or blank if (item == null) { continue; } i = DiveV2(i, level, item.Item, masterDetail.Details); } else { item = CreateItemComponentV2(questionnaireItem); questionnaire.Item.Add(item); } } questionnaires.Add(questionnaire); } return(questionnaires); }
private static Questionnaire.ItemComponent CreateItemComponentV1(QuestionnaireItem item) { Questionnaire.QuestionnaireItemType?itemType = EnumUtility.ParseLiteral <Questionnaire.QuestionnaireItemType>(item.Type); if (!itemType.HasValue) { throw new Exception($"QuestionnaireItemType at question with linkId: {item.LinkId} is not conforming to any valid literals. QuestionnaireItemType: {item.Type}"); } Questionnaire.ItemComponent itemComponent = new Questionnaire.ItemComponent { Type = itemType, }; itemComponent.LinkId = string.IsNullOrWhiteSpace(item.LinkId) ? null : item.LinkId; itemComponent.Prefix = string.IsNullOrWhiteSpace(item.Prefix) ? null : item.Prefix; itemComponent.Text = string.IsNullOrWhiteSpace(item.Text) ? null : item.Text; if (!string.IsNullOrWhiteSpace(item.EnableWhen)) { itemComponent.EnableWhen = ParseEnableWhen(item.EnableWhen).ToList(); // TODO: Defaults to 'any' in the first iteration of "migrate to R4". itemComponent.EnableBehavior = Questionnaire.EnableWhenBehavior.Any; } if (itemType != Questionnaire.QuestionnaireItemType.Group && itemType != Questionnaire.QuestionnaireItemType.Display) { itemComponent.Required = item.Required.HasValue ? item.Required : null; itemComponent.ReadOnly = item.ReadOnly; itemComponent.Initial = string.IsNullOrEmpty(item.Initial) ? null : new List <Questionnaire.InitialComponent> { new Questionnaire.InitialComponent { Value = GetElement(itemType.Value, item.Initial) } }; } if (itemType != Questionnaire.QuestionnaireItemType.Display) { itemComponent.Repeats = item.Repeats; } if (!string.IsNullOrWhiteSpace(item.ValidationText)) { itemComponent.SetStringExtension(Constants.ValidationTextUri, item.ValidationText); } if (!string.IsNullOrWhiteSpace(item.ReferenceValue) && item.ReferenceValue.IndexOf('#') == 0) { itemComponent.AnswerValueSetElement = new Canonical($"#{item.ReferenceValue.Substring(1)}"); } if (!string.IsNullOrWhiteSpace(item.EntryFormat)) { itemComponent.SetStringExtension(Constants.EntryFormatUri, item.EntryFormat); } if (item.MaxValue.HasValue) { itemComponent.SetIntegerExtension(Constants.MaxValueUri, item.MaxValue.Value); } if (item.MinValue.HasValue) { itemComponent.SetIntegerExtension(Constants.MinValueUri, item.MinValue.Value); } return(itemComponent); }
private IList <Questionnaire> GetQuestionnairesFromFlatFileFormatV1(string path) { if (string.IsNullOrWhiteSpace(path)) { throw new ArgumentNullException(nameof(path)); } if (!File.Exists(path)) { throw new FileNotFoundException($"File not found: '{path}'", path); } IList <Questionnaire> questionnaires = new List <Questionnaire>(); var engine = new MasterDetailEngine <QuestionnaireHeader, QuestionnaireItem>(new MasterDetailSelector(RecordSelector)) { Encoding = new UTF8Encoding() }; MasterDetails <QuestionnaireHeader, QuestionnaireItem>[] masterDetails = engine.ReadFile(path); foreach (MasterDetails <QuestionnaireHeader, QuestionnaireItem> masterDetail in masterDetails) { _logger.LogDebug($"Questionnaire: {masterDetail.Master.Name} - {masterDetail.Master.Title}"); Questionnaire questionnaire = new Questionnaire(); questionnaire.Meta = new Meta { Profile = new string[] { "http://ehelse.no/fhir/StructureDefinition/sdf-Questionnaire" } }; questionnaire.Id = string.IsNullOrWhiteSpace(masterDetail.Master.Id) ? null : masterDetail.Master.Id; questionnaire.Url = string.IsNullOrWhiteSpace(masterDetail.Master.Url) ? null : masterDetail.Master.Url; questionnaire.Version = string.IsNullOrWhiteSpace(masterDetail.Master.Version) ? null : masterDetail.Master.Version; questionnaire.Name = string.IsNullOrWhiteSpace(masterDetail.Master.Name) ? null : masterDetail.Master.Name; questionnaire.Title = string.IsNullOrWhiteSpace(masterDetail.Master.Title) ? null : masterDetail.Master.Title; questionnaire.Status = string.IsNullOrWhiteSpace(masterDetail.Master.Status) ? null : EnumUtility.ParseLiteral <PublicationStatus>(masterDetail.Master.Status); questionnaire.Date = string.IsNullOrWhiteSpace(masterDetail.Master.Date) ? null : masterDetail.Master.Date; questionnaire.Publisher = string.IsNullOrWhiteSpace(masterDetail.Master.Publisher) ? null : masterDetail.Master.Publisher; questionnaire.Description = string.IsNullOrWhiteSpace(masterDetail.Master.Description) ? null : new Markdown(masterDetail.Master.Description); questionnaire.Purpose = string.IsNullOrWhiteSpace(masterDetail.Master.Purpose) ? null : new Markdown(masterDetail.Master.Purpose); questionnaire.Contact = string.IsNullOrWhiteSpace(masterDetail.Master.Contact) ? null : new List <ContactDetail> { new ContactDetail { Telecom = new List <ContactPoint> { new ContactPoint { System = ContactPoint.ContactPointSystem.Url, Value = masterDetail.Master.Contact } } } }; if (!string.IsNullOrWhiteSpace(masterDetail.Master.Language)) { questionnaire.Language = masterDetail.Master.Language; // TODO: Vi trenger definere Visningsnavn for språket, eksempelvis: Norsk (bokmål), osv. questionnaire.Meta.Tag.Add(new Coding("urn:ietf:bcp:47", questionnaire.Language)); } IList <string> linkIds = new List <string>(); Questionnaire.ItemComponent item = null; for (int i = 0; i < masterDetail.Details.Length; i++) { QuestionnaireItem questionnaireItem = masterDetail.Details[i]; if (linkIds.IndexOf(questionnaireItem.LinkId) > 0) { throw new DuplicateLinkIdException(questionnaireItem.LinkId); } _logger.LogDebug($"Questionnaire Item: {questionnaireItem.LinkId} - {questionnaireItem.Type} - {questionnaireItem.Text}"); int level = questionnaireItem.LinkId.Split('.').Length - 1; if (level > 0) { i = DiveV1(i, level, item.Item, masterDetail.Details); } else { item = CreateItemComponentV1(questionnaireItem); questionnaire.Item.Add(item); } } questionnaires.Add(questionnaire); } return(questionnaires); }
private Questionnaire.ItemComponent CreateItemComponentV2(QuestionnaireItem2 item) { Questionnaire.QuestionnaireItemType?itemType = EnumUtility.ParseLiteral <Questionnaire.QuestionnaireItemType>(item.Type); if (!itemType.HasValue) { throw new Exception($"QuestionnaireItemType at question with linkId: {item.LinkId} is not conforming to any valid literals. QuestionnaireItemType: {item.Type}"); } Questionnaire.ItemComponent itemComponent = new Questionnaire.ItemComponent { Type = itemType, }; itemComponent.LinkId = string.IsNullOrWhiteSpace(item.LinkId) ? null : item.LinkId; itemComponent.Prefix = string.IsNullOrWhiteSpace(item.Prefix) ? null : item.Prefix; itemComponent.Text = string.IsNullOrWhiteSpace(item.Text) ? null : item.Text; if (!string.IsNullOrWhiteSpace(item.EnableWhen)) { itemComponent.EnableWhen = ParseEnableWhen(item.EnableWhen).ToList(); // TODO: Defaults to 'any' in the first iteration of "migrate to R4". itemComponent.EnableBehavior = Questionnaire.EnableWhenBehavior.Any; } if (itemType != Questionnaire.QuestionnaireItemType.Group && itemType != Questionnaire.QuestionnaireItemType.Display) { itemComponent.Required = item.Required.HasValue ? item.Required : null; itemComponent.ReadOnly = item.ReadOnly; itemComponent.Initial = string.IsNullOrEmpty(item.Initial) ? null : new List <Questionnaire.InitialComponent> { new Questionnaire.InitialComponent { Value = GetElement(itemType.Value, item.Initial) } }; itemComponent.MaxLength = item.MaxLength.HasValue ? item.MaxLength : null; } if (itemType != Questionnaire.QuestionnaireItemType.Display) { itemComponent.Repeats = item.Repeats; } if (!string.IsNullOrWhiteSpace(item.ValidationText)) { itemComponent.SetStringExtension(Constants.ValidationTextUri, item.ValidationText); } if (!string.IsNullOrWhiteSpace(item.Options) && item.Options.IndexOf('#') == 0) { itemComponent.AnswerValueSetElement = new Canonical($"#{item.Options.Substring(1)}"); } else if (!string.IsNullOrWhiteSpace(item.Options) && (item.Options.IndexOf("http://") == 0 || item.Options.IndexOf("https://") == 0)) { itemComponent.AnswerValueSetElement = new Canonical(item.Options); } if (!string.IsNullOrWhiteSpace(item.EntryFormat)) { itemComponent.SetStringExtension(Constants.EntryFormatUri, item.EntryFormat); } if (item.MaxValueInteger.HasValue) { itemComponent.SetIntegerExtension(Constants.MaxValueUri, item.MaxValueInteger.Value); } if (item.MinValueInteger.HasValue) { itemComponent.SetIntegerExtension(Constants.MinValueUri, item.MinValueInteger.Value); } if (item.MaxValueDate.HasValue) { itemComponent.SetExtension(Constants.MaxValueUri, new FhirDateTime(new DateTimeOffset(item.MaxValueDate.Value.ToUniversalTime()))); } if (item.MinValueDate.HasValue) { itemComponent.SetExtension(Constants.MinValueUri, new FhirDateTime(new DateTimeOffset(item.MinValueDate.Value.ToUniversalTime()))); } if (item.MinLength.HasValue) { itemComponent.SetIntegerExtension(Constants.MinLenghtUri, item.MinLength.Value); } if (item.MaxDecimalPlaces.HasValue) { itemComponent.SetIntegerExtension(Constants.MaxDecimalPlacesUri, item.MaxDecimalPlaces.Value); } if (!string.IsNullOrWhiteSpace(item.RepeatsText)) { itemComponent.SetStringExtension(Constants.RepeatsTextUri, item.RepeatsText); } if (!string.IsNullOrWhiteSpace(item.ItemControl)) { CodeableConcept codeableConcept = new CodeableConcept { Coding = new List <Coding> { new Coding { System = Constants.ItemControlSystem, Code = item.ItemControl } } }; itemComponent.SetExtension(Constants.ItemControlUri, codeableConcept); } if (item.MaxOccurs.HasValue) { itemComponent.SetIntegerExtension(Constants.MaxOccursUri, item.MaxOccurs.Value); } if (item.MinOccurs.HasValue) { itemComponent.SetIntegerExtension(Constants.MinOccursUri, item.MinOccurs.Value); } if (!string.IsNullOrWhiteSpace(item.Regex)) { itemComponent.SetStringExtension(Constants.RegexUri, item.Regex); } if (!string.IsNullOrWhiteSpace(item.Markdown)) { if (itemComponent.Text == null) { throw new MissingRequirementException($"Question with linkId: {item.LinkId}. The 'Text' attribute is required when setting the 'Markdown' extension so that form fillers which do not support the 'Markdown' extension still can display informative text to the user."); } itemComponent.TextElement.SetExtension(Constants.RenderingMarkdownUri, new Markdown(item.Markdown)); } if (!string.IsNullOrWhiteSpace(item.Unit)) { Coding unitCoding = ParseCoding(item.Unit); itemComponent.SetExtension(Constants.QuestionnaireUnitUri, unitCoding); } if (!string.IsNullOrWhiteSpace(item.Code)) { itemComponent.Code = ParseArrayOfCoding(item.Code); } if (!string.IsNullOrWhiteSpace(item.Option)) { List <Element> options = ParseArrayOfElement(item.Option); foreach (DataType element in options) { if (element is ResourceReference) { itemComponent.AddExtension(Constants.OptionReferenceUri, element); } else { itemComponent.AnswerOption.Add(new Questionnaire.AnswerOptionComponent { Value = element }); } } } if (!string.IsNullOrWhiteSpace(item.FhirPathExpression)) { itemComponent.SetStringExtension(Constants.FhirPathUri, item.FhirPathExpression); } if (item.Hidden) { itemComponent.SetBoolExtension(Constants.QuestionnaireItemHidden, item.Hidden); } if (item.AttachmentMaxSize.HasValue && itemComponent.Type == Questionnaire.QuestionnaireItemType.Attachment) { itemComponent.SetExtension(Constants.QuestionnaireAttachmentMaxSize, new FhirDecimal(item.AttachmentMaxSize)); } if (!string.IsNullOrWhiteSpace(item.CalculatedExpression)) { itemComponent.SetStringExtension(Constants.CalculatedExpressionUri, item.CalculatedExpression); } if (!string.IsNullOrWhiteSpace(item.GuidanceAction)) { itemComponent.SetStringExtension(Constants.GuidanceActionUri, item.GuidanceAction.Trim()); } if (!string.IsNullOrWhiteSpace(item.GuidanceParameter)) { itemComponent.SetStringExtension(Constants.GuidanceParameterUri, $"hn_frontend_{item.GuidanceParameter.Trim()}"); } if (!string.IsNullOrWhiteSpace(item.FhirPathValidation)) { itemComponent.SetStringExtension(Constants.FhirPathValidationUri, item.FhirPathValidation); } if (!string.IsNullOrWhiteSpace(item.FhirPathMaxValue)) { itemComponent.SetStringExtension(Constants.SdfMaxValueUri, item.FhirPathMaxValue); } if (!string.IsNullOrWhiteSpace(item.FhirPathMinValue)) { itemComponent.SetStringExtension(Constants.SdfMinValueUri, item.FhirPathMinValue); } if (!string.IsNullOrWhiteSpace(item.EnableBehavior)) { itemComponent.EnableBehavior = EnumUtility.ParseLiteral <Questionnaire.EnableWhenBehavior>(item.EnableBehavior.ToLowerInvariant()); } return(itemComponent); }