/// <summary>
        /// Try match the particle once.
        /// </summary>
        /// <param name="particleMatchInfo"></param>
        /// <param name="validationContext">The context information for validation.</param>
        public override void TryMatchOnce(ParticleMatchInfo particleMatchInfo, ValidationContext validationContext)
        {
            Debug.Assert(!(particleMatchInfo.StartElement is OpenXmlMiscNode));

            var next = particleMatchInfo.StartElement;

            particleMatchInfo.LastMatchedElement = null;
            particleMatchInfo.Match = ParticleMatch.Nomatch;

            ParticleConstraint childConstraint;
            int constraintIndex = 0;
            int constraintTotal = ParticleConstraint.ChildrenParticles.Length;

            var childMatchInfo = new ParticleMatchInfo();

            while (constraintIndex < constraintTotal && next != null)
            {
                childConstraint = ParticleConstraint.ChildrenParticles[constraintIndex];

                // Use Reset() instead of new() to avoid heavy memory allocation and GC.
                childMatchInfo.Reset(next);

                childConstraint.ParticleValidator.TryMatch(childMatchInfo, validationContext);

                // if the _childMatchInfo.StartElement is changed, it means this method of this object is called more than once on the stack.
                Debug.Assert(childMatchInfo.StartElement == next);

                switch (childMatchInfo.Match)
                {
                case ParticleMatch.Nomatch:
                    // continue trying match next child constraint.
                    constraintIndex++;
                    break;

                case ParticleMatch.Matched:
                    particleMatchInfo.Match = ParticleMatch.Matched;
                    particleMatchInfo.LastMatchedElement = childMatchInfo.LastMatchedElement;
                    return;

                case ParticleMatch.Partial:
                    // partial match, incomplete children.
                    particleMatchInfo.Match = ParticleMatch.Partial;
                    particleMatchInfo.LastMatchedElement = childMatchInfo.LastMatchedElement;
                    if (validationContext.CollectExpectedChildren)
                    {
                        particleMatchInfo.SetExpectedChildren(childMatchInfo.ExpectedChildren);
                    }

                    return;
                }
            }

            // no match
            Debug.Assert(particleMatchInfo.Match == ParticleMatch.Nomatch);
            return;
        }
