private string FindOrAddDataTypeTemplate(string dataTypeName)
        {
            string templateName = "dataType_" + dataTypeName;

            if (this.dataTypeTemplates.ContainsKey(dataTypeName))
            {
                return(templateName);
            }

            SimpleSchema.SchemaObject simpleComplexType = this.simpleSchema.ComplexTypes.SingleOrDefault(y => y.Name == dataTypeName);

            bool dataTypeDefined = this.tdb.ImplementationGuideTypeDataTypes.Count(y =>
                                                                                   y.ImplementationGuideTypeId == this.rootTemplate.ImplementationGuideTypeId &&
                                                                                   y.DataTypeName == dataTypeName) > 0;

            if (simpleComplexType == null || !dataTypeDefined)
            {
                return(string.Empty);
            }

            XmlElement dataTypeTemplate = TransformHelper.CreateXslTemplate(this.transformDoc, templateName, string.Empty);

            dataTypeTemplate.AppendChild(
                TransformHelper.CreateXsltTemplateParam(this.transformDoc, "instance"));

            CompleteDataTypeTemplate(dataTypeTemplate, simpleComplexType, "$instance");
            this.dataTypeTemplates.Add(dataTypeName, dataTypeTemplate);

            return(templateName);
        }
Пример #2
0
        public string GetConstraintDataType(DB.TemplateConstraint aConstraint, string aConstraintXpath)
        {
            var    templateType = aConstraint.Template.TemplateType;
            string context      = !string.IsNullOrEmpty(aConstraint.Template.PrimaryContextType) ?
                                  aConstraint.Template.PrimaryContextType : templateType.RootContextType;

            var schema = SimplifiedSchemaContext.GetSimplifiedSchema(HttpContext.Current.Application, templateType.ImplementationGuideType);

            schema = schema.GetSchemaFromContext(context);

            SimpleSchema.SchemaObject lSchemaObject = schema.FindFromPath(aConstraintXpath);
            return(lSchemaObject.DataType);
        }
Пример #3
0
        public void FindFromTypeTest()
        {
            string type = "IVL_TS";

            SimpleSchema.SchemaObject actual = this.cdaSchema.FindFromType(type);
            Assert.IsTrue(actual.Children.Exists(y => y.Name == "nullFlavor" && y.IsAttribute), "Could not find @nullFlavor attribute on IVL_TS");
            Assert.IsTrue(actual.Children.Exists(y => y.Name == "value" && y.IsAttribute), "Could not find @value attribute on IVL_TS");

            SimpleSchema.SchemaObject lowSchemaObject = actual.Children.SingleOrDefault(y => y.Name == "low" && !y.IsAttribute);
            Assert.IsNotNull(lowSchemaObject, "Could not find <low> within IVL_TS");
            Assert.IsTrue(lowSchemaObject.Children.Exists(y => y.Name == "nullFlavor" && y.IsAttribute), "Could now find low/@nullFlavor within IVL_TS");
            Assert.IsTrue(lowSchemaObject.Children.Exists(y => y.Name == "value" && y.IsAttribute), "Could now find low/@value within IVL_TS");
        }
Пример #4
0
        public void FindFromPathTest()
        {
            SimpleSchema.SchemaObject documentObj = this.cdaSchema.FindFromPath("ClinicalDocument[ClinicalDocument]");
            Assert.IsNotNull(documentObj, "FindFromPath should have returned a ClinicalDocument schema object.");
            Assert.AreNotEqual(0, documentObj.Children.Count, "Expected the ClinicalDocument schema object to have children.");

            SimpleSchema.SchemaObject idObj = this.cdaSchema.FindFromPath("ClinicalDocument[ClinicalDocument]/id[II]");
            Assert.IsNotNull(idObj, "FindFromPath should have returned an id schema object.");
            Assert.IsFalse(idObj.IsAttribute, "id schema object should not be an attribute.");

            // Should be able to find without specifying the types for each level
            SimpleSchema.SchemaObject rootObj = this.cdaSchema.FindFromPath("ClinicalDocument/id/@root");
            Assert.IsNotNull(rootObj, "FindFromPath should have returned a root schemaobject.");
            Assert.IsTrue(rootObj.IsAttribute, "Expected FindFromPath to return an attribute for @root.");

            // Should be able to find WITH specifying the types for each level
            rootObj = this.cdaSchema.FindFromPath("ClinicalDocument[ClinicalDocument]/id[II]/@root[uid]");
            Assert.IsNotNull(rootObj);
            Assert.IsTrue(rootObj.IsAttribute, "Expected FindFromPath to return an attribute for @root.");

            SimpleSchema.SchemaObject invalidObj = this.cdaSchema.FindFromPath("ClinicalDocument[ClinicalDocument]/test[test]");
            Assert.IsNull(invalidObj, "Expected not to find an element.");
        }
