public void GenerateSchematronAssertion_NestedElement_WithAttribute_NULLFlavor_ConformanceSHALL_CardinalityOneToOne()
        {
            var idElement           = new DocumentTemplateElement("id");
            var nullFlavorAttribute = new DocumentTemplateElementAttribute("nullFlavor", "NI");

            idElement.AddAttribute(nullFlavorAttribute);
            var cdaDocumentTemplate = new DocumentTemplate("urn:hl7-org:v3");

            cdaDocumentTemplate.AddElement(new DocumentTemplateElement("component")
                                           .AddElement(new DocumentTemplateElement("section")
                                                       .AddElement(new DocumentTemplateElement("entry")
                                                                   .AddElement(new DocumentTemplateElement("organizer")
                                                                               .AddElement(new DocumentTemplateElement("performer")
                                                                                           .AddElement(new DocumentTemplateElement("assignedEntity")
                                                                                                       .AddElement(idElement)))))));
            var builder = new AssertionLineBuilder(this.tdb, nullFlavorAttribute, this.igType, this.igTypeSchema);

            builder.ConformsTo(ConformanceParser.Parse("SHALL")).WithCardinality(CardinalityParser.Parse("1..1")).WithinContext("cda:");
            var assertion         = builder.ToString();
            var expectedAssertion = @"cda:id[@nullFlavor='NI']";

            Assert.IsTrue(assertion == expectedAssertion,
                          "Assertion string was not correct. Expected '{0}', Actual '{1}'.", expectedAssertion, assertion);
            var contextBuilder  = new ContextBuilder(idElement.ParentElement, "cda");
            var context         = contextBuilder.GetRelativeContextString();
            var expectedContext = "cda:assignedEntity";

            Assert.IsTrue(context == expectedContext, "Context is not correct. Expected '{0}', Actual '{1}'", expectedContext, context);
        }
        public void GenerateSchematronAssertion_Element_With_Value_And_AttributeOverride_ConformanceSHALL_CardinalityOneToOne()
        {
            //create cda doc
            var cdaDocumentTemplate = new DocumentTemplate("urn:hl7-org:v3");
            //create code element
            var element = new DocumentTemplateElement("statusCode", "Test");

            element.ElementToAttributeOverrideMapping.Add("statusCode", "code");
            element.ElementToAttributeOverrideMapping.Add("code", "code");
            //add element to doc
            cdaDocumentTemplate.AddElement(element);
            //create schematron assertion line builder
            var builder = new AssertionLineBuilder(this.tdb, element, this.igType, this.igTypeSchema);
            //define cardinality and conformance
            var cardinality = CardinalityParser.Parse("1..1");
            var conformance = ConformanceParser.Parse("SHALL");

            //add element (context comes from doc), conformance, cardinality through fluent interface
            builder.ConformsTo(conformance).WithCardinality(cardinality);
            //generate string
            string assertion = builder.ToString();

            //did we generate the correct string?
            Assert.IsTrue(assertion == @"count(cda:statusCode[@code='Test'])=1", "The generated assertion was not correct. Expected 'count(cda:statusCode[@code='Test'])=1', Actual '{0}'.", assertion);
        }
        public void GenerateSchematronAssertion_Attribute_TwoAttributes_No_Element_ConformanceSHALL_CardinalityOneToOne()
        {
            var attr = new DocumentTemplateElementAttribute("code");

            attr.SingleValue = "OBS";
            attr.DataType    = "CD";
            //create schematron assertion line builder, build one at a time (regular interface, see above for fluent interface)
            var builder = new AssertionLineBuilder(this.tdb, attr, this.igType, this.igTypeSchema);
            //define cardinality
            var cardinality = CardinalityParser.Parse("1..1");

            //add cardinality for the element
            builder.WithCardinality(cardinality);
            //define conformance
            var conformance = ConformanceParser.Parse("SHALL");

            //add conformance for the element
            builder.ConformsTo(conformance);
            //generate string
            string assertion = builder.ToString();
            //did we generate the correct string?
            string expected = @"count(self::node()[@code='OBS'])=1";

            Assert.IsTrue(assertion == expected, "Assertion string was not correct. Expected '{0}', Actual '{1}'.", expected, assertion);
        }
