1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
|
//------------------------------------------------------------------------------
// <copyright file="SiblingIterators.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">Microsoft</owner>
//------------------------------------------------------------------------------
using System;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Schema;
using System.Diagnostics;
using System.Collections;
using System.ComponentModel;
namespace System.Xml.Xsl.Runtime {
/// <summary>
/// Iterate over all following-sibling content nodes.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public struct FollowingSiblingIterator {
private XmlNavigatorFilter filter;
private XPathNavigator navCurrent;
/// <summary>
/// Initialize the FollowingSiblingIterator.
/// </summary>
public void Create(XPathNavigator context, XmlNavigatorFilter filter) {
this.navCurrent = XmlQueryRuntime.SyncToNavigator(this.navCurrent, context);
this.filter = filter;
}
/// <summary>
/// Position the iterator on the next following-sibling node. Return true if such a node exists and
/// set Current property. Otherwise, return false (Current property is undefined).
/// </summary>
public bool MoveNext() {
return this.filter.MoveToFollowingSibling(this.navCurrent);
}
/// <summary>
/// Return the current result navigator. This is only defined after MoveNext() has returned true.
/// </summary>
public XPathNavigator Current {
get { return this.navCurrent; }
}
}
/// <summary>
/// Iterate over child following-sibling nodes. This is a simple variation on the ContentMergeIterator, so use containment
/// to reuse its code (can't use inheritance with structures).
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public struct FollowingSiblingMergeIterator {
private ContentMergeIterator wrapped;
/// <summary>
/// Initialize the FollowingSiblingMergeIterator.
/// </summary>
public void Create(XmlNavigatorFilter filter) {
this.wrapped.Create(filter);
}
/// <summary>
/// Position this iterator to the next content or sibling node. Return IteratorResult.NoMoreNodes if there are
/// no more content or sibling nodes. Return IteratorResult.NeedInputNode if the next input node needs to be
/// fetched first. Return IteratorResult.HaveCurrent if the Current property is set to the next node in the
/// iteration.
/// </summary>
public IteratorResult MoveNext(XPathNavigator navigator) {
return this.wrapped.MoveNext(navigator, false);
}
/// <summary>
/// Return the current result navigator. This is only defined after MoveNext() has returned IteratorResult.HaveCurrent.
/// </summary>
public XPathNavigator Current {
get { return this.wrapped.Current; }
}
}
/// <summary>
/// Iterate over all preceding nodes according to XPath preceding axis rules, returning nodes in reverse
/// document order.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public struct PrecedingSiblingIterator {
private XmlNavigatorFilter filter;
private XPathNavigator navCurrent;
/// <summary>
/// Initialize the PrecedingSiblingIterator.
/// </summary>
public void Create(XPathNavigator context, XmlNavigatorFilter filter) {
this.navCurrent = XmlQueryRuntime.SyncToNavigator(this.navCurrent, context);
this.filter = filter;
}
/// <summary>
/// Return true if the Current property is set to the next Preceding node in reverse document order.
/// </summary>
public bool MoveNext() {
return this.filter.MoveToPreviousSibling(this.navCurrent);
}
/// <summary>
/// Return the current result navigator. This is only defined after MoveNext() has returned true.
/// </summary>
public XPathNavigator Current {
get { return this.navCurrent; }
}
}
/// <summary>
/// Iterate over all preceding-sibling content nodes in document order.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public struct PrecedingSiblingDocOrderIterator {
private XmlNavigatorFilter filter;
private XPathNavigator navCurrent, navEnd;
private bool needFirst, useCompPos;
/// <summary>
/// Initialize the PrecedingSiblingDocOrderIterator.
/// </summary>
public void Create(XPathNavigator context, XmlNavigatorFilter filter) {
this.filter = filter;
this.navCurrent = XmlQueryRuntime.SyncToNavigator(this.navCurrent, context);
this.navEnd = XmlQueryRuntime.SyncToNavigator(this.navEnd, context);
this.needFirst = true;
// If the context node will be filtered out, then use ComparePosition to
// determine when the context node has been passed by. Otherwise, IsSamePosition
// is sufficient to determine when the context node has been reached.
this.useCompPos = this.filter.IsFiltered(context);
}
/// <summary>
/// Position the iterator on the next preceding-sibling node. Return true if such a node exists and
/// set Current property. Otherwise, return false (Current property is undefined).
/// </summary>
public bool MoveNext() {
if (this.needFirst) {
// Get first matching preceding-sibling node
if (!this.navCurrent.MoveToParent())
return false;
if (!this.filter.MoveToContent(this.navCurrent))
return false;
this.needFirst = false;
}
else {
// Get next matching preceding-sibling node
if (!this.filter.MoveToFollowingSibling(this.navCurrent))
return false;
}
// Accept matching sibling only if it precedes navEnd in document order
if (this.useCompPos)
return (this.navCurrent.ComparePosition(this.navEnd) == XmlNodeOrder.Before);
if (this.navCurrent.IsSamePosition(this.navEnd)) {
// Found the original context node, so iteration is complete. If MoveNext
// is called again, use ComparePosition so that false will continue to be
// returned.
this.useCompPos = true;
return false;
}
return true;
}
/// <summary>
/// Return the current result navigator. This is only defined after MoveNext() has returned true.
/// </summary>
public XPathNavigator Current {
get { return this.navCurrent; }
}
}
}
|