Beispiel #1
0
 internal void AddReference(ScopedNode node)
 {
     if (References == null || !References.Contains(node))
     {
         (References ?? (References = new List <ScopedNode>())).Add(node);
     }
 }
        internal static OperationOutcome ValidateChildConstraints(this Validator validator, ElementDefinitionNavigator definition,
                                                                  ScopedNode instance, bool allowAdditionalChildren)
        {
            var outcome = new OperationOutcome();

            if (!definition.HasChildren)
            {
                return(outcome);
            }

            validator.Trace(outcome, "Start validation of inlined child constraints for '{0}'".FormatWith(definition.Path), Issue.PROCESSING_PROGRESS, instance);

            var matchResult = ChildNameMatcher.Match(definition, instance);

            if (matchResult.UnmatchedInstanceElements.Any() && !allowAdditionalChildren)
            {
                var elementList = String.Join(",", matchResult.UnmatchedInstanceElements.Select(e => "'" + e.Name + "'"));
                validator.Trace(outcome, $"Encountered unknown child elements {elementList} for definition '{definition.Path}'",
                                Issue.CONTENT_ELEMENT_HAS_UNKNOWN_CHILDREN, instance);
            }

            //TODO: Give warnings for out-of order children.  Really? That's an xml artifact, no such thing in Json!
            //(with the serializationrepresentationnav we could determine the source is xml and make order matter....)

            // Recursively validate my children
            foreach (var match in matchResult.Matches)
            {
                outcome.Add(validator.ValidateMatch(match, instance));
            }

            return(outcome);
        }
Beispiel #3
0
        public IList <Declaration> FindMembers(object result, int line, int col)
        {
            List <Declaration> members = new List <Declaration>();

            if (_node != null)
            {
                ScopedNode found = FindNode(_node.TreeNode, line, col);

                if (found != null)
                {
                    if (found.TreeFuncs != null)
                    {
                        foreach (Method func in found.TreeFuncs)
                        {
                            members.Add(new Declaration(func.Description, func.Name, 207, func.Name));
                        }
                    }
                    if (found.ScopeVars != null)
                    {
                        foreach (Field field in found.ScopeVars)
                        {
                            members.Add(new Declaration(field.Description, field.Name, 208, field.Name));
                        }
                    }
                }
            }

            return(members);
        }
Beispiel #4
0
        private ScopedNode FindNode(ParseTreeNode rootnode, int line, int col)
        {
            ScopedNode found = null;

            foreach (ParseTreeNode childnode in rootnode.ChildNodes)
            {
                ScopedNode node = childnode.AstNode as ScopedNode;
                if (node != null)
                {
                    int endline, endcol;

                    try
                    {
                        _source.GetLineIndexOfPosition(node.Span.EndPosition, out endline, out endcol);

                        if ((node.Location.Line < line && endline > line) || (node.Location.Line == line && node.Location.Column >= col && (endline > line || endcol >= col)))
                        {
                            found = FindNode(node.TreeNode, line, col) ?? node as ScopedNode;
                        }
                    }
                    catch (ArgumentException) { }
                }
            }

            return(found);
        }
Beispiel #5
0
        internal Field(string name, UoToken uotypetoken, ScopedNode locationnode, ParsingContext context, bool isconst = false)
        {
            Name        = name;
            Description = string.Empty;

            Node = locationnode;
            if (Node != null)
            {
                AddReference(Node);
            }

            if (uotypetoken != null)
            {
                UoTypeToken = uotypetoken;
                Type        = uotypetoken.Value;
            }
            else
            {
                Type        = null;
                UoTypeToken = null;
            }
            Value       = null;
            DefFilename = context.CurrentParseTree.FileName;
            isConst     = isconst;
        }
Beispiel #6
0
        protected static ITypedElement MakeElementStack(Base instance, SummaryType summary)
        {
            if (summary == SummaryType.False)
            {
                return(instance.ToTypedElement());
            }

            var patchedInstance = (Base)instance.DeepCopy();

            MetaSubsettedAdder.AddSubsetted(patchedInstance, atRoot: true);

            var baseNav = new ScopedNode(patchedInstance.ToTypedElement());

            switch (summary)
            {
            case SummaryType.True:
                return(MaskingNode.ForSummary(baseNav));

            case SummaryType.Text:
                return(MaskingNode.ForText(baseNav));

            case SummaryType.Data:
                return(MaskingNode.ForData(baseNav));

            case SummaryType.Count:
                return(MaskingNode.ForCount(baseNav));

            default:
                return(baseNav);
            }
        }