예제 #4
0
 static public void AddElementValueAndDataType(string aPrefix, DocumentTemplateElement aElement, IConstraint aTemplateConstraint)
 {
     if (!string.IsNullOrEmpty(aTemplateConstraint.Value))
     {
         if (!string.IsNullOrEmpty(aTemplateConstraint.ValueConformance))
         {
             var valueConformanceType = ConformanceParser.Parse(aTemplateConstraint.ValueConformance);
             var conformanceType      = ConformanceParser.Parse(aTemplateConstraint.Conformance);
             if (valueConformanceType == conformanceType)
             {
                 aElement.Value = !string.IsNullOrEmpty(aTemplateConstraint.Value) ? aTemplateConstraint.Value.Trim() : aTemplateConstraint.Value;
             }
         }
         else
         {
             aElement.Value = !string.IsNullOrEmpty(aTemplateConstraint.Value) ? aTemplateConstraint.Value.Trim() : aTemplateConstraint.Value;
         }
     }
     // Add the data type attribute if one is present on the constraint
     if (!string.IsNullOrEmpty(aTemplateConstraint.DataType))
     {
         if (aPrefix == "cda")
         {
             if (aElement.ElementName != "code")
             {
                 DocumentTemplateElementAttribute dataTypeAttr = new DocumentTemplateElementAttribute("xsi:type");
                 dataTypeAttr.SingleValue = aTemplateConstraint.DataType;
                 aElement.AddAttribute(dataTypeAttr);
             }
         }
     }
 }
예제 #5
0
        public void GenerateSchematronAssertion_Attribute_Value_DataType_ConformanceSHALL_CardinalityOneToOne()
        {
            var attr = new DocumentTemplateElementAttribute("code", "57024-2")
            {
                DataType = "CE"
            };
            //create schematron assertion line builder, build one at a time (regular interface, see above for fluent interface)
            var builder = new AssertionLineBuilder(attr, templateIdentifierXpath, templateVersionIdentifierXpath);
            //define cardinality
            var cardinality = CardinalityParser.Parse("1..1");

            //add cardinality for the element
            builder.WithCardinality(cardinality);
            //define conformance
            var conformance = ConformanceParser.Parse("SHALL");

            //add conformance for the element
            builder.ConformsTo(conformance);
            //generate string
            string assertion = builder.ToString();
            //did we generate the correct string?
            string expected = @"count(self::node()[@code='57024-2'])=1";

            Assert.IsTrue(assertion == expected, "Assertion string was not correct. Expected '{0}', Actual '{1}'.", expected, assertion);
        }
예제 #6
0
        public ConstraintParser(IObjectRepository tdb,
                                IConstraint constraint,
                                ImplementationGuideType igType,
                                SimpleSchema igTypeSchema,
                                IEnumerable <Template> allTemplates,
                                string valueSetFile = "voc.xml",
                                VocabularyOutputType vocabularyOutputType = VocabularyOutputType.Default)
        {
            this.tdb          = tdb;
            this.constraint   = constraint;
            this.valueSetFile = valueSetFile;
            this.igType       = igType;
            this.igTypeSchema = igTypeSchema;
            this.allTemplates = allTemplates;
            this.igTypePlugin = igType.GetPlugin();

            if (!string.IsNullOrEmpty(this.constraint.Cardinality))
            {
                this.constraintCardinalityType = CardinalityParser.Parse(this.constraint.Cardinality);
            }

            if (!string.IsNullOrEmpty(this.constraint.Conformance))
            {
                this.constraintConformanceType = ConformanceParser.Parse(this.constraint.Conformance);
            }

            this.prefix = igType.SchemaPrefix;

            this.vocabularyOutputType = vocabularyOutputType;
        }