Пример #5
0
        public void FindFromTypeTest()
        {
            string type = "IVL_TS";

            SimpleSchema.SchemaObject actual = this.cdaSchema.FindFromType(type);
            Assert.IsTrue(actual.Children.Exists(y => y.Name == "nullFlavor" && y.IsAttribute), "Could not find @nullFlavor attribute on IVL_TS");
            Assert.IsTrue(actual.Children.Exists(y => y.Name == "value" && y.IsAttribute), "Could not find @value attribute on IVL_TS");

            /* TODO: Schema Choice support temporarily removed from non-FHIR schemas
             * var choiceSchemaObject = actual.Children.SingleOrDefault(y => y.Name == "choice" && y.IsChoice);
             * Assert.IsNotNull(choiceSchemaObject, "Expected to find a choice");
             *
             * SimpleSchema.SchemaObject lowSchemaObject = choiceSchemaObject.Children.SingleOrDefault(y => y.Name == "low" && !y.IsAttribute);
             * Assert.IsNotNull(lowSchemaObject, "Could not find <low> within IVL_TS");
             * Assert.IsTrue(lowSchemaObject.Children.Exists(y => y.Name == "nullFlavor" && y.IsAttribute), "Could now find low/@nullFlavor within IVL_TS");
             * Assert.IsTrue(lowSchemaObject.Children.Exists(y => y.Name == "value" && y.IsAttribute), "Could now find low/@value within IVL_TS");
             */

            SimpleSchema.SchemaObject lowSchemaObject = actual.Children.SingleOrDefault(y => y.Name == "low" && !y.IsAttribute);
            Assert.IsNotNull(lowSchemaObject, "Could not find <low> within IVL_TS");
            Assert.IsTrue(lowSchemaObject.Children.Exists(y => y.Name == "nullFlavor" && y.IsAttribute), "Could now find low/@nullFlavor within IVL_TS");
            Assert.IsTrue(lowSchemaObject.Children.Exists(y => y.Name == "value" && y.IsAttribute), "Could now find low/@value within IVL_TS");
        }
        private void CompleteDataTypeTemplate(XmlElement parent, SimpleSchema.SchemaObject simpleObject, string currentXpath)
        {
            foreach (SimpleSchema.SchemaObject cChildObject in simpleObject.Children)
            {
                if (cChildObject.Type == SimpleSchema.ObjectTypes.Attribute)
                {
                    string cAttributeName  = Helper.NormalizeName(cChildObject.Name);
                    string cAttributeXpath = !string.IsNullOrEmpty(currentXpath) ? currentXpath + "/@" + cAttributeName : "@" + cAttributeName;

                    XmlElement attributeIfEle = TransformHelper.CreateXsltIf(this.transformDoc, cAttributeXpath);
                    attributeIfEle.AppendChild(
                        TransformHelper.CreateXsltAttributeWithValueOf(this.transformDoc, cAttributeName, cAttributeXpath));

                    parent.AppendChild(attributeIfEle);
                }
                else if (cChildObject.Type == SimpleSchema.ObjectTypes.Element)
                {
                    string cChildXpath = !string.IsNullOrEmpty(currentXpath) ? currentXpath + "/" + cChildObject.Name : cChildObject.Name;

                    XmlElement newForeachEle   = TransformHelper.CreateXsltForEach(this.transformDoc, cChildXpath);
                    XmlElement newChildElement = TransformHelper.CreateXsltElement(this.transformDoc, cChildObject.Name);

                    CompleteDataTypeTemplate(newChildElement, cChildObject, string.Empty);

                    newForeachEle.AppendChild(newChildElement);
                    parent.AppendChild(newForeachEle);
                }
            }

            if (simpleObject.Mixed)
            {
                string     textXpath = !string.IsNullOrEmpty(currentXpath) ? currentXpath + "/text()" : "text()";
                XmlElement textValue = TransformHelper.CreateXsltValueOf(this.transformDoc, textXpath);
                parent.AppendChild(textValue);
            }
        }
        public StructureDefinition Convert(Template template, SimpleSchema schema, SummaryType?summaryType = null)
        {
            var fhirStructureDef = new fhir_stu3.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);
        }
        public void CreateElementDefinition(
            StructureDefinition strucDef,
            TemplateConstraint constraint,
            SimpleSchema.SchemaObject schemaObject)
        {
            if (constraint.IsPrimitive)     // Skip primitives (for now, at least)
            {
                return;
            }

            string sliceName           = constraint.GetSliceName();
            string elementPath         = constraint.GetElementPath(strucDef.Type != null ? strucDef.Type.ToString() : null);
            var    igSettings          = GetIGSettings(constraint);
            var    constraintFormatter = FormattedConstraintFactory.NewFormattedConstraint(this.tdb, igSettings, this.igTypePlugin, constraint);
            string definition          = constraintFormatter.GetPlainText(false, false, false);

            if (definition == null)
            {
                definition = string.Empty;
            }

            ElementDefinition newElementDef = new ElementDefinition()
            {
                Short      = !string.IsNullOrEmpty(constraint.Label) ? constraint.Label : constraint.Context,
                Label      = !string.IsNullOrEmpty(constraint.Label) ? constraint.Label : null,
                Comment    = !string.IsNullOrEmpty(constraint.Notes) ? constraint.Notes : null,
                Path       = elementPath,
                SliceName  = sliceName,
                Definition = definition,
                ElementId  = constraint.GetElementId()
            };

            if (constraint.IsChoice)
            {
                newElementDef.Slicing = new ElementDefinition.SlicingComponent();
                newElementDef.Slicing.Discriminator.Add(new ElementDefinition.DiscriminatorComponent()
                {
                    Type = ElementDefinition.DiscriminatorType.Type,
                    Path = "$this"
                });
                newElementDef.Slicing.Rules = ElementDefinition.SlicingRules.Open;
            }
            else if (constraint.Parent != null && constraint.Parent.IsChoice)
            {
                newElementDef.SliceName = constraint.Context;
            }

            // Cardinality
            if (!string.IsNullOrEmpty(constraint.Cardinality))
            {
                newElementDef.Min = constraint.CardinalityType.Left;
                newElementDef.Max = constraint.CardinalityType.Right == Cardinality.MANY ? "*" : constraint.CardinalityType.Right.ToString();
            }

            // Binding
            string valueConformance = string.IsNullOrEmpty(constraint.ValueConformance) ? constraint.Conformance : constraint.ValueConformance;
            bool   hasBinding       = constraint.References.Any(y => y.ReferenceType == ConstraintReferenceTypes.Template);

            if (constraint.ValueSet != null && valueConformance.IndexOf("NOT") < 0)
            {
                hasBinding            = true;
                newElementDef.Binding = new ElementDefinition.ElementDefinitionBindingComponent()
                {
                    ValueSet = new ResourceReference()
                    {
                        Reference = constraint.ValueSet.GetIdentifier(ValueSetIdentifierTypes.HTTP),
                        Display   = constraint.ValueSet.Name
                    }
                };

                if (valueConformance == "SHALL")
                {
                    newElementDef.Binding.Strength = BindingStrength.Required;
                }
                else if (valueConformance == "SHOULD")
                {
                    newElementDef.Binding.Strength = BindingStrength.Preferred;
                }
                else if (valueConformance == "MAY")
                {
                    newElementDef.Binding.Strength = BindingStrength.Example;
                }
            }

            // Single-Value Binding
            if (schemaObject != null && (!string.IsNullOrEmpty(constraint.Value) || !string.IsNullOrEmpty(constraint.DisplayName)))
            {
                Element elementBinding = null;

                hasBinding = true;
                switch (schemaObject.DataType)
                {
                case "CodeableConcept":
                    var codableConceptBinding = new CodeableConcept();
                    var coding = new Coding();
                    codableConceptBinding.Coding.Add(coding);

                    if (!string.IsNullOrEmpty(constraint.Value))
                    {
                        coding.Code = constraint.Value;
                    }

                    if (constraint.CodeSystem != null)
                    {
                        coding.System = constraint.CodeSystem.Oid;
                    }

                    if (!string.IsNullOrEmpty(constraint.DisplayName))
                    {
                        coding.Display = constraint.DisplayName;
                    }

                    elementBinding = codableConceptBinding;
                    break;

                case "Coding":
                    var codingBinding = new Coding();

                    if (!string.IsNullOrEmpty(constraint.Value))
                    {
                        codingBinding.Code = constraint.Value;
                    }

                    if (constraint.CodeSystem != null)
                    {
                        codingBinding.System = constraint.CodeSystem.Oid;
                    }

                    if (!string.IsNullOrEmpty(constraint.DisplayName))
                    {
                        codingBinding.Display = constraint.DisplayName;
                    }

                    elementBinding = codingBinding;
                    break;

                case "code":
                    var codeBinding = new Code();
                    codeBinding.Value = !string.IsNullOrEmpty(constraint.Value) ? constraint.Value : constraint.DisplayName;
                    elementBinding    = codeBinding;
                    break;

                default:
                    var stringBinding = new FhirString();
                    stringBinding.Value = !string.IsNullOrEmpty(constraint.Value) ? constraint.Value : constraint.DisplayName;
                    elementBinding      = stringBinding;
                    break;
                }

                if (constraint.IsFixed)
                {
                    newElementDef.Fixed = elementBinding;
                }
                else
                {
                    newElementDef.Pattern = elementBinding;
                }
            }

            // Add the type of the element when bound to a value set
            if (hasBinding && schemaObject != null && !string.IsNullOrEmpty(schemaObject.DataType))
            {
                StructureDefinition profile = GetBaseProfile(constraint.Template);
                newElementDef.Type = GetProfileDataTypes(profile, constraint);

                var containedTemplates = (from tcr in constraint.References
                                          join t in this.tdb.Templates on tcr.ReferenceIdentifier equals t.Oid
                                          where tcr.ReferenceType == ConstraintReferenceTypes.Template
                                          select new { Identifier = t.Oid, t.PrimaryContextType });

                // If there is a contained template/profile, make sure it supports a "Reference" type, and then output the profile identifier in the type
                if (containedTemplates.Count() > 0 && newElementDef.Type.Exists(y => y.Code == "Reference" || y.Code == "Extension"))
                {
                    if (!string.IsNullOrEmpty(newElementDef.SliceName))
                    {
                        var foundMatchingElement = strucDef.Differential.Element.SingleOrDefault(y => y.Path == newElementDef.Path && y.SliceName == newElementDef.SliceName);

                        if (foundMatchingElement != null)
                        {
                            foundMatchingElement.Definition += " " + definition;
                            newElementDef = foundMatchingElement;
                        }
                    }

                    var containedTypes = new List <ElementDefinition.TypeRefComponent>();
                    foreach (var containedTemplate in containedTemplates)
                    {
                        bool isExtension = containedTemplate.PrimaryContextType == "Extension" && newElementDef.Type.Exists(y => y.Code == "Extension");

                        containedTypes.Add(new ElementDefinition.TypeRefComponent()
                        {
                            Code          = isExtension ? "Extension" : "Reference",
                            Profile       = isExtension ? containedTemplate.Identifier : null,
                            TargetProfile = !isExtension ? containedTemplate.Identifier : null
                        });
                    }

                    newElementDef.Type = containedTypes;
                }
            }

            // Add the element to the list if it's new
            if (!strucDef.Differential.Element.Contains(newElementDef))
            {
                strucDef.Differential.Element.Add(newElementDef);
            }

            // Children
            foreach (var childConstraint in constraint.ChildConstraints.OrderBy(y => y.Order))
            {
                var childSchemaObject = schemaObject != null?schemaObject.Children.SingleOrDefault(y => y.Name == childConstraint.Context) : null;

                CreateElementDefinition(strucDef, childConstraint, childSchemaObject);
            }
        }