Beispiel #7
0
 internal void AddReference(ScopedNode node)
 {
     //  if (node is DeclarationNode) node = ((DeclarationNode)Node).DeclNode;
     if (References == null || !References.Contains(node))
     {
         (References ?? (References = new List <ScopedNode>())).Add(node);
     }
 }
 private static ITypedElement wrapInScopedNode(ITypedElement input)
 {
     if (input is not ScopedNode)
     {
         input = new ScopedNode(input);
     }
     return(input);
 }
        public void SetupSource()
        {
            var bundleXml = File.ReadAllText(Path.Combine("TestData", "bundle-contained-references.xml"));

            var bundle = (new FhirXmlParser()).Parse <Bundle>(bundleXml);

            Assert.IsNotNull(bundle);
            _bundleNode = new ScopedNode(bundle.ToTypedElement());
        }
 private void EmitScopedNode(ScopedNode node)
 {
     using (var model = emitter.DeclareLocal(node.ModelToScope.ResultType))
     {
         EvaluateExpression(node.ModelToScope);
         emitter.StoreLocal(model);
         AddModelScope(x => x.LoadLocal(model));
         EmitNode(node.Node);
         RemoveModelScope();
     }
 }
Beispiel #11
0
        public void SummaryData()
        {
            var tpXml    = File.ReadAllText(Path.Combine("TestData", "mask-text.xml"));
            var typeinfo = new PocoStructureDefinitionSummaryProvider().Provide("ValueSet");

            var nav    = new ScopedNode(getXmlNode(tpXml));
            var masker = MaskingNode.ForData(nav);
            var output = masker.ToXml();

            var maskedChildren = masker.Descendants().Count();

            Assert.AreEqual(nav.Descendants().Count() - 3, maskedChildren);
        }
Beispiel #12
0
        public void CreateFuncsNode(ParsingContext context, ParseTreeNode parseNode)
        {
            ScopedNode node = new ScopedNode();

            node.Init(context, parseNode);
            parseNode.AstNode = node;

            foreach (ParseTreeNode cnode in parseNode.ChildNodes)
            {
                ((ScopedNode)cnode.AstNode).Parent = node;
                node.ChildNodes.Add((ScopedNode)cnode.AstNode);
            }
        }
        public void TestBucketAssignment()
        {
            var s = createSliceDefs() as SliceGroupBucket;

            var p = new Patient();

            p.Telecom.Add(new ContactPoint {
                System = ContactPoint.ContactPointSystem.Phone, Use = ContactPoint.ContactPointUse.Home, Value = "+31-6-39015765"
            });
            p.Telecom.Add(new ContactPoint {
                System = ContactPoint.ContactPointSystem.Email, Use = ContactPoint.ContactPointUse.Work, Value = "*****@*****.**"
            });
            p.Telecom.Add(new ContactPoint {
                System = ContactPoint.ContactPointSystem.Other, Use = ContactPoint.ContactPointUse.Temp, Value = "skype://crap"
            });
            p.Telecom.Add(new ContactPoint {
                System = ContactPoint.ContactPointSystem.Other, Use = ContactPoint.ContactPointUse.Home, Value = "http://nu.nl"
            });
            p.Telecom.Add(new ContactPoint {
                System = ContactPoint.ContactPointSystem.Fax, Use = ContactPoint.ContactPointUse.Work, Value = "+31-20-6707070"
            });
            var pnode = new ScopedNode(p.ToTypedElement());

            var telecoms = pnode.Children("telecom").Cast <ScopedNode>();

            foreach (var telecom in telecoms)
            {
                Assert.True(s.Add(telecom));
            }

            var outcome = s.Validate(_validator, pnode);

            Assert.True(outcome.Success);
            Assert.Equal(0, outcome.Warnings);

            Assert.Equal("+31-6-39015765", s.ChildSlices[0].Members.Single().Children("value").Single().Value);

            var emailBucket = s.ChildSlices[1] as SliceGroupBucket;

            Assert.Equal("*****@*****.**", emailBucket.Members.Single().Children("value").Single().Value);
            Assert.False(emailBucket.ChildSlices[0].Members.Any());
            Assert.Equal("*****@*****.**", emailBucket.ChildSlices[1].Members.Single().Children("value").Single().Value);

            var otherBucket = s.ChildSlices[2] as SliceGroupBucket;

            Assert.Equal("http://nu.nl", otherBucket.ChildSlices[0].Members.Single().Children("value").Single().Value);
            Assert.False(otherBucket.ChildSlices[1].Members.Any());
            Assert.Equal("skype://crap", otherBucket.Members.First().Children("value").Single().Value); // in the open slice - find it on other bucket, not child

            Assert.Equal("+31-20-6707070", s.Members.Last().Children("value").Single().Value);          // in the open-at-end slice
        }
Beispiel #14
0
        public void SummaryCountUsingStructureDefinitionSummaryProvider()
        {
            var tpXml = File.ReadAllText(Path.Combine("TestData", "mask-text.xml"));

            var nav    = new ScopedNode(getXmlNodeSDSP(tpXml));
            var masker = MaskingNode.ForCount(nav);

            var maskedChildren = masker.Descendants().Count();

            Assert.AreEqual(maskedChildren, 2);

            ITypedElement getXmlNodeSDSP(string xml, FhirXmlParsingSettings s = null) =>
            XmlParsingHelpers.ParseToTypedElement(xml, new StructureDefinitionSummaryProvider(ZipSource.CreateValidationSource()), s);
        }