예제 #7
0
 static public void AddConformance(IConstraint aTemplateConstraint, AssertionLineBuilder aAssertionLineBuilder)
 {
     // Determine if we have a conformance
     if (!string.IsNullOrEmpty(aTemplateConstraint.Conformance))
     {
         aAssertionLineBuilder.ConformsTo(
             ConformanceParser.Parse(aTemplateConstraint.Conformance));
     }
 }
예제 #8
0
        /// <summary>
        /// Helper function which creates an AssertionLineBuilder for an element given the constraint. This function will examine the constraint's value and datatype
        /// and add those to the builder if necessary. Also if aGenerateContext == true then it will add the context of the element.
        /// </summary>
        /// <param name="aElement">Element to base the AssertionLineBuilder from</param>
        /// <param name="aTemplateConstraint">TemplateConstraint which has the necessary properties (e.g. Element Value, Data Type) to add to the AssertionLineBuilder</param>
        /// <param name="aGenerateContext">Flag to determine whether a context should be added as part of the AssertionLineBuilder</param>
        /// <returns>A new AssertionLineBuilder for the aElement passed in</returns>
        private AssertionLineBuilder CreateAssertionLineBuilderForElement(DocumentTemplateElement aElement, IConstraint aTemplateConstraint, ref string aParentContext, bool aGenerateContext = true)
        {
            //add the value and data type
            ConstraintToDocumentElementHelper.AddElementValueAndDataType(this.prefix, aElement, aTemplateConstraint);

            //create builders
            var builder = new AssertionLineBuilder(this.tdb, aElement, this.igType, this.igTypeSchema);

            if (aGenerateContext)
            {
                ContextBuilder contextBuilder = null;

                if (aElement.ParentElement != null)                                           //build the context
                {
                    contextBuilder = new ContextBuilder(aElement.ParentElement, this.prefix); //the context will start from the first parent (or root)
                    builder.WithinContext(string.Format("{0}", contextBuilder.GetFullyQualifiedContextString()));
                }
            }

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

            foreach (var containedTemplate in containedTemplates)
            {
                builder.ContainsTemplate(containedTemplate.Identifier, containedTemplate.PrimaryContextType);

                if (aTemplateConstraint.Parent != null && aTemplateConstraint.Parent.IsBranch)
                {
                    builder.WithinContext(aParentContext, ContextWrapper.Slash); //put the parent context into the element context, this is a special case where we want the full context within the template assertion
                    aParentContext = string.Empty;                               //clear the parent context b/c we have put it within the element's context
                }
            }

            if (aTemplateConstraint.Parent != null)
            {
                Conformance conformance = ConformanceParser.Parse(aTemplateConstraint.Parent.Conformance);
                if (conformance == Conformance.SHOULD)
                {
                    builder.HasOptionalParentContext();
                }
            }

            //TODO: Refactor this out, hardcoding these special cases for QRDA
            if (this.prefix.ToLower().Contains("cda"))
            {
                aElement.ElementToAttributeOverrideMapping.Add("code", "code");
                aElement.ElementToAttributeOverrideMapping.Add("statusCode", "code");
                aElement.ElementToAttributeOverrideMapping.Add("realmCode", "code");
                aElement.ElementToAttributeOverrideMapping.Add("externalDocument", "classCode");
            }

            return(builder);
        }
        public void GenerateSchematronAssertion_Element_ValueSet_SVS_ConformanceSHALL_CardinalityOneToOne()
        {
            var element = new DocumentTemplateElement("administrativeGenderCode");
            //create schematron assertion line builder, build one at a time (regular interface, see above for fluent interface)
            var builder = new AssertionLineBuilder(this.tdb, element, this.igType, this.igTypeSchema);
            //define cardinality
            var cardinality = CardinalityParser.Parse("1..1");

            //add cardinality for the element
            builder.WithCardinality(cardinality);
            //define conformance
            var conformance = ConformanceParser.Parse("SHALL");

            //add conformance for the element
            builder.ConformsTo(conformance);
            builder.WithinValueSet("4.3.2.1", VocabularyOutputType.SVS_SingleValueSet);
            //generate string
            string assertion = builder.ToString();
            //did we generate the correct string?
            string expected = @"count(cda:administrativeGenderCode[@code=document('4.3.2.1.xml')/svs:RetrieveValueSetResponse/svs:ValueSet[@id='4.3.2.1']/svs:ConceptList/svs:Concept/@code])=1";

            Assert.IsTrue(assertion == expected, "Assertion string was not correct. Expected '{0}', Actual '{1}'.", expected, assertion);
        }
