/// <summary>
        /// Compares xsi:type attribute values
        /// </summary>
        private ComparisonState CompareXsiType(XmlAttribute control,
                                               XPathContext controlContext,
                                               XmlAttribute test,
                                               XPathContext testContext)
        {
            bool mustChangeControlContext = control != null;
            bool mustChangeTestContext    = test != null;

            if (!mustChangeControlContext && !mustChangeTestContext)
            {
                return(new OngoingComparisonState(this));
            }
            bool attributePresentOnBothSides = mustChangeControlContext &&
                                               mustChangeTestContext;

            try {
                XmlQualifiedName controlAttrName = null;
                if (mustChangeControlContext)
                {
                    controlAttrName = control.GetQName();
                    controlContext.AddAttribute(controlAttrName);
                    controlContext.NavigateToAttribute(controlAttrName);
                }
                XmlQualifiedName testAttrName = null;
                if (mustChangeTestContext)
                {
                    testAttrName = test.GetQName();
                    testContext.AddAttribute(testAttrName);
                    testContext.NavigateToAttribute(testAttrName);
                }
                return(Compare(new Comparison(ComparisonType.ATTR_NAME_LOOKUP,
                                              control, GetXPath(controlContext),
                                              controlAttrName,
                                              GetParentXPath(controlContext),
                                              test, GetXPath(testContext),
                                              testAttrName, GetParentXPath(testContext)))
                       .AndIfTrueThen(attributePresentOnBothSides,
                                      () => CompareAttributeExplicitness(control, controlContext,
                                                                         test, testContext))
                       .AndIfTrueThen(attributePresentOnBothSides,
                                      new Comparison(ComparisonType.ATTR_VALUE,
                                                     control, GetXPath(controlContext),
                                                     ValueAsQName(control),
                                                     GetParentXPath(controlContext),
                                                     test, GetXPath(testContext),
                                                     ValueAsQName(test),
                                                     GetParentXPath(testContext))));
            } finally {
                if (mustChangeControlContext)
                {
                    controlContext.NavigateToParent();
                }
                if (mustChangeTestContext)
                {
                    testContext.NavigateToParent();
                }
            }
        }
        private Func <ComparisonState> NormalAttributeComparer(XmlElement control,
                                                               XPathContext controlContext,
                                                               Attributes controlAttributes,
                                                               XmlElement test,
                                                               XPathContext testContext,
                                                               Attributes testAttributes)
        {
            return(() => {
                ComparisonState chain = new OngoingComparisonState(this);
                ICollection <XmlAttribute> foundTestAttributes = new HashSet <XmlAttribute>();

                foreach (XmlAttribute controlAttr
                         in controlAttributes.RemainingAttributes)
                {
                    XmlQualifiedName controlAttrName = controlAttr.GetQName();
                    XmlAttribute testAttr =
                        FindMatchingAttr(testAttributes.RemainingAttributes,
                                         controlAttr);
                    XmlQualifiedName testAttrName = testAttr != null
                        ? testAttr.GetQName() : null;

                    controlContext.NavigateToAttribute(controlAttrName);
                    try {
                        chain =
                            chain.AndThen(new Comparison(ComparisonType.ATTR_NAME_LOOKUP,
                                                         control, GetXPath(controlContext),
                                                         controlAttrName,
                                                         GetParentXPath(controlContext),
                                                         test, GetXPath(testContext),
                                                         testAttrName,
                                                         GetParentXPath(testContext)));

                        if (testAttr != null)
                        {
                            testContext.NavigateToAttribute(testAttrName);
                            try {
                                chain =
                                    chain.AndThen(() =>
                                                  CompareNodes(controlAttr, controlContext,
                                                               testAttr, testContext));

                                foundTestAttributes.Add(testAttr);
                            } finally {
                                testContext.NavigateToParent();
                            }
                        }
                    } finally {
                        controlContext.NavigateToParent();
                    }
                }
                return chain.AndThen(() => {
                    ComparisonState secondChain = new OngoingComparisonState(this);
                    foreach (XmlAttribute testAttr
                             in testAttributes.RemainingAttributes)
                    {
                        if (!foundTestAttributes.Contains(testAttr))
                        {
                            XmlQualifiedName testAttrName = testAttr.GetQName();
                            testContext.NavigateToAttribute(testAttrName);
                            try {
                                secondChain =
                                    secondChain
                                    .AndThen(new Comparison(ComparisonType.ATTR_NAME_LOOKUP,
                                                            control,
                                                            GetXPath(controlContext),
                                                            null, GetParentXPath(controlContext),
                                                            test,
                                                            GetXPath(testContext),
                                                            testAttrName,
                                                            GetParentXPath(testContext)));
                            } finally {
                                testContext.NavigateToParent();
                            }
                        }
                    }
                    return secondChain;
                });
            });
        }