Пример #2
0
        public override void TryMatch(ParticleMatchInfo particleMatchInfo, ValidationContext validationContext)
        {
            if (ParticleConstraint.MaxOccurs == 1)
            {
                TryMatchOnce(particleMatchInfo, validationContext);
            }
            else
            {
                int matchCount = 0;
                var next       = particleMatchInfo.StartElement;

                var childMatchInfo = new ParticleMatchInfo();

                while (next is not null && ParticleConstraint.MaxOccursGreaterThan(matchCount))
                {
                    // Use Reset() instead of new() to avoid heavy memory allocation and GC.
                    childMatchInfo.Reset(next);
                    TryMatchOnce(childMatchInfo, validationContext);

                    // if the _childMatchInfo.StartElement is changed, it means this method of this object is called more than once on the stack.
                    Debug.Assert(childMatchInfo.StartElement == next);

                    if (childMatchInfo.Match == ParticleMatch.Nomatch)
                    {
                        break;
                    }
                    else if (childMatchInfo.Match == ParticleMatch.Matched)
                    {
                        matchCount++;
                        particleMatchInfo.LastMatchedElement = childMatchInfo.LastMatchedElement;
                        next = validationContext.GetNextChildMc(particleMatchInfo.LastMatchedElement);
                    }
                    else
                    {
                        // return error
                        particleMatchInfo.Match = ParticleMatch.Partial;
                        particleMatchInfo.LastMatchedElement = childMatchInfo.LastMatchedElement;
                        if (validationContext.CollectExpectedChildren)
                        {
                            particleMatchInfo.SetExpectedChildren(childMatchInfo.ExpectedChildren);
                        }

                        return;
                    }
                }

                if (matchCount == 0)
                {
                    particleMatchInfo.Match = ParticleMatch.Nomatch;
                    if (validationContext.CollectExpectedChildren)
                    {
                        particleMatchInfo.SetExpectedChildren(GetExpectedElements());
                    }
                }
                else if (matchCount >= ParticleConstraint.MinOccurs)
                {
                    // matched OK
                    particleMatchInfo.Match = ParticleMatch.Matched;
                }
                else
                {
                    if (GetRequiredElements(particleMatchInfo.ExpectedChildren))
                    {
                        // minOccurs failed, incomplete children.
                        particleMatchInfo.Match = ParticleMatch.Partial;
                    }
                    else
                    {
                        // all children elements are optional
                        particleMatchInfo.Match = ParticleMatch.Matched;
                    }
                }
            }

            return;
        }
        /// <summary>
        /// Try match the particle once.
        /// </summary>
        /// <param name="particleMatchInfo"></param>
        /// <param name="validationContext">The context information for validation.</param>
        public override void TryMatchOnce(ParticleMatchInfo particleMatchInfo, ValidationContext validationContext)
        {
            Debug.Assert(!(particleMatchInfo.StartElement is OpenXmlMiscNode));

            var next = particleMatchInfo.StartElement;

            particleMatchInfo.LastMatchedElement = null;
            particleMatchInfo.Match = ParticleMatch.Nomatch;

            ParticleConstraint childConstraint;
            int constraintIndex = 0;
            int constraintTotal = this.ParticleConstraint.ChildrenParticles.Length;

            while (constraintIndex < constraintTotal && next != null)
            {
                childConstraint = this.ParticleConstraint.ChildrenParticles[constraintIndex];

                // Use Reset() instead of new() to avoid heavy memory alloction and GC.
                _childMatchInfo.Reset(next);

                childConstraint.ParticleValidator.TryMatch(_childMatchInfo, validationContext);

                // if the _childMatchInfo.StartElement is changed, it means this method of this object is called more than once on the stack.
                Debug.Assert(_childMatchInfo.StartElement == next);

                switch (_childMatchInfo.Match)
                {
                case ParticleMatch.Nomatch:
                    if (childConstraint.ParticleValidator.GetRequiredElements(null))
                    {
                        if (validationContext.CollectExpectedChildren)
                        {
                            if (particleMatchInfo.ExpectedChildren == null)
                            {
                                particleMatchInfo.SetExpectedChildren(childConstraint.ParticleValidator.GetRequiredElements());
                            }
                            else
                            {
                                // reuse same object, avoid object alloction.
                                particleMatchInfo.ExpectedChildren.Clear();
                                childConstraint.ParticleValidator.GetRequiredElements(particleMatchInfo.ExpectedChildren);
                            }
                        }

                        // incomplete children.
                        if (next == particleMatchInfo.StartElement)
                        {
                            // the first child is not the correct one.
                            particleMatchInfo.Match = ParticleMatch.Nomatch;
                            particleMatchInfo.LastMatchedElement = null;
                            return;
                        }
                        else
                        {
                            // partial match, incomplete children.
                            particleMatchInfo.Match = ParticleMatch.Partial;
                            return;
                        }
                    }
                    else
                    {
                        // continue trying match next child constraint.
                        constraintIndex++;
                        continue;
                    }

                case ParticleMatch.Matched:
                    particleMatchInfo.LastMatchedElement = _childMatchInfo.LastMatchedElement;
                    next = validationContext.GetNextChildMc(particleMatchInfo.LastMatchedElement);
                    // continue trying match next child constraint.
                    constraintIndex++;
                    break;

                case ParticleMatch.Partial:
                    // partial match, incomplete children.
                    particleMatchInfo.Match = ParticleMatch.Partial;
                    particleMatchInfo.LastMatchedElement = _childMatchInfo.LastMatchedElement;
                    if (validationContext.CollectExpectedChildren)
                    {
                        particleMatchInfo.SetExpectedChildren(_childMatchInfo.ExpectedChildren);
                    }
                    return;
                }
            }

            if (constraintIndex == constraintTotal)
            {
                if (particleMatchInfo.LastMatchedElement != null)
                {
                    particleMatchInfo.Match = ParticleMatch.Matched;
                }
                else
                {
                    particleMatchInfo.Match = ParticleMatch.Nomatch;
                }
                return;
            }
            else
            {
                for (; constraintIndex < constraintTotal; constraintIndex++)
                {
                    if (this.ParticleConstraint.ChildrenParticles[constraintIndex].ParticleValidator.GetRequiredElements(null))
                    {
                        if (validationContext.CollectExpectedChildren)
                        {
                            if (particleMatchInfo.ExpectedChildren == null)
                            {
                                particleMatchInfo.InitExpectedChildren();
                            }
                            this.ParticleConstraint.ChildrenParticles[constraintIndex].ParticleValidator.GetRequiredElements(particleMatchInfo.ExpectedChildren);
                        }
                        particleMatchInfo.Match = ParticleMatch.Partial;
                        return;
                    }
                }
                // all other children constraint are optional.
                particleMatchInfo.Match = ParticleMatch.Matched;
                return;
            }
        }