예제 #10
0
        public void GenerateSchematronAssertion_Element_With_Value_ConformanceSHALL_CardinalityOneToOne()
        {
            //create cda doc
            var cdaDocumentTemplate = new DocumentTemplate("urn:hl7-org:v3");
            //create code element
            var element = new DocumentTemplateElement("code", "Test");

            //add element to doc
            cdaDocumentTemplate.AddElement(element);
            //create schematron assertion line builder
            var builder = new AssertionLineBuilder(element, templateIdentifierXpath, templateVersionIdentifierXpath, "cda");
            //define cardinality and conformance
            var cardinality = CardinalityParser.Parse("1..1");
            var conformance = ConformanceParser.Parse("SHALL");

            //add element (context comes from doc), conformance, cardinality through fluent interface
            builder.ConformsTo(conformance).WithCardinality(cardinality);
            //generate string
            string assertion = builder.ToString();

            //did we generate the correct string?
            Assert.IsTrue(assertion == @"count(cda:code[translate(text(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')='test'])=1", "The generated assertion was not correct. Expected 'count(cda:code[text()='Test'])=1', Actual '{0}'.", assertion);
        }
        public void GenerateSchematronAssertion_NamespaceEMA_Element_Template_ConformanceSHALL_CardinalityOneToOne()
        {
            //create cda doc
            var cdaDocumentTemplate = new DocumentTemplate("urn:hl7-org:v3");
            //create code element
            var element = new DocumentTemplateElement("encounter");

            //add element to doc
            cdaDocumentTemplate.AddElement(element);
            //create schematron assertion line builder
            var builder = new AssertionLineBuilder(this.tdb, element, this.igType, this.igTypeSchema, "ema");
            //define cardinality and conformance
            var cardinality = CardinalityParser.Parse("1..1");
            var conformance = ConformanceParser.Parse("SHALL");

            //add element (context comes from doc), conformance, cardinality through fluent interface
            builder.ConformsTo(conformance).WithCardinality(cardinality).ContainsTemplate("urn:oid:4.3.2.1", "Section");
            //generate string
            string assertion = builder.ToString();
            string expected  = @"count(ema:encounter[ema:templateId[@root='4.3.2.1']])=1";

            //did we generate the correct string?
            Assert.IsTrue(assertion == expected, "The generated assertion was not correct. Expected '{0}', Actual '{1}'.", expected, assertion);
        }
        public void GenerateSchematronAssertion_Attribute_Valueset_ConformanceMAY_CardinalityOneToOne()
        {
            var attr = new DocumentTemplateElementAttribute("moodCode", "EVN");
            //create schematron assertion line builder, build one at a time (regular interface, see above for fluent interface)
            var builder = new AssertionLineBuilder(this.tdb, attr, this.igType, this.igTypeSchema);
            //define cardinality
            var cardinality = CardinalityParser.Parse("1..1");

            //add cardinality for the element
            builder.WithCardinality(cardinality);
            //define conformance
            var conformance = ConformanceParser.Parse("MAY");

            //add conformance for the element
            builder.ConformsTo(conformance);
            //add valueset
            builder.WithinValueSet("2.16.840.1.113883.1.11.20.2");
            //generate string
            string assertion = builder.ToString();
            //did we generate the correct string?
            string expected = "@moodCode='EVN' and @moodCode=document('the_voc.xml')/voc:systems/voc:system[@valueSetOid='2.16.840.1.113883.1.11.20.2']/voc:code/@value";

            Assert.IsTrue(assertion == expected, "Assertion string was not correct. Expected empty string, Actual '{1}'.", expected, assertion);
        }
        public void GenerateSchematronAssertion_Element_ConformanceSHALL_CardinalityZeroToMany()
        {
            //create cda doc
            var cdaDocumentTemplate = new DocumentTemplate("urn:hl7-org:v3");
            //create code element
            var element = new DocumentTemplateElement("code");

            //add element to doc
            cdaDocumentTemplate.AddElement(element);
            //create schematron assertion line builder
            var builder = new AssertionLineBuilder(this.tdb, element, this.igType, this.igTypeSchema);
            //define cardinality and conformance
            var cardinality = CardinalityParser.Parse("0..*");
            var conformance = ConformanceParser.Parse("SHALL");

            //add element (context comes from doc), conformance, cardinality through fluent interface
            builder.ConformsTo(conformance).WithCardinality(cardinality);
            //generate string
            string assertion = builder.ToString();
            string expected  = "not(cda:code) or cda:code";

            //did we generate the correct string?
            Assert.IsTrue(assertion == expected, "The generated assertion was not correct. Expected '{0}', Actual '{1}'.", expected, assertion);
        }
