/// <summary> /// Return a following sibling of the specified node that has the specified type. If no such /// sibling exists, then do not set pageNode or idxNode and return false. /// </summary> public static bool GetContentSibling(ref XPathNode[] pageNode, ref int idxNode, XPathNodeType typ) { XPathNode[] page = pageNode; int idx = idxNode; int mask = XPathNavigatorEx.GetContentKindMask(typ); Debug.Assert(pageNode != null && idxNode != 0, "Cannot pass null argument(s)"); if (page[idx].NodeType != XPathNodeType.Attribute) { while (true) { idx = page[idx].GetSibling(out page); if (idx == 0) { break; } if (((1 << (int)page[idx].NodeType) & mask) != 0) { Debug.Assert(typ != XPathNodeType.Attribute && typ != XPathNodeType.Namespace); pageNode = page; idxNode = idx; return(true); } } } return(false); }
/// <summary> /// Return the first child of the specified node that has the specified type (must be a content type). If no such /// child exists, then do not set pageNode or idxNode and return false. /// </summary> public static bool GetContentChild(ref XPathNode[] pageNode, ref int idxNode, XPathNodeType typ) { XPathNode[] page = pageNode; int idx = idxNode; int mask; Debug.Assert(pageNode != null && idxNode != 0, "Cannot pass null argument(s)"); // Only check children if at least one content-typed child exists if (page[idx].HasContentChild) { mask = XPathNavigatorEx.GetContentKindMask(typ); GetChild(ref page, ref idx); do { if (((1 << (int)page[idx].NodeType) & mask) != 0) { // Never return attributes, as Attribute is not a content type if (typ == XPathNodeType.Attribute) { return(false); } pageNode = page; idxNode = idx; return(true); } idx = page[idx].GetSibling(out page); }while (idx != 0); } return(false); }
/// <summary> /// Get the next node that: /// 1. Follows the current node in document order (includes descendants, unlike XPath following axis) /// 2. Precedes the ending node in document order (if pageEnd is null, then all following nodes in the document are considered) /// 3. Has the specified XPathNodeType (but Attributes and Namespaces never match) /// If no such node exists, then do not set pageCurrent or idxCurrent and return false. /// </summary> public static bool GetContentFollowing(ref XPathNode[] pageCurrent, ref int idxCurrent, XPathNode[] pageEnd, int idxEnd, XPathNodeType typ) { XPathNode[] page = pageCurrent; int idx = idxCurrent; int mask = XPathNavigatorEx.GetContentKindMask(typ); Debug.Assert(pageCurrent != null && idxCurrent != 0, "Cannot pass null argument(s)"); Debug.Assert(typ != XPathNodeType.Text, "Text should be handled by GetTextFollowing in order to take into account collapsed text."); Debug.Assert(page[idx].NodeType != XPathNodeType.Attribute, "Current node should never be an attribute or namespace--caller should handle this case."); // Since nodes are laid out in document order on pages, scan them sequentially // rather than following sibling/child/parent links. idx++; do { if ((object)page == (object)pageEnd && idx <= idxEnd) { // Only scan to termination point while (idx != idxEnd) { if (((1 << (int)page[idx].NodeType) & mask) != 0) { goto FoundNode; } idx++; } break; } else { // Scan all nodes in the page while (idx < page[0].PageInfo.NodeCount) { if (((1 << (int)page[idx].NodeType) & mask) != 0) { goto FoundNode; } idx++; } } page = page[0].PageInfo.NextPage; idx = 1; }while (page != null); return(false); FoundNode: Debug.Assert(!page[idx].IsAttrNmsp, "GetContentFollowing should never return attributes or namespaces."); // Found match pageCurrent = page; idxCurrent = idx; return(true); }