Пример #9
0
        private void AddTemplateTableConstraint(Template template, IEnumerable <ConstraintReference> templateReferences, Table table, TemplateConstraint constraint, int level, bool includeCategoryHeader, SimpleSchema.SchemaObject schemaObject)
        {
            // Skip the child constraints if this is a choice there is only one child constraint. This constraint
            // adopts the constraint narrative of the child constraint when there is only one option.
            if (constraint.IsChoice && constraint.ChildConstraints.Count == 1)
            {
                constraint = constraint.ChildConstraints.First();
            }

            if (constraint.IsPrimitive != true && !string.IsNullOrEmpty(constraint.Context))
            {
                string xpath          = constraint.Context;
                string cardinality    = constraint.Cardinality;
                string conformance    = constraint.Conformance;
                string dataType       = constraint.DataType;
                string fixedValue     = string.Empty;
                string fixedValueLink = string.Empty;
                string levelSpacing   = string.Empty;
                string confNumber     = template.OwningImplementationGuideId + "-" + constraint.Number.ToString();
                var    isFhir         = constraint.Template.ImplementationGuideType.SchemaURI == ImplementationGuideType.FHIR_NS;

                // Check if we're dealing with a FHIR constraint
                if (isFhir && schemaObject != null)
                {
                    dataType = schemaObject.DataType;
                }

                if (constraint.ValueSet != null)
                {
                    string valueSetIdentifier = constraint.ValueSet.GetIdentifier(igTypePlugin);
                    fixedValue = string.Format("{0} ({1})", valueSetIdentifier, constraint.ValueSet.Name);
                }
                else if (constraint.CodeSystem != null)
                {
                    fixedValue = string.Format("{0} ({1})", constraint.CodeSystem.Oid, constraint.CodeSystem.Name);
                }

                var constraintReferences = templateReferences.Where(y => y.TemplateConstraintId == constraint.Id);

                if (!string.IsNullOrEmpty(constraint.Value))
                {
                    if (!string.IsNullOrEmpty(fixedValue))
                    {
                        fixedValue += " = " + constraint.Value;
                    }
                    else
                    {
                        fixedValue = constraint.Value;
                    }
                }
                else if (constraintReferences.Count() > 0)
                {
                    var containedTemplateValues = constraintReferences.Select(y => string.Format("{0} (identifier: {1}", y.Name, y.Identifier));
                    fixedValue = string.Join(" or ", containedTemplateValues);

                    var firstConstraintReference = constraintReferences.First();

                    if (constraintReferences.Count() == 1 && firstConstraintReference.IncludedInIG)
                    {
                        fixedValueLink = firstConstraintReference.Bookmark;
                    }
                }

                for (int i = 1; i <= (level); i++)      // One tab for each level
                {
                    levelSpacing += "\t";
                }

                TableRow entryRow = new TableRow();

                if (includeCategoryHeader)
                {
                    AppendTextCell(entryRow, constraint.Category);
                }

                AppendTextCell(entryRow, levelSpacing + xpath);
                AppendTextCell(entryRow, cardinality);
                AppendTextCell(entryRow, conformance);
                AppendTextCell(entryRow, dataType);
                AppendHyperlinkCell(entryRow, confNumber, "C_" + confNumber);

                if (!string.IsNullOrEmpty(fixedValueLink))
                {
                    AppendHyperlinkCell(entryRow, fixedValue, fixedValueLink);
                }
                else
                {
                    AppendTextCell(entryRow, fixedValue);
                }

                table.AppendChild(entryRow);
            }

            // Recursively handle child constraints
            var childConstraints = template.ChildConstraints
                                   .Where(y => y.ParentConstraintId == constraint.Id)
                                   .OrderBy(y => y.Order);

            foreach (TemplateConstraint cConstraint in childConstraints)
            {
                if (this.HasSelectedCategories && !string.IsNullOrEmpty(cConstraint.Category) && !this.selectedCategories.Contains(cConstraint.Category))
                {
                    continue;
                }

                var nextSchemaObject = schemaObject != null?
                                       schemaObject.Children.SingleOrDefault(y => y.Name == cConstraint.Context) :
                                           null;

                this.AddTemplateTableConstraint(template, templateReferences, table, cConstraint, level + 1, includeCategoryHeader, nextSchemaObject);
            }
        }
        public void CreateElementDefinition(
            StructureDefinition strucDef,
            TemplateConstraint constraint,
            SimpleSchema.SchemaObject schemaObject,
            string sliceName = null)
        {
            if (constraint.IsPrimitive)     // Skip primitives (for now, at least)
            {
                return;
            }

            string newSliceName = null;

            if (constraint.IsBranch)
            {
                newSliceName = string.Format("{0}_slice_pos{1}", constraint.Context, constraint.Order);
            }

            var igSettings          = GetIGSettings(constraint);
            var constraintFormatter = FormattedConstraintFactory.NewFormattedConstraint(this.tdb, igSettings, this.igTypePlugin, constraint);

            ElementDefinition newElementDef = new ElementDefinition()
            {
                Short      = !string.IsNullOrEmpty(constraint.Label) ? constraint.Label : constraint.Context,
                Label      = !string.IsNullOrEmpty(constraint.Label) ? constraint.Label : null,
                Comments   = !string.IsNullOrEmpty(constraint.Notes) ? constraint.Notes : null,
                Path       = constraint.GetElementPath(strucDef.ConstrainedType),
                Name       = constraint.IsBranch ? newSliceName : sliceName,
                Definition = constraintFormatter.GetPlainText(false, false, false)
            };

            // Cardinality
            if (!string.IsNullOrEmpty(constraint.Cardinality))
            {
                newElementDef.Min = constraint.CardinalityType.Left;
                newElementDef.Max = constraint.CardinalityType.Right == Cardinality.MANY ? "*" : constraint.CardinalityType.Right.ToString();
            }

            // Binding
            string valueConformance = string.IsNullOrEmpty(constraint.ValueConformance) ? constraint.Conformance : constraint.ValueConformance;
            bool   hasBinding       = constraint.References.Any(y => y.ReferenceType == ConstraintReferenceTypes.Template);

            if (constraint.ValueSet != null && valueConformance.IndexOf("NOT") < 0)
            {
                hasBinding            = true;
                newElementDef.Binding = new ElementDefinition.ElementDefinitionBindingComponent()
                {
                    ValueSet = new ResourceReference()
                    {
                        Reference = string.Format("ValueSet/{0}", constraint.ValueSet.Id),
                        Display   = constraint.ValueSet.Name
                    }
                };

                if (valueConformance == "SHALL")
                {
                    newElementDef.Binding.Strength = BindingStrength.Required;
                }
                else if (valueConformance == "SHOULD")
                {
                    newElementDef.Binding.Strength = BindingStrength.Preferred;
                }
                else if (valueConformance == "MAY")
                {
                    newElementDef.Binding.Strength = BindingStrength.Example;
                }
            }

            // Single-Value Binding
            if (schemaObject != null && (!string.IsNullOrEmpty(constraint.Value) || !string.IsNullOrEmpty(constraint.DisplayName)))
            {
                hasBinding = true;
                switch (schemaObject.DataType)
                {
                case "CodeableConcept":
                    var fixedCodeableConcept = new CodeableConcept();
                    var coding = new Coding();
                    fixedCodeableConcept.Coding.Add(coding);

                    if (!string.IsNullOrEmpty(constraint.Value))
                    {
                        coding.Code = constraint.Value;
                    }

                    if (constraint.CodeSystem != null)
                    {
                        coding.System = constraint.CodeSystem.Oid;
                    }

                    if (!string.IsNullOrEmpty(constraint.DisplayName))
                    {
                        coding.Display = constraint.DisplayName;
                    }

                    newElementDef.Fixed = fixedCodeableConcept;
                    break;

                case "Coding":
                    var fixedCoding = new Coding();

                    if (!string.IsNullOrEmpty(constraint.Value))
                    {
                        fixedCoding.Code = constraint.Value;
                    }

                    if (constraint.CodeSystem != null)
                    {
                        fixedCoding.System = constraint.CodeSystem.Oid;
                    }

                    if (!string.IsNullOrEmpty(constraint.DisplayName))
                    {
                        fixedCoding.Display = constraint.DisplayName;
                    }

                    newElementDef.Fixed = fixedCoding;
                    break;

                case "code":
                    var fixedCode = new Code();
                    fixedCode.Value     = !string.IsNullOrEmpty(constraint.Value) ? constraint.Value : constraint.DisplayName;
                    newElementDef.Fixed = fixedCode;
                    break;

                default:
                    var fixedString = new FhirString();
                    fixedString.Value   = !string.IsNullOrEmpty(constraint.Value) ? constraint.Value : constraint.DisplayName;
                    newElementDef.Fixed = fixedString;
                    break;
                }
            }

            // Add the type of the element when bound to a value set
            if (hasBinding && schemaObject != null && !string.IsNullOrEmpty(schemaObject.DataType))
            {
                StructureDefinition profile = GetBaseProfile(constraint.Template);
                newElementDef.Type = GetProfileDataTypes(profile, constraint);

                var containedTemplates = (from tcr in constraint.References
                                          join t in this.tdb.Templates on tcr.ReferenceIdentifier equals t.Oid
                                          where tcr.ReferenceType == ConstraintReferenceTypes.Template
                                          select new { Identifier = t.Oid, t.PrimaryContextType });

                // If there is a contained template/profile, make sure it supports a "Reference" type, and then output the profile identifier in the type
                if (containedTemplates.Count() > 0 && newElementDef.Type.Exists(y => y.Code == "Reference" || y.Code == "Extension"))
                {
                    var containedTypes = new List <ElementDefinition.TypeRefComponent>();
                    foreach (var containedTemplate in containedTemplates)
                    {
                        bool isExtension = containedTemplate.PrimaryContextType == "Extension" && newElementDef.Type.Exists(y => y.Code == "Extension");

                        containedTypes.Add(new ElementDefinition.TypeRefComponent()
                        {
                            Code    = isExtension ? "Extension" : "Reference",
                            Profile = new List <string>(new string[] { containedTemplate.Identifier })
                        });
                    }

                    newElementDef.Type = containedTypes;
                }
            }

            // Add the element to the list
            strucDef.Differential.Element.Add(newElementDef);

            // Children
            foreach (var childConstraint in constraint.ChildConstraints.OrderBy(y => y.Order))
            {
                var childSchemaObject = schemaObject != null?schemaObject.Children.SingleOrDefault(y => y.Name == childConstraint.Context) : null;

                CreateElementDefinition(strucDef, childConstraint, childSchemaObject, newSliceName);
            }
        }