예제 #14
0
        public ConstraintParser(IObjectRepository tdb, IConstraint constraint, ImplementationGuideType igType, string valueSetFile = "voc.xml", VocabularyOutputType vocabularyOutputType = VocabularyOutputType.Default)
        {
            this.tdb          = tdb;
            this.constraint   = constraint;
            this.valueSetFile = valueSetFile;
            this.igTypePlugin = igType.GetPlugin();

            if (this.constraint.ValueSetId != null)
            {
                this.constraintValueSet = this.tdb.ValueSets.Single(y => y.Id == constraint.ValueSetId);
            }

            if (this.constraint.ValueCodeSystemId != null)
            {
                this.constraintCodeSystem = this.tdb.CodeSystems.Single(y => y.Id == constraint.ValueCodeSystemId);
            }

            if (!string.IsNullOrEmpty(this.constraint.Cardinality))
            {
                this.constraintCardinalityType = CardinalityParser.Parse(this.constraint.Cardinality);
            }

            if (!string.IsNullOrEmpty(this.constraint.Conformance))
            {
                this.constraintConformanceType = ConformanceParser.Parse(this.constraint.Conformance);
            }

            if (this.constraint.ContainedTemplateId != null)
            {
                this.containedTemplate = this.tdb.Templates.Single(y => y.Id == this.constraint.ContainedTemplateId.Value);
            }

            this.prefix = igType.SchemaPrefix;

            this.vocabularyOutputType = vocabularyOutputType;
        }
