|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace MS.Internal.Xml.XPath
{
using System;
using Microsoft.Xml;
using Microsoft.Xml.XPath;
using System.Diagnostics;
using Microsoft.Xml.Xsl;
internal sealed class UnionExpr : Query
{
internal Query qy1, qy2;
private bool _advance1,_advance2;
private XPathNavigator _currentNode;
private XPathNavigator _nextNode;
public UnionExpr(Query query1, Query query2)
{
this.qy1 = query1;
this.qy2 = query2;
_advance1 = true;
_advance2 = true;
}
private UnionExpr(UnionExpr other) : base(other)
{
this.qy1 = Clone(other.qy1);
this.qy2 = Clone(other.qy2);
_advance1 = other._advance1;
_advance2 = other._advance2;
_currentNode = Clone(other._currentNode);
_nextNode = Clone(other._nextNode);
}
public override void Reset()
{
qy1.Reset();
qy2.Reset();
_advance1 = true;
_advance2 = true;
_nextNode = null;
}
public override void SetXsltContext(XsltContext xsltContext)
{
qy1.SetXsltContext(xsltContext);
qy2.SetXsltContext(xsltContext);
}
public override object Evaluate(XPathNodeIterator context)
{
qy1.Evaluate(context);
qy2.Evaluate(context);
_advance1 = true;
_advance2 = true;
_nextNode = null;
base.ResetCount();
return this;
}
private XPathNavigator ProcessSamePosition(XPathNavigator result)
{
_currentNode = result;
_advance1 = _advance2 = true;
return result;
}
private XPathNavigator ProcessBeforePosition(XPathNavigator res1, XPathNavigator res2)
{
_nextNode = res2;
_advance2 = false;
_advance1 = true;
_currentNode = res1;
return res1;
}
private XPathNavigator ProcessAfterPosition(XPathNavigator res1, XPathNavigator res2)
{
_nextNode = res1;
_advance1 = false;
_advance2 = true;
_currentNode = res2;
return res2;
}
public override XPathNavigator Advance()
{
XPathNavigator res1, res2;
XmlNodeOrder order = 0;
if (_advance1)
{
res1 = qy1.Advance();
}
else
{
res1 = _nextNode;
}
if (_advance2)
{
res2 = qy2.Advance();
}
else
{
res2 = _nextNode;
}
if (res1 != null && res2 != null)
{
order = CompareNodes(res1, res2);
}
else if (res2 == null)
{
_advance1 = true;
_advance2 = false;
_currentNode = res1;
_nextNode = null;
return res1;
}
else
{
_advance1 = false;
_advance2 = true;
_currentNode = res2;
_nextNode = null;
return res2;
}
if (order == XmlNodeOrder.Before)
{
return ProcessBeforePosition(res1, res2);
}
else if (order == XmlNodeOrder.After)
{
return ProcessAfterPosition(res1, res2);
}
else
{
// BugBug. In case of Unknown we sorting as the same.
return ProcessSamePosition(res1);
}
}
public override XPathNavigator MatchNode(XPathNavigator xsltContext)
{
if (xsltContext != null)
{
XPathNavigator result = qy1.MatchNode(xsltContext);
if (result != null)
{
return result;
}
return qy2.MatchNode(xsltContext);
}
return null;
}
public override XPathResultType StaticType { get { return XPathResultType.NodeSet; } }
public override XPathNodeIterator Clone() { return new UnionExpr(this); }
public override XPathNavigator Current { get { return _currentNode; } }
public override int CurrentPosition { get { throw new InvalidOperationException(); } }
public override void PrintQuery(XmlWriter w)
{
w.WriteStartElement(this.GetType().Name);
if (qy1 != null)
{
qy1.PrintQuery(w);
}
if (qy2 != null)
{
qy2.PrintQuery(w);
}
w.WriteEndElement();
}
}
}
|