// 对一批互相没有树重叠关系的对象进行筛选 static MarcNodeList simpleSelect(MarcNodeList source, string strXPath, int nMaxCount = -1) { // 准备一个模拟的记录节点 // MarcRecord record = new MarcRecord(); MarcNode temp_root = new MarcNode(); temp_root.Name = "temp"; // 保存下集合中所有的Parent指针 List <MarcNode> parents = new List <MarcNode>(); foreach (MarcNode node in source) { // 保存指针 parents.Add(node.Parent); // 建立父子关系,但原来位置的ChidNodes并不摘除 temp_root.ChildNodes.baseAdd(node); node.Parent = temp_root; // Debug.Assert(node.Parent == temp_root, ""); } Debug.Assert(parents.Count == source.count, ""); try { MarcNodeList results = new MarcNodeList(); MarcNavigator nav = new MarcNavigator(temp_root); // 出发点在模拟的记录节点上 XPathNodeIterator ni = nav.Select(strXPath); while (ni.MoveNext() && (nMaxCount == -1 || results.count < nMaxCount)) { NaviItem item = ((MarcNavigator)ni.Current).Item; if (item.Type != NaviItemType.Element) { throw new Exception("xpath '" + strXPath + "' 命中了非元素类型的节点,这是不允许的"); continue; } if (results.indexOf(item.MarcNode) == -1) // 不重复的才加入 { results.add(item.MarcNode); } } return(results); } finally { // 恢复原先的 Parent 指针 Debug.Assert(parents.Count == source.count, ""); for (int i = 0; i < source.count; i++) { source[i].Parent = parents[i]; } } }
// 针对集合中的元素进行 XPath 筛选 // 本函数不怕同一批元素之间有重叠关系。所采用的策略是一批一批单独筛选,然后把输出结果合成 // parameters: // nMaxCount 至多选择开头这么多个元素。-1表示不限制 /// <summary> /// 针对当前集合中的全部元素进行 XPath 选择 /// </summary> /// <param name="strXPath">XPath字符串</param> /// <param name="nMaxCount">限制命中的最大元素个数。如果为 -1,表示不限制</param> /// <returns>选中的元素所构成的新集合</returns> public MarcNodeList select(string strXPath, int nMaxCount /* = -1*/) { // 把当前集合分割为每段内部确保互相不重叠 List <MarcNodeList> lists = new List <MarcNodeList>(); { MarcNodeList segment = new MarcNodeList(); // 当前累积的段落 foreach (MarcNode node in this) { if (segment.count > 0) { if (isCross(node, segment) == true) { // 推走 lists.Add(segment); segment = new MarcNodeList(); } } segment.add(node); } // 最后剩下的 if (segment.count > 0) { lists.Add(segment); } } MarcNodeList results = new MarcNodeList(); foreach (MarcNodeList segment in lists) { // 对一批互相没有树重叠关系的对象进行筛选 MarcNodeList temp = simpleSelect(segment, strXPath, -1); foreach (MarcNode node in temp) { if (results.indexOf(node) == -1) { results.add(node); } } if (nMaxCount != -1 && results.count >= nMaxCount) { if (results.count > nMaxCount) { return(results.getAt(0, nMaxCount)); } break; } } return(results); }