예제 #15
0
        /// <summary>
        /// This is the main public interface for constraint parser. Takes the given constraint and builds an AssertionLineBuilder, applying the values, attributes, context, etc as necessary.
        /// </summary>
        /// <returns>
        /// AssertionLineBuilder representing the values from the constraint given to the parser.
        /// </returns>
        public AssertionLineBuilder CreateAssertionLineBuilder()
        {
            if (this.valueSet == null && this.constraint.ValueSetId != null)
            {
                this.valueSet = this.tdb.ValueSets.Single(y => y.Id == constraint.ValueSetId);
            }

            if (this.codeSystem == null && this.constraint.ValueCodeSystemId != null)
            {
                this.codeSystem = this.tdb.CodeSystems.Single(y => y.Id == constraint.ValueCodeSystemId);
            }

            IConstraint currentConstraint  = this.constraint; //set current constraint, setting this as a variable allows us to move the current constraint to the parent when dealing with branches
            var         containedTemplates = currentConstraint.References.Where(y => y.ReferenceType == ConstraintReferenceTypes.Template);

            if (string.IsNullOrEmpty(currentConstraint.Context) && !containedTemplates.Any()) //we can have empty context but a contained template
            {
                return(null);
            }

            DocumentTemplateElement          element   = null;
            DocumentTemplateElementAttribute attribute = null;

            ConstraintToDocumentElementHelper.ParseContextForElementAndAttribute(currentConstraint, out element, out attribute);
            DocumentTemplateElement parentElement =
                ConstraintToDocumentElementHelper.CreateParentElementForAttribute(currentConstraint, attribute);

            string parentContext =
                CreateParentContextForElement(parentElement, element, currentConstraint);

            AssertionLineBuilder asb             = null;
            AssertionLineBuilder branchedRootAsb = null;

            // Determine if we should create the AssertionLineBuilder starting with an attribute or an element.
            if (attribute != null)
            {
                DecorateAttributeFromConstraint(parentContext, attribute, currentConstraint, this.valueSet);
                if (currentConstraint.Parent != null && currentConstraint.IsBranch)
                {
                    branchedRootAsb = CreateBranchedRootAssertionLineBuilderFromConstraint(currentConstraint);
                }
                else
                {
                    asb = CreateAssertionLineBuilderForAttribute(parentElement, attribute, ref parentContext, ref currentConstraint);
                }
            }
            else //this is an element
            {
                // Only add the code system constraints if there is no value conformance or the value conformance matches the element/attribute conformance
                // This is because in the SchematronGenerator class, a duplicate constraint is created when the value conformance is different from
                // the element/attribute conformance, where the duplicate constraint's conformance matches the value conformance.
                if (string.IsNullOrEmpty(currentConstraint.ValueConformance) || ConformanceParser.Parse(currentConstraint.Conformance) == ConformanceParser.Parse(currentConstraint.ValueConformance))
                {
                    ConstraintToDocumentElementHelper.AddCodeSystemToElement(this.tdb, this.igTypePlugin, element, currentConstraint);
                }

                if (currentConstraint.IsBranch)
                {
                    branchedRootAsb = CreateBranchedRootAssertionLineBuilderFromConstraint(currentConstraint);
                    branchedRootAsb.HasParentContext(parentContext);
                }
                else
                {
                    //if we have a context already then we will append it at end so pass in false, else go ahead and generate (pass in true)
                    asb = CreateAssertionLineBuilderForElement(element, this.constraint, ref parentContext, string.IsNullOrEmpty(parentContext));
                }
            }

            if (branchedRootAsb == null) //if this is a branched root then a separate builder was constructed
            {
                ConstraintToDocumentElementHelper.AddConformance(currentConstraint, asb);
                ConstraintToDocumentElementHelper.AddCardinality(currentConstraint, asb);
                // Determine if we have a valueset
                if (this.valueSet != null && currentConstraint.IsValueSetStatic)
                {
                    var requireValueset = true;

                    if (!string.IsNullOrEmpty(currentConstraint.ValueConformance))
                    {
                        if (ConformanceParser.Parse(currentConstraint.Conformance) != ConformanceParser.Parse(currentConstraint.ValueConformance))
                        {
                            requireValueset = false;
                        }
                    }

                    if (requireValueset)
                    {
                        //TODO: Move into CDA specific library
                        //are we bound directly to a code or value element?
                        bool includeNullFlavor = false;
                        if (element != null && attribute == null && (element.ElementName == "value" || element.ElementName == "code"))
                        {
                            includeNullFlavor = true;
                        }

                        string valueSetIdentifier = this.igTypePlugin.ParseIdentifier(this.valueSet.GetIdentifier(this.igTypePlugin));
                        asb.WithinValueSet(valueSetIdentifier, this.valueSetFile, this.vocabularyOutputType, includeNullFlavor);
                    }
                }

                //determine if we have a parent context
                if (!string.IsNullOrEmpty(parentContext))
                {
                    asb.HasParentContext(parentContext);
                    DecorateParentOptionality(asb, currentConstraint);
                }
            }
            else //branched root, use that one instead
            {
                //determine if we have a parent context
                if (!string.IsNullOrEmpty(parentContext))
                {
                    branchedRootAsb.HasParentContext(parentContext);
                    DecorateParentOptionality(branchedRootAsb, currentConstraint);
                }
            }

            return((branchedRootAsb == null) ? asb : branchedRootAsb);
        }