Beispiel #15
0
        public void Summary()
        {
            var tpXml     = File.ReadAllText(Path.Combine("TestData", "fp-test-patient.xml"));
            var typeinfo  = new PocoStructureDefinitionSummaryProvider().Provide("Patient");
            var inSummary = typeinfo.GetElements().Where(e => e.InSummary).ToList();

            var nav    = new ScopedNode(getXmlNode(tpXml));
            var masker = MaskingNode.ForSummary(nav);
            var output = masker.ToXml();

            var maskedChildren = masker.Children().ToList();

            Assert.IsTrue(maskedChildren.Count < inSummary.Count);
            Assert.IsTrue(maskedChildren.Select(c => c.Name).All(c => inSummary.Any(s => s.ElementName == c)));
        }
        private Expression HandleScopedNode(ScopedNode node)
        {
            var scopedModel = ParseExpression(node.ModelToScope);
            var storedModel = Expression.Variable(scopedModel.Type);

            PushScope(storedModel);
            var body = HandleNode(node.Node);

            PopScope();

            return(Expression.Block(
                       new[] { storedModel },
                       Expression.Assign(storedModel, scopedModel),
                       body
                       ));
        }
Beispiel #17
0
        public void ScriptNodeCreator(ParsingContext context, ParseTreeNode parseNode)
        {
            ScopedNode node = new ScopedNode();

            node.Init(context, parseNode);
            parseNode.AstNode = node;

            foreach (ParseTreeNode cnode in parseNode.ChildNodes)
            {
                if (cnode.Term.Name == "Declarations")
                {
                    node.ChildNodes.Add((ScopedNode)cnode.AstNode);
                    ((ScopedNode)cnode.AstNode).Parent = node;

                    node.m_LocalVars = GetMembers(context);
                }
            }

            // Initialize a check of types and scope on the script tree
            node.CheckTree(context);
        }
Beispiel #18
0
        protected static ITypedElement MakeElementStack(Base instance, SummaryType summary, string[] elements)
        {
            if (summary == SummaryType.False && elements == null)
            {
                return(instance.ToTypedElement());
            }

            if (elements != null && summary != SummaryType.False)
            {
                throw Error.Argument("elements", "Elements parameter is supported only when summary is SummaryType.False or summary is not specified at all.");
            }

            var patchedInstance = (Base)instance.DeepCopy();

            MetaSubsettedAdder.AddSubsetted(patchedInstance, atRoot: true);

            var baseNav = new ScopedNode(patchedInstance.ToTypedElement());

            switch (summary)
            {
            case SummaryType.True:
                return(MaskingNode.ForSummary(baseNav));

            case SummaryType.Text:
                return(MaskingNode.ForText(baseNav));

            case SummaryType.Data:
                return(MaskingNode.ForData(baseNav));

            case SummaryType.Count:
                return(MaskingNode.ForCount(baseNav));

            case SummaryType.False:
                return(MaskingNode.ForElements(baseNav, elements));

            default:
                return(baseNav);
            }
        }
Beispiel #19
0
        private static ITypedElement resolveReference(this Validator validator, ScopedNode instance, string reference, out ElementDefinition.AggregationMode?referenceKind, OperationOutcome outcome)
        {
            var identity = new ResourceIdentity(reference);

            if (identity.Form == ResourceIdentityForm.Undetermined)
            {
                if (!Uri.IsWellFormedUriString(Uri.EscapeDataString(reference), UriKind.RelativeOrAbsolute))
                {
                    validator.Trace(outcome, $"Encountered an unparseable reference ({reference})", Issue.CONTENT_UNPARSEABLE_REFERENCE, instance);
                    referenceKind = null;
                    return(null);
                }
            }

            var result = instance.Resolve(reference);

            if (identity.Form == ResourceIdentityForm.Local)
            {
                referenceKind = ElementDefinition.AggregationMode.Contained;
                if (result == null)
                {
                    validator.Trace(outcome, $"Contained reference ({reference}) is not resolvable", Issue.CONTENT_CONTAINED_REFERENCE_NOT_RESOLVABLE, instance);
                }
            }
            else
            {
                if (result != null)
                {
                    referenceKind = ElementDefinition.AggregationMode.Bundled;
                }
                else
                {
                    referenceKind = ElementDefinition.AggregationMode.Referenced;
                }
            }

            return(result);
        }
Beispiel #20
0
 private Func <OperationOutcome> createValidator(ElementDefinitionNavigator nav, ScopedNode instance)
 {
     return(() => validateElement(nav, instance));
 }