Пример #11
0
        /// <summary>
        /// Perform validations on a single constraint.
        /// </summary>
        /// <param name="results">The list of errors that should be added to when a constraint has an error matching the schema</param>
        /// <param name="schemaObjects">The list of sibling-level schema objects that the constraint should be compared to</param>
        /// <param name="currentConstraint">The current constraint to match against the schema</param>
        public void ValidateTemplateConstraint(
            Template template,
            XPathNavigator xpathNavigator,
            List <ValidationResult> results,
            SimpleSchema schema,
            List <SimpleSchema.SchemaObject> schemaObjects,
            TemplateConstraint currentConstraint,
            IEnumerable <Template> allContainedTemplates)
        {
            List <TemplateConstraint> childConstraints = currentConstraint.ChildConstraints.ToList();

            if (!string.IsNullOrEmpty(currentConstraint.Schematron))
            {
                try
                {
                    XPathExpression expr = xpathNavigator.Compile(currentConstraint.Schematron);
                }
                catch (XPathException ex)
                {
                    results.Add(ValidationResult.CreateResult(template.Id, template.Name, currentConstraint.Number.Value, ValidationLevels.Error, "Custom schematron is not valid: " + ex.Message));
                }
            }

            if (currentConstraint.IsPrimitive && string.IsNullOrEmpty(currentConstraint.PrimitiveText))
            {
                results.Add(ValidationResult.CreateResult(template.Id, template.Name, currentConstraint.Number.Value, ValidationLevels.Error, "Primitive does not have any narrative text."));
                return;
            }
            else if (!string.IsNullOrEmpty(currentConstraint.Context))
            {
                string context     = currentConstraint.Context;
                bool   isAttribute = context.StartsWith("@");

                // If it is an attribute, then we need to remove the @ from the context
                if (isAttribute)
                {
                    context = context.Substring(1);
                }

                SimpleSchema.SchemaObject foundSchemaObject = schemaObjects.SingleOrDefault(y => y.Name.ToLower() == context.ToLower() && y.IsAttribute == isAttribute);

                // Verify that the template (if specified) matches the datatype of the constraints
                if (foundSchemaObject != null)
                {
                    var templates          = allContainedTemplates != null ? allContainedTemplates : this.tdb.Templates.AsEnumerable();
                    var containedTemplates = (from tcr in currentConstraint.References
                                              join t in templates on tcr.ReferenceIdentifier equals t.Oid
                                              where tcr.ReferenceType == ConstraintReferenceTypes.Template
                                              select t);
                    string constraintDataType = !string.IsNullOrEmpty(currentConstraint.DataType) ? currentConstraint.DataType : foundSchemaObject.DataType;

                    foreach (var containedTemplate in containedTemplates)
                    {
                        string containedTemplateDataType = containedTemplate.PrimaryContextType;

                        bool isFhirResourceReference = schema.Schema.TargetNamespace == "http://hl7.org/fhir" && (constraintDataType == "ResourceReference" || constraintDataType == "Reference");

                        if (!isFhirResourceReference && containedTemplateDataType.ToLower() != constraintDataType.ToLower())
                        {
                            results.Add(ValidationResult.CreateResult(
                                            template.Id,
                                            template.Name,
                                            currentConstraint.Number.Value,
                                            ValidationLevels.Error,
                                            "Contained template \"{0}\" has a type of \"{1}\" which does not match the containing element \"{2}\"",
                                            containedTemplate.Oid,
                                            containedTemplateDataType,
                                            constraintDataType));
                        }
                    }
                }

                // Verify that branched elements have at least one identifier
                if (currentConstraint.IsBranch && childConstraints.Count(y => y.IsBranchIdentifier) == 0)
                {
                    results.Add(ValidationResult.CreateResult(template.Id, template.Name, currentConstraint.Number.Value, ValidationLevels.Warning, "Branched constraint \"{0}\" does not have any identifiers associated with it.", currentConstraint.GetXpath()));
                }

                // Verify that a schema-object can be matched to this constraint
                if (foundSchemaObject == null)
                {
                    results.Add(ValidationResult.CreateResult(template.Id, template.Name, currentConstraint.Number.Value, ValidationLevels.Error, "Constraint has context of \"{0}\" which is not found in the schema.", currentConstraint.GetXpath()));
                    return; // Do not process child constraints when the parent is not matched to the schema
                }
                else if (foundSchemaObject.Cardinality != null && currentConstraint.Cardinality != null)
                {
                    var siblings    = currentConstraint.ParentConstraint != null ? currentConstraint.ParentConstraint.ChildConstraints : template.ChildConstraints.Where(y => y.ParentConstraint == null);
                    var isDuplicate = siblings.Count(y => y.Context == currentConstraint.Context) > 1;

                    // Warn when a constraint that is associated with the schema that has multiple cardinality but is not branched
                    if (template.IsOpen &&
                        !foundSchemaObject.Cardinality.EndsWith("..1") &&
                        !foundSchemaObject.Cardinality.EndsWith("..0") &&
                        !currentConstraint.IsBranch &&
                        isDuplicate)
                    {
                        var error = ValidationResult.CreateResult(template.Id, template.Name, currentConstraint.Number.Value, ValidationLevels.Warning, "Schema allows multiple for \"{0}\" but the constraint is not branched. Consider branching this constraint.", currentConstraint.GetXpath());
                        results.Add(error);
                    }

                    if (foundSchemaObject.Cardinality.EndsWith("..1") && !(currentConstraint.Cardinality.EndsWith("..0") || currentConstraint.Cardinality.EndsWith("..1")))
                    {
                        var error = ValidationResult.CreateResult(template.Id, template.Name, currentConstraint.Number.Value, ValidationLevels.Error, "The cardinality for the element is loosened in the constraint from the underlying schema.");
                        results.Add(error);
                    }
                }

                List <SimpleSchema.SchemaObject> childSchemaObjects = foundSchemaObject.Children;

                // If a data-type is specified, then we should find the data-type within the schema, since it is likely different than what
                // is specified by default.
                if (!string.IsNullOrEmpty(currentConstraint.DataType))
                {
                    SimpleSchema.SchemaObject foundSchemaTypeObject = schema.FindFromType(currentConstraint.DataType);

                    if (foundSchemaTypeObject != null)
                    {
                        childSchemaObjects = foundSchemaTypeObject.Children;
                    }
                }

                childConstraints.ForEach(y => ValidateTemplateConstraint(template, xpathNavigator, results, schema, childSchemaObjects, y, allContainedTemplates));
            }
        }
Пример #12
0
        private void AddTemplateTableConstraint(Template template, Table table, TemplateConstraint constraint, int level, bool includeCategoryHeader, SimpleSchema.SchemaObject schemaObject)
        {
            if (constraint.IsPrimitive != true && !string.IsNullOrEmpty(constraint.Context))
            {
                string xpath          = constraint.Context;
                string cardinality    = constraint.Cardinality;
                string conformance    = constraint.Conformance;
                string dataType       = constraint.DataType;
                string fixedValue     = string.Empty;
                string fixedValueLink = string.Empty;
                string levelSpacing   = string.Empty;
                string confNumber     = constraint.GetFormattedNumber(this.igSettings.PublishDate);
                var    isFhir         = constraint.Template.ImplementationGuideType.SchemaURI == ImplementationGuideType.FHIR_NS;

                // Check if we're dealing with a FHIR constraint
                if (isFhir && schemaObject != null)
                {
                    dataType = schemaObject.DataType;
                }

                if (constraint.ValueSet != null)
                {
                    fixedValue = string.Format("{0} ({1})", constraint.ValueSet.Oid, constraint.ValueSet.Name);
                }
                else if (constraint.CodeSystem != null)
                {
                    fixedValue = string.Format("{0} ({1})", constraint.CodeSystem.Oid, constraint.CodeSystem.Name);
                }

                if (!string.IsNullOrEmpty(constraint.Value))
                {
                    if (!string.IsNullOrEmpty(fixedValue))
                    {
                        fixedValue += " = " + constraint.Value;
                    }
                    else
                    {
                        fixedValue = constraint.Value;
                    }
                }
                else if (constraint.ContainedTemplate != null)
                {
                    fixedValue = string.Format("{0} (identifier: {1}", constraint.ContainedTemplate.Name, constraint.ContainedTemplate.Oid);
                    if (this.templates.Contains(constraint.ContainedTemplate))
                    {
                        fixedValueLink = constraint.ContainedTemplate.Bookmark;
                    }
                }

                for (int i = 1; i <= (level); i++)      // One tab for each level
                {
                    levelSpacing += "\t";
                }

                TableRow entryRow = new TableRow();

                if (includeCategoryHeader)
                {
                    AppendTextCell(entryRow, constraint.Category);
                }

                AppendTextCell(entryRow, levelSpacing + xpath);
                AppendTextCell(entryRow, cardinality);
                AppendTextCell(entryRow, conformance);
                AppendTextCell(entryRow, dataType);
                AppendHyperlinkCell(entryRow, confNumber, "C_" + confNumber);

                if (!string.IsNullOrEmpty(fixedValueLink))
                {
                    AppendHyperlinkCell(entryRow, fixedValue, fixedValueLink);
                }
                else
                {
                    AppendTextCell(entryRow, fixedValue);
                }

                table.AppendChild(entryRow);
            }

            // Recursively handle child constraints
            var childConstraints = template.ChildConstraints
                                   .Where(y => y.ParentConstraintId == constraint.Id)
                                   .OrderBy(y => y.Order);

            foreach (TemplateConstraint cConstraint in childConstraints)
            {
                if (this.HasSelectedCategories && !string.IsNullOrEmpty(cConstraint.Category) && !this.selectedCategories.Contains(cConstraint.Category))
                {
                    continue;
                }

                var nextSchemaObject = schemaObject != null?
                                       schemaObject.Children.SingleOrDefault(y => y.Name == cConstraint.Context) :
                                           null;

                this.AddTemplateTableConstraint(template, table, cConstraint, level + 1, includeCategoryHeader, nextSchemaObject);
            }
        }
Пример #13
0
        public void TestSimplifiedSchema_CDA()
        {
            SimpleSchema cdaSchema = SimpleSchema.CreateSimpleSchema(
                Trifolia.Shared.Helper.GetIGSimplifiedSchemaLocation(
                    new ImplementationGuideType()
            {
                Name           = Constants.IGTypeNames.CDA,
                SchemaLocation = Constants.IGTypeSchemaLocations.CDA
            }));

            Assert.IsNotNull(cdaSchema.ComplexTypes);
            Assert.AreEqual(232, cdaSchema.ComplexTypes.Count);         // This number may change if the schema changes
            Assert.IsNotNull(cdaSchema.Children);
            Assert.AreEqual(1, cdaSchema.Children.Count);

            // Test root document level
            SimpleSchema.SchemaObject clinicalDocument = cdaSchema.Children.SingleOrDefault(y => y.Name == "ClinicalDocument");
            Assert.IsNotNull(clinicalDocument);
            Assert.AreEqual("ClinicalDocument", clinicalDocument.DataType);
            Assert.AreEqual(false, clinicalDocument.Mixed);
            Assert.AreEqual(31, clinicalDocument.Children.Count);
            var clinicalDocumentInvalidChildNames = clinicalDocument.Children.Where(y => string.IsNullOrEmpty(y.Name) || y.Name.Length <= 1);

            Assert.IsTrue(clinicalDocumentInvalidChildNames.Count() == 0);
            Assert.AreEqual(SimpleSchema.ObjectTypes.Element, clinicalDocument.Type);

            // Test datatype
            SimpleSchema.SchemaObject typeId = clinicalDocument.Children.SingleOrDefault(y => y.Name == "typeId");
            Assert.IsNotNull(typeId);
            Assert.AreEqual("typeId[typeId]", typeId.ToString());
            Assert.AreEqual("typeId", typeId.DataType);
            Assert.AreEqual("1..1", typeId.Cardinality);
            Assert.AreEqual("SHALL", typeId.Conformance);
            Assert.AreEqual(false, typeId.Mixed);
            Assert.AreEqual(5, typeId.Children.Count);
            var typeIdInvalidNames = typeId.Children.Where(y => string.IsNullOrEmpty(y.Name) || y.Name.Length <= 1);

            Assert.IsTrue(typeIdInvalidNames.Count() == 0);
            Assert.AreEqual(SimpleSchema.ObjectTypes.Element, typeId.Type);

            // Test attribute
            SimpleSchema.SchemaObject typeIdRoot = typeId.Children.SingleOrDefault(y => y.Name == "root");
            Assert.IsNotNull(typeId);
            Assert.AreEqual("uid", typeIdRoot.DataType);
            Assert.AreEqual("1..1", typeIdRoot.Cardinality);
            Assert.AreEqual("SHALL", typeIdRoot.Conformance);
            Assert.AreEqual(false, typeIdRoot.Mixed);
            Assert.AreEqual(0, typeIdRoot.Children.Count);
            Assert.AreEqual(SimpleSchema.ObjectTypes.Attribute, typeIdRoot.Type);

            // Test many cardinality
            SimpleSchema.SchemaObject recordTarget = clinicalDocument.Children.SingleOrDefault(y => y.Name == "recordTarget");
            Assert.IsNotNull(recordTarget);
            Assert.AreEqual("RecordTarget", recordTarget.DataType);
            Assert.AreEqual("1..*", recordTarget.Cardinality);
            Assert.AreEqual("SHALL", recordTarget.Conformance);
            Assert.AreEqual(false, recordTarget.Mixed);
            Assert.AreEqual(7, recordTarget.Children.Count);
            var recordTargetInvalidNames = recordTarget.Children.Where(y => string.IsNullOrEmpty(y.Name) || y.Name.Length <= 1);

            Assert.IsTrue(recordTargetInvalidNames.Count() == 0);
            Assert.AreEqual(SimpleSchema.ObjectTypes.Element, recordTarget.Type);

            // Test patientRole
            SimpleSchema.SchemaObject patientRole = recordTarget.Children.SingleOrDefault(y => y.Name == "patientRole");
            Assert.IsNotNull(patientRole);
            Assert.AreEqual("PatientRole", patientRole.DataType);
            Assert.AreEqual("1..1", patientRole.Cardinality);
            Assert.AreEqual("SHALL", patientRole.Conformance);
            Assert.AreEqual(false, patientRole.Mixed);
            Assert.AreEqual(10, patientRole.Children.Count);
            Assert.AreEqual(SimpleSchema.ObjectTypes.Element, patientRole.Type);

            // Test conformance
            SimpleSchema.SchemaObject patient = patientRole.Children.SingleOrDefault(y => y.Name == "patient");
            Assert.IsNotNull(patient);
            Assert.AreEqual("Patient", patient.DataType);
            Assert.AreEqual("0..1", patient.Cardinality);
            Assert.AreEqual("MAY", patient.Conformance);
            Assert.AreEqual(false, patient.Mixed);
            Assert.AreEqual(24, patient.Children.Count);
            Assert.IsNotNull(patient.Children.SingleOrDefault(y => y.Name == "sdtc:raceCode"));
            var patientInvalidNames = patient.Children.Where(y => string.IsNullOrEmpty(y.Name) || y.Name.Length <= 1);

            Assert.IsTrue(patientInvalidNames.Count() == 0);
            Assert.AreEqual(SimpleSchema.ObjectTypes.Element, patientRole.Type);

            SimpleSchema.SchemaObject sdtcRaceCode = patient.Children.Single(y => y.Name == "sdtc:raceCode");
            var sdtcRaceCodeInvalidNames           = sdtcRaceCode.Children.Where(y => string.IsNullOrEmpty(y.Name) || y.Name.Length <= 1);

            Assert.IsTrue(sdtcRaceCodeInvalidNames.Count() == 0);

            // Test mixed
            SimpleSchema.SchemaObject patientName = patient.Children.SingleOrDefault(y => y.Name == "name");
            Assert.IsNotNull(patientName);
            Assert.AreEqual("PN", patientName.DataType);
            Assert.AreEqual("0..*", patientName.Cardinality);
            Assert.AreEqual("MAY", patientName.Conformance);
            Assert.AreEqual(true, patientName.Mixed);
            Assert.AreEqual(8, patientName.Children.Count, "Expected patient to have 8 children");       // TODO: Schema Choice support temporarily removed from non-FHIR schemas
            Assert.IsTrue(patientName.Children.Count(y => string.IsNullOrEmpty(y.Name) || y.Name.Length <= 1) == 0);
            Assert.AreEqual(SimpleSchema.ObjectTypes.Element, patientRole.Type);
        }
Пример #14
0
        private void AddConstraint(XmlNode aParent, List <SimpleSchema.SchemaObject> siblingSchemaObjects, TemplateConstraint aConstraint)
        {
            // If the constraint is a primitive, add a comment to the sample
            if (aConstraint.IsPrimitive)
            {
                XmlComment comment            = _currentDocument.CreateComment("PRIMITIVE: " + aConstraint.PrimitiveText);
                XmlNode    nonAttributeParent = GetNonAttributeParent(aParent);

                if (nonAttributeParent != null)
                {
                    nonAttributeParent.AppendChild(comment);
                }
            }
            // If the constraint is not primitive and does not have a context, add an error comment to the sample
            else if (!aConstraint.IsPrimitive && string.IsNullOrEmpty(aConstraint.Context))
            {
                XmlComment comment =
                    _currentDocument.CreateComment("ERROR: Constraint " + aConstraint.Id.ToString() +
                                                   " does not have a context.");
                aParent.AppendChild(comment);
            }
            else
            {
                // Splitting on / in case legacy data is exported that makes use of xpath in constraint contexts
                string[] lContextSplit = aConstraint.Context.Split('/');
                XmlNode  lCurrentNode  = aParent;
                SimpleSchema.SchemaObject lSchemaObject = null;

                foreach (string lCurrentContextSplit in lContextSplit)
                {
                    bool   lIsAttribute     = lCurrentContextSplit.StartsWith("@");
                    string lStrippedContext = lCurrentContextSplit.Replace("@", "");

                    // Add an error comment if an attribute is a child of another attribute (ex: "@root/@extension")
                    if (lIsAttribute && lCurrentNode is XmlAttribute)
                    {
                        XmlComment comment =
                            _currentDocument.CreateComment(
                                "ERROR: An attribute cannot be a child of another attribute for constraint " +
                                aConstraint.Id.ToString());
                        lCurrentNode.AppendChild(comment);
                        break;
                    }

                    // Find the schema object associated with this constraint
                    if (siblingSchemaObjects != null)
                    {
                        lSchemaObject =
                            siblingSchemaObjects.SingleOrDefault(
                                y => y.Name == lStrippedContext && y.IsAttribute == lIsAttribute);
                    }

                    // If the constraint is an attribute, add an attribute to the parent
                    if (lIsAttribute)
                    {
                        XmlAttribute attribute = lCurrentNode.Attributes[lStrippedContext];

                        if (attribute == null)
                        {
                            attribute = _currentDocument.CreateAttribute(lStrippedContext);
                            lCurrentNode.Attributes.Append(attribute);
                        }

                        if (!string.IsNullOrEmpty(aConstraint.Value))
                        {
                            attribute.Value = aConstraint.Value;
                        }
                        else
                        {
                            attribute.Value = "XXX";
                        }

                        lCurrentNode = attribute;
                    }
                    // Otherwise, create an element and add it to the parent
                    else
                    {
                        XmlElement lNewContextElement = _currentDocument.CreateElement(lCurrentContextSplit);

                        if (lSchemaObject != null)
                        {
                            foreach (SimpleSchema.SchemaObject lCurrentSchemaAttribute in lSchemaObject.Children.Where(y => y.IsAttribute))
                            {
                                if (!lCurrentSchemaAttribute.Cardinality.StartsWith("1.."))
                                {
                                    continue;
                                }

                                XmlAttribute newAttribute = _currentDocument.CreateAttribute(lCurrentSchemaAttribute.Name);
                                lNewContextElement.Attributes.Append(newAttribute);

                                if (!string.IsNullOrEmpty(lCurrentSchemaAttribute.FixedValue))
                                {
                                    newAttribute.Value = lCurrentSchemaAttribute.FixedValue;
                                }
                                else if (!string.IsNullOrEmpty(lCurrentSchemaAttribute.Value))
                                {
                                    newAttribute.Value = lCurrentSchemaAttribute.Value;
                                }
                                else
                                {
                                    newAttribute.Value = "YYY";
                                }
                            }

                            if (!string.IsNullOrEmpty(aConstraint.DataType) && lSchemaObject.DataType != aConstraint.DataType)
                            {
                                XmlAttribute xsiTypeAttribute = _currentDocument.CreateAttribute("xsi", "type", "http://www.w3.org/2001/XMLSchema-instance");
                                xsiTypeAttribute.Value = aConstraint.DataType;
                                lNewContextElement.Attributes.Append(xsiTypeAttribute);
                            }
                        }

                        // Do not add elements to attributes
                        if (!(lCurrentNode is XmlAttribute))
                        {
                            lCurrentNode.AppendChild(lNewContextElement);
                            lCurrentNode = lNewContextElement;
                        }
                        else
                        {
                            // Add a comment to the generated sample that indicates the problem
                            string commentText = string.Format(
                                "Error: Attribute contains an element. (CONF #: {0}, context: '{1}')",
                                aConstraint.Id,
                                !string.IsNullOrEmpty(aConstraint.Context) ? aConstraint.Context : "N/A");
                            XmlComment comment = this._currentDocument.CreateComment(commentText);

                            if (lCurrentNode.ParentNode != null)
                            {
                                lCurrentNode.ParentNode.AppendChild(comment);
                            }
                            else
                            {
                                this._currentDocument.DocumentElement.AppendChild(comment);
                            }
                        }
                    }

                    if (lSchemaObject == null)
                    {
                        this.isSchemaValid = false;
                    }
                }

                List <TemplateConstraint> childConstraints = aConstraint.ChildConstraints
                                                             .OrderBy(y => y.Order)
                                                             .ToList();
                childConstraints.ForEach(y => AddConstraint(lCurrentNode, lSchemaObject != null ? lSchemaObject.Children : null, y));

                if (lSchemaObject != null)
                {
                    this.AddMissingRequiredData(lCurrentNode, lSchemaObject.Children);
                }

                if (lCurrentNode is XmlElement)
                {
                    foreach (XmlNode childNode in lCurrentNode.ChildNodes)
                    {
                        if (childNode is XmlElement)
                        {
                            this.igTypePlugin.FillSampleData((XmlElement)childNode);
                        }
                    }
                }
            }
        }
Пример #15
0
        private void CreateConstraints(IGSettingsManager igManager, IIGTypePlugin igTypePlugin, IEnumerable <TemplateConstraint> constraints, List <ViewDataModel.Constraint> parentList, SimpleSchema templateSchema, SimpleSchema.SchemaObject schemaObject = null)
        {
            foreach (var constraint in constraints.OrderBy(y => y.Order))
            {
                var theConstraint = constraint;

                // TODO: Possible bug? Should schemaObject always be re-set? Remove schemaObject == null from if()
                if (templateSchema != null && schemaObject == null)
                {
                    schemaObject = templateSchema.Children.SingleOrDefault(y => y.Name == constraint.Context);
                }

                IFormattedConstraint fc = FormattedConstraintFactory.NewFormattedConstraint(this.tdb, igManager, igTypePlugin, theConstraint, this.constraintReferences.Cast <ConstraintReference>().ToList(), "#/volume2/", "#/valuesets/#", true, true, true, false);

                var newConstraintModel = new ViewDataModel.Constraint()
                {
                    Number             = string.Format("{0}-{1}", theConstraint.Template.OwningImplementationGuideId, theConstraint.Number),
                    Narrative          = fc.GetHtml(string.Empty, 1, true),
                    Conformance        = theConstraint.Conformance,
                    Cardinality        = theConstraint.Cardinality,
                    Context            = theConstraint.Context,
                    DataType           = theConstraint.DataType,
                    Value              = theConstraint.Value,
                    ValueSetIdentifier = theConstraint.ValueSet != null?theConstraint.ValueSet.GetIdentifier(igTypePlugin) : null,
                                             ValueSetDate = theConstraint.ValueSetDate != null?theConstraint.ValueSetDate.Value.ToShortDateString() : null,
                                                                IsChoice = theConstraint.IsChoice
                };

                newConstraintModel.ContainedTemplates = (from cr in this.constraintReferences
                                                         where cr.TemplateConstraintId == theConstraint.Id
                                                         select new ViewDataModel.TemplateReference()
                {
                    Identifier = cr.Identifier,
                    Bookmark = cr.Bookmark,
                    ImplementationGuide = cr.ImplementationGuide,
                    PublishDate = cr.PublishDate,
                    Name = cr.Name
                }).ToList();

                var isFhir = constraint.Template.ImplementationGuideType.SchemaURI == ImplementationGuideType.FHIR_NS;

                // Check if we're dealing with a FHIR constraint
                if (isFhir && schemaObject != null)
                {
                    newConstraintModel.DataType = schemaObject.DataType;
                }

                parentList.Add(newConstraintModel);

                var nextSchemaObject = schemaObject != null?
                                       schemaObject.Children.SingleOrDefault(y => y.Name == constraint.Context) :
                                           null;

                // Recursively add child constraints
                CreateConstraints(igManager, igTypePlugin, theConstraint.ChildConstraints, newConstraintModel.Constraints, null, nextSchemaObject);
            }
        }