Beispiel #21
0
        internal void LoadFile(string path, ScopedNode node, ParsingContext context, IDictionary <string, string> refDepends = null)
        {
            string curExt = context.CurrentParseTree.FileName == "<Source>" ? null : Path.GetExtension(context.CurrentParseTree.FileName);
            string fullpath
                = curExt == null ? null : Utils.FindFile(string.Format("{0}.{1}", path, curExt), context.CurrentParseTree.FileName)
                  ?? Utils.FindFile(path, context.CurrentParseTree.FileName)
                  ?? Utils.FindFile(string.Format("{0}.uosl", path), context.CurrentParseTree.FileName)
                  ?? Utils.FindFile(string.Format("{0}.uosl.q", path), context.CurrentParseTree.FileName);

            if (fullpath != null)
            {
                fullpath = (new FileInfo(fullpath)).FullName;

                FileInfo fi = new FileInfo(fullpath);

                ParseCache cache;

                if (!Inherits.TryGetValue(fullpath, out cache) || fi.LastWriteTime > cache.FileDate)
                {
                    Inherits[fullpath] = cache = new ParseCache(fi.LastWriteTime);

                    LanguageOption options = Utils.DetermineFileLanguage(fullpath, this.Options);

                    ParsingContext subcontext = new ParsingContext(new Parser(options == this.Options ? this : GetGrammar(options)));

                    using (StreamReader reader = new StreamReader(fullpath))
                    {
                        Inherits[fullpath] = cache = new ParseCache(fi.LastWriteTime, subcontext.Parser.Parse(reader.ReadToEnd(), fullpath));
                    }
                }

                if (refDepends != null)
                {
                    refDepends.Add(path, fullpath);
                }

                if (cache.Tree != null)
                {
                    if (cache.Tree.HasErrors())
                    {
                        foreach (ParserMessage error in cache.Tree.ParserMessages)
                        {
                            if (error is ExternalErrorMessage)
                            {
                                context.AddParserMessage(error);
                            }
                            else
                            {
                                context.AddParserMessage(new ExternalErrorMessage(fullpath, error.Level, error.Location, error.Message, error.ParserState));
                            }
                        }
                    }
                    if (cache.Tree.Root != null && cache.Tree.Root.AstNode != null)
                    {
                        if (((ScopedNode)cache.Tree.Root.AstNode).ScopeVars != null)
                        {
                            foreach (Field field in ((ScopedNode)cache.Tree.Root.AstNode).ScopeVars)
                            {
                                node.AddVar(field, context);
                            }
                        }
                        if (((ScopedNode)cache.Tree.Root.AstNode).TreeFuncs != null)
                        {
                            foreach (Method method in ((ScopedNode)cache.Tree.Root.AstNode).TreeFuncs)
                            {
                                AddFunc(method, context);
                            }
                        }

                        if (refDepends != null && cache.Tree.Root.FirstChild.AstNode is DeclarationsNode)
                        {
                            foreach (var kvp in ((DeclarationsNode)cache.Tree.Root.FirstChild.AstNode).Depends)
                            {
                                if (refDepends.ContainsKey(kvp.Key))
                                {
                                    context.AddParserMessage(ParserErrorLevel.Error, node.Span, "A recursion of inheritance detected occurred when parsing {0}.", kvp.Key);
                                }
                                else
                                {
                                    refDepends.Add(kvp.Key, kvp.Value);
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                context.AddParserError("{0} Dependancy not found.", path);
            }
        }
Beispiel #22
0
        void ICompletionSource.AugmentCompletionSession(ICompletionSession session, IList <CompletionSet> completionSets)
        {
            List <string> strList = new List <string>();

            SnapshotPoint point = session.GetTriggerPoint(m_textBuffer).GetPoint(m_textBuffer.CurrentSnapshot);

            if (nodeprovider.isComment(point))
            {
                return;
            }

            Node node = nodeprovider.GetMostSpecificNode(point);

            List <Completion> m_compList = null;

            if (node != null && node.astnode is ScopedNode)
            {
                var terms = ((ScopedNode)node.astnode).ExpectedTerms.Where(term => term.FlagIsSet(Irony.Parsing.TermFlags.IsKeyword) || term.FlagIsSet(Irony.Parsing.TermFlags.IsPunctuation));
                if (terms.Count() > 0)
                {
                    foreach (var term in terms)
                    {
                        if (!strList.Contains(term.Name))
                        {
                            strList.Add(term.Name);
                        }
                    }
                }
                else
                {
                    foreach (var term in UOSL.Service.UOSLBase.Keywords)
                    {
                        if (!strList.Contains(term.Key))
                        {
                            strList.Add(term.Key);
                        }
                    }
                }

                if (strList.Count > 0)
                {
                    foreach (string str in strList)
                    {
                        (m_compList ?? (m_compList = new List <Completion>())).Add(new Completion(str, str, str, null, null));
                    }

                    strList.Clear();
                }
            }


            if (node == null || node.astnode.AsString == "Declarations" || node.astnode.AsString == "Script")
            {
                int pos = point.Position;
                // move to beginning of previous word
                while ((pos >= point.Snapshot.Length || char.IsWhiteSpace(point.Snapshot[pos])) && pos >= 0)
                {
                    pos--;
                }
                int end = pos;
                while (!char.IsWhiteSpace(point.Snapshot[pos]) && pos >= 0)
                {
                    pos--;
                }
                string keyword = pos > 0 && pos < end?point.Snapshot.GetText(pos + 1, end - pos) : null;

                if (keyword == "trigger" && m_trigsNames != null)
                {
                    completionSets.Add(new CompletionSet(
                                           "Triggers", //the non-localized title of the tab
                                           "Triggers", //the display title of the tab
                                           FindTokenSpanAtPosition(session.GetTriggerPoint(m_textBuffer),
                                                                   session),
                                           m_trigsNames,
                                           null));
                }
                else if (m_types != null && keyword == "function" || keyword == "member" || keyword == "forward")
                {
                    completionSets.Add(new CompletionSet(
                                           "Types", //the non-localized title of the tab
                                           "Types", //the display title of the tab
                                           FindTokenSpanAtPosition(session.GetTriggerPoint(m_textBuffer),
                                                                   session),
                                           m_types,
                                           null));
                }
                else if (m_trigsFull != null)
                {
                    if (m_compList != null)
                    {
                        completionSets.Add(new CompletionSet(
                                               "Keywords", //the non-localized title of the tab
                                               "Keywords", //the display title of the tab
                                               FindTokenSpanAtPosition(session.GetTriggerPoint(m_textBuffer),
                                                                       session),
                                               m_compList,
                                               null));
                    }

                    completionSets.Add(new CompletionSet(
                                           "Triggers", //the non-localized title of the tab
                                           "Triggers", //the display title of the tab
                                           FindTokenSpanAtPosition(session.GetTriggerPoint(m_textBuffer),
                                                                   session),
                                           m_trigsFull,
                                           null));
                }
                else if (m_compList != null)
                {
                    completionSets.Add(new CompletionSet(
                                           "Keywords", //the non-localized title of the tab
                                           "Keywords", //the display title of the tab
                                           FindTokenSpanAtPosition(session.GetTriggerPoint(m_textBuffer),
                                                                   session),
                                           m_compList,
                                           null));
                }
            }
            else
            {
                if (m_compList != null)
                {
                    completionSets.Add(new CompletionSet(
                                           "Keywords", //the non-localized title of the tab
                                           "Keywords", //the display title of the tab
                                           FindTokenSpanAtPosition(session.GetTriggerPoint(m_textBuffer),
                                                                   session),
                                           m_compList,
                                           null));
                }

                ScopedNode snode = node.astnode as ScopedNode;
                if (snode.ScopeVars != null)
                {
                    foreach (var var in snode.ScopeVars)
                    {
                        strList.Add(var.Name);
                    }

                    if (strList.Count > 0)
                    {
                        strList.Sort();

                        m_compList = new List <Completion>();
                        foreach (string str in strList)
                        {
                            m_compList.Add(new Completion(str, str, str, null, null));
                        }

                        completionSets.Add(new CompletionSet(
                                               "Vars", //the non-localized title of the tab
                                               "Vars", //the display title of the tab
                                               FindTokenSpanAtPosition(session.GetTriggerPoint(m_textBuffer),
                                                                       session),
                                               m_compList,
                                               null));

                        strList.Clear();
                    }
                }

                if (nodeprovider.Funcs != null)
                {
                    foreach (var func in nodeprovider.Funcs)
                    {
                        if (!strList.Contains(func.Name))
                        {
                            strList.Add(func.Name);
                        }
                    }

                    if (strList.Count > 0)
                    {
                        strList.Sort();

                        m_compList = new List <Completion>();
                        foreach (string str in strList)
                        {
                            m_compList.Add(new Completion(str, str, str, null, null));
                        }

                        completionSets.Add(new CompletionSet(
                                               "Funcs", //the non-localized title of the tab
                                               "Funcs", //the display title of the tab
                                               FindTokenSpanAtPosition(session.GetTriggerPoint(m_textBuffer),
                                                                       session),
                                               m_compList,
                                               null));
                    }

                    strList.Clear();
                }

                if (m_core != null)
                {
                    completionSets.Add(new CompletionSet(
                                           "Core", //the non-localized title of the tab
                                           "Core", //the display title of the tab
                                           FindTokenSpanAtPosition(session.GetTriggerPoint(m_textBuffer),
                                                                   session),
                                           m_core,
                                           null));
                }
            }
        }
Beispiel #23
0
        //   private OperationOutcome validateElement(ElementDefinitionNavigator definition, IElementNavigator instance)

        private OperationOutcome validateElement(ElementDefinitionNavigator definition, ScopedNode instance)
        {
            var outcome = new OperationOutcome();

            Trace(outcome, $"Start validation of ElementDefinition at path '{definition.QualifiedDefinitionPath()}'", Issue.PROCESSING_PROGRESS, instance);

            // If navigator cannot be moved to content, there's really nothing to validate against.
            if (definition.AtRoot && !definition.MoveToFirstChild())
            {
                outcome.AddIssue($"Snapshot component of profile '{definition.StructureDefinition?.Url}' has no content.", Issue.PROFILE_ELEMENTDEF_IS_EMPTY, instance);
                return(outcome);
            }

            // This does not work, since the children might still be empty, we need something better
            //// Any node must either have a value, or children, or both (e.g. extensions on primitives)
            if (instance.Value == null && !instance.Children().Any())
            {
                outcome.AddIssue("Element must not be empty", Issue.CONTENT_ELEMENT_MUST_HAVE_VALUE_OR_CHILDREN, instance);
                return(outcome);
            }

            var elementConstraints = definition.Current;

            if (elementConstraints.IsPrimitiveValueConstraint())
            {
                // The "value" property of a FHIR Primitive is the bottom of our recursion chain, it does not have a nameReference
                // nor a <type>, the only thing left to do to validate the content is to validate the string representation of the
                // primitive against the regex given in the core definition
                outcome.Add(VerifyPrimitiveContents(elementConstraints, instance));
            }
            else
            {
                bool isInlineChildren = !definition.Current.IsRootElement();

                // Now, validate the children
                if (definition.HasChildren)
                {
                    // If we are at the root of an abstract type (e.g. is this instance a Resource)?
                    // or we are at a nested resource, we may expect more children in the instance than
                    // we know about
                    bool allowAdditionalChildren = (isInlineChildren && elementConstraints.IsResourcePlaceholder()) ||
                                                   (!isInlineChildren && definition.StructureDefinition.Abstract == true);

                    // Handle in-lined constraints on children. In a snapshot, these children should be exhaustive,
                    // so there's no point in also validating the <type> or <nameReference>
                    // TODO: Check whether this is even true when the <type> has a profile?
                    // Note: the snapshot is *not* exhaustive if the declared type is a base FHIR type (like Resource),
                    // in which case there may be additional children (verified in the next step)
                    outcome.Add(this.ValidateChildConstraints(definition, instance, allowAdditionalChildren: allowAdditionalChildren));

                    // Special case: if we are located at a nested resource (i.e. contained or Bundle.entry.resource),
                    // we need to validate based on the actual type of the instance
                    if (isInlineChildren && elementConstraints.IsResourcePlaceholder())
                    {
                        outcome.Add(this.ValidateType(elementConstraints, instance));
                    }
                }

                if (!definition.HasChildren)
                {
                    // No inline-children, so validation depends on the presence of a <type> or <nameReference>
                    if (elementConstraints.Type != null || elementConstraints.NameReference != null)
                    {
                        outcome.Add(this.ValidateType(elementConstraints, instance));
                        outcome.Add(ValidateNameReference(elementConstraints, definition, instance));
                    }
                    else
                    {
                        Trace(outcome, "ElementDefinition has no child, nor does it specify a type or nameReference to validate the instance data against", Issue.PROFILE_ELEMENTDEF_CONTAINS_NO_TYPE_OR_NAMEREF, instance);
                    }
                }
            }

            outcome.Add(this.ValidateFixed(elementConstraints, instance));
            outcome.Add(this.ValidatePattern(elementConstraints, instance));
            outcome.Add(this.ValidateMinMaxValue(elementConstraints, instance));
            outcome.Add(ValidateMaxLength(elementConstraints, instance));
            outcome.Add(this.ValidateFp(elementConstraints, instance));
            outcome.Add(this.ValidateBinding(elementConstraints, instance));
            outcome.Add(this.ValidateExtension(elementConstraints, instance, "http://hl7.org/fhir/StructureDefinition/regex"));

            // If the report only has partial information, no use to show the hierarchy, so flatten it.
            if (Settings.Trace == false)
            {
                outcome.Flatten();
            }

            return(outcome);
        }
Beispiel #24
0
        public static OperationOutcome ValidateFp(this Validator v, ElementDefinition definition, ScopedNode instance)
        {
            var outcome = new OperationOutcome();

            if (!definition.Constraint.Any())
            {
                return(outcome);
            }
            if (v.Settings.SkipConstraintValidation)
            {
                return(outcome);
            }

            var context = instance.ResourceContext;

            foreach (var constraintElement in definition.Constraint)
            {
                bool success = false;

                try
                {
                    var compiled = getExecutableConstraint(v, outcome, instance, constraintElement);
                    success = compiled.Predicate(instance, new FhirEvaluationContext(context)
                    {
                        ElementResolver = callExternalResolver
                    });
                }
                catch (Exception e)
                {
                    v.Trace(outcome, $"Evaluation of FhirPath for constraint '{constraintElement.Key}' failed: {e.Message}",
                            Issue.PROFILE_ELEMENTDEF_INVALID_FHIRPATH_EXPRESSION, instance);
                }

                if (!success)
                {
                    var text  = "Instance failed constraint " + constraintElement.ConstraintDescription();
                    var issue = constraintElement.Severity == ElementDefinition.ConstraintSeverity.Error ?
                                Issue.CONTENT_ELEMENT_FAILS_ERROR_CONSTRAINT : Issue.CONTENT_ELEMENT_FAILS_WARNING_CONSTRAINT;

                    v.Trace(outcome, text, issue, instance);
                }
            }

            return(outcome);

            ITypedElement callExternalResolver(string url)
            {
                OperationOutcome o = new OperationOutcome();
                var result         = v.ExternalReferenceResolutionNeeded(url, o, "dummy");

                if (o.Success && result != null)
                {
                    return(result);
                }

                return(null);
            }
        }
Beispiel #25
0
 private static Func <OperationOutcome> createValidatorForTypeRef(Validator validator, ScopedNode instance, ElementDefinition.TypeRefComponent tr)
 {
     // In STU3, we need to do BOTH
     // First, call Validate() against the profile (which is then a profile on Reference) THEN validate the referenced resource
     if (tr.Code == FHIRDefinedType.Reference)
     {
         return(() => validator.ValidateResourceReference(instance, tr));
     }
     else
     {
         return(() => validator.Validate(instance, tr.GetDeclaredProfiles(), statedCanonicals: null, statedProfiles: null));
     }
 }
Beispiel #26
0
        internal static OperationOutcome ValidateTypeReferences(this Validator validator,
                                                                IEnumerable <ElementDefinition.TypeRefComponent> typeRefs, ScopedNode instance)
        {
            //TODO: It's more efficient to do the non-reference types FIRST, since ANY match would be ok,
            //and validating non-references is cheaper
            //TODO: For each choice, we will currently try to resolve the reference. If it fails, you'll get multiple errors and probably
            //better separate the fetching of the instance from the validation, so we do not run the rest of the validation (multiple times!)
            //when a reference cannot be resolved.  (this happens in a choice type where there are multiple references with multiple profiles)

            IEnumerable <Func <OperationOutcome> > validations = typeRefs.Select(tr => createValidatorForTypeRef(validator, instance, tr));

            return(validator.Combine(BatchValidationMode.Any, instance, validations));
        }
Beispiel #27
0
        internal static OperationOutcome ValidateType(this Validator validator, ElementDefinition definition, ScopedNode instance)
        {
            var outcome = new OperationOutcome();

            validator.Trace(outcome, "Validating against constraints specified by the element's defined type", Issue.PROCESSING_PROGRESS, instance);

            if (definition.Type.Any(tr => tr.Code == null))
            {
                validator.Trace(outcome, "ElementDefinition contains a type with an empty type code", Issue.PROFILE_ELEMENTDEF_CONTAINS_NULL_TYPE, instance);
            }

            // Check if this is a choice: there are multiple distinct Codes to choose from
            var typeRefs = definition.Type.Where(tr => tr.Code != null);
            var choices  = typeRefs.Select(tr => tr.Code.Value).Distinct();

            if (choices.Count() > 1)
            {
                if (instance.InstanceType != null)
                {
                    // This is a choice type, find out what type is present in the instance data
                    // (e.g. deceased[Boolean], or _resourceType in json). This is exposed by IElementNavigator.TypeName.
                    var instanceType = ModelInfo.FhirTypeNameToFhirType(instance.InstanceType);
                    if (instanceType != null)
                    {
                        // In fact, the next statements are just an optimalization, without them, we would do an ANY validation
                        // against *all* choices, what we do here is pre-filtering for sensible choices, and report if there isn't
                        // any.
                        var applicableChoices = typeRefs.Where(tr => ModelInfo.IsInstanceTypeFor(tr.Code.Value, instanceType.Value));

                        // Instance typename must be one of the applicable types in the choice
                        if (applicableChoices.Any())
                        {
                            outcome.Include(validator.ValidateTypeReferences(applicableChoices, instance));
                        }
                        else
                        {
                            var choiceList = String.Join(",", choices.Select(t => "'" + t.GetLiteral() + "'"));
                            validator.Trace(outcome, $"Type specified in the instance ('{instance.InstanceType}') is not one of the allowed choices ({choiceList})",
                                            Issue.CONTENT_ELEMENT_HAS_INCORRECT_TYPE, instance);
                        }
                    }
                    else
                    {
                        validator.Trace(outcome, $"Instance indicates the element is of type '{instance.InstanceType}', which is not a known FHIR core type.",
                                        Issue.CONTENT_ELEMENT_CHOICE_INVALID_INSTANCE_TYPE, instance);
                    }
                }
                else
                {
                    validator.Trace(outcome, "ElementDefinition is a choice or contains a polymorphic type constraint, but the instance does not indicate its actual type",
                                    Issue.CONTENT_ELEMENT_CANNOT_DETERMINE_TYPE, instance);
                }
            }
            else if (choices.Count() == 1)
            {
                // Only one type present in list of typerefs, all of the typerefs are candidates
                outcome.Include(validator.ValidateTypeReferences(typeRefs, instance));
            }

            return(outcome);
        }
        private static OperationOutcome ValidateMatch(this Validator validator, Match match, ScopedNode parent)
        {
            var outcome = new OperationOutcome();

            var definition = match.Definition.Current;

            if (definition.Min == null)
            {
                validator.Trace(outcome, $"Element definition does not specify a 'min' value, which is required. Cardinality has not been validated",
                                Issue.PROFILE_ELEMENTDEF_CARDINALITY_MISSING, parent);
            }
            else if (definition.Max == null)
            {
                validator.Trace(outcome, $"Element definition does not specify a 'max' value, which is required. Cardinality has not been validated",
                                Issue.PROFILE_ELEMENTDEF_CARDINALITY_MISSING, parent);
            }

            var cardinality = Cardinality.FromElementDefinition(definition);

            IBucket bucket;

            try
            {
                bucket = BucketFactory.CreateRoot(match.Definition, validator);
            }
            catch (NotImplementedException ni)
            {
                // Will throw if a non-supported slice type is encountered
                validator.Trace(outcome, ni.Message, Issue.UNSUPPORTED_SLICING_NOT_SUPPORTED, parent);
                return(outcome);
            }

            foreach (var element in match.InstanceElements)
            {
                var success = bucket.Add(element);

                // For the "root" slice group (=the original core element that was sliced, not resliced)
                // any element that does not match is an error
                // Since the ChildNameMatcher currently does the matching, this will never go wrong
            }

            outcome.Add(bucket.Validate(validator, parent));

            return(outcome);
        }
Beispiel #29
0
        internal static OperationOutcome ValidateResourceReference(this Validator validator, ScopedNode instance, ElementDefinition.TypeRefComponent typeRef)
        {
            var outcome = new OperationOutcome();

            var reference = instance.ParseResourceReference()?.Reference;

            if (reference == null)       // No reference found -> this is always valid
            {
                return(outcome);
            }


            // Try to resolve the reference *within* the current instance (Bundle, resource with contained resources) first
            var referencedResource = validator.resolveReference(instance, reference,
                                                                out ElementDefinition.AggregationMode? encounteredKind, outcome);

            // Validate the kind of aggregation.
            // If no aggregation is given, all kinds of aggregation are allowed, otherwise only allow
            // those aggregation types that are given in the Aggregation element
            bool hasAggregation = typeRef.Aggregation != null && typeRef.Aggregation.Count() != 0;

            if (hasAggregation && !typeRef.Aggregation.Any(a => a == encounteredKind))
            {
                validator.Trace(outcome, $"Encountered a reference ({reference}) of kind '{encounteredKind}' which is not allowed", Issue.CONTENT_REFERENCE_OF_INVALID_KIND, instance);
            }

            // Bail out if we are asked to follow an *external reference* when this is disabled in the settings
            if (validator.Settings.ResolveExteralReferences == false && encounteredKind == ElementDefinition.AggregationMode.Referenced)
            {
                return(outcome);
            }

            // If we failed to find a referenced resource within the current instance, try to resolve it using an external method
            if (referencedResource == null && encounteredKind == ElementDefinition.AggregationMode.Referenced)
            {
                try
                {
                    referencedResource = validator.ExternalReferenceResolutionNeeded(reference, outcome, instance.Location);
                }
                catch (Exception e)
                {
                    validator.Trace(outcome, $"Resolution of external reference {reference} failed. Message: {e.Message}",
                                    Issue.UNAVAILABLE_REFERENCED_RESOURCE, instance);
                }
            }

            // If the reference was resolved (either internally or externally, validate it
            if (referencedResource != null)
            {
                validator.Trace(outcome, $"Starting validation of referenced resource {reference} ({encounteredKind})", Issue.PROCESSING_START_NESTED_VALIDATION, instance);

                // References within the instance are dealt with within the same validator,
                // references to external entities will operate within a new instance of a validator (and hence a new tracking context).
                // In both cases, the outcome is included in the result.
                OperationOutcome childResult;

                if (encounteredKind != ElementDefinition.AggregationMode.Referenced)
                {
                    childResult = validator.Validate(referencedResource, typeRef.GetDeclaredProfiles(), statedProfiles: null, statedCanonicals: null);
                }
                else
                {
                    var newValidator = validator.NewInstance();
                    childResult = newValidator.Validate(referencedResource, typeRef.GetDeclaredProfiles(), statedProfiles: null, statedCanonicals: null);
                }

                // Prefix each path with the referring resource's path to keep the locations
                // interpretable
                foreach (var issue in childResult.Issue)
                {
                    issue.Location = issue.Location.Concat(new string[] { instance.Location });
                }

                outcome.Include(childResult);
            }
            else
            {
                validator.Trace(outcome, $"Cannot resolve reference {reference}", Issue.UNAVAILABLE_REFERENCED_RESOURCE, instance);
            }

            return(outcome);
        }
Beispiel #30
0
        internal OperationOutcome ValidateNameReference(ElementDefinition definition, ElementDefinitionNavigator allDefinitions, ScopedNode instance)
        {
            var outcome = new OperationOutcome();

            if (definition.NameReference != null)
            {
                Trace(outcome, $"Start validation of constraints referred to by nameReference '{definition.NameReference}'", Issue.PROCESSING_PROGRESS, instance);

                var referencedPositionNav = allDefinitions.ShallowCopy();

                if (referencedPositionNav.JumpToNameReference(definition.NameReference))
                {
                    outcome.Include(Validate(instance, referencedPositionNav));
                }
                else
                {
                    Trace(outcome, $"ElementDefinition uses a non-existing nameReference '{definition.NameReference}'", Issue.PROFILE_ELEMENTDEF_INVALID_NAMEREFERENCE, instance);
                }
            }

            return(outcome);
        }