// 返回一段元素 public MarcNodeList getAt(int start, int length) { MarcNodeList results = new MarcNodeList(); if (length == 0) { return(results); } if (start < 0 || start >= this.count) { throw new Exception("index值 " + start.ToString() + " 超出许可范围"); } if (start + length - 1 < 0 || start + length - 1 >= this.count) { throw new Exception("index + length 值 " + (start + length).ToString() + " 超出许可范围"); } for (int i = 0; i < length; i++) { results.add(this[start + i]); } return(results); }
// 返回某些元素 // parameters: // length 要取得的个数。如果为-1,表示从index一直取到末尾 /// <summary> /// 获得当前集合中一段范围的元素 /// </summary> /// <param name="index">起点下标</param> /// <param name="length">个数</param> /// <returns>指定的元素(所构成的一个新集合)</returns> public MarcNodeList getAt(int index, int length) { MarcNodeList results = new MarcNodeList(); if (length == 0) { return(results); } if (index < 0 || index >= this.count) { throw new ArgumentException("index值 " + index.ToString() + " 超出许可范围", "index"); } if (length == -1) { length = this.count - index; } if (index + length < 0 || index + length - 1 >= this.count) { throw new ArgumentException("index+length值 " + (index + length).ToString() + " 超出许可范围"); } for (int i = index; i < index + length; i++) { results.add(this[i]); } return(results); }
// 对一批互相没有树重叠关系的对象进行筛选 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); }
// 返回最后一个元素 /// <summary> /// 获得当前集合的最后一个元素 /// </summary> /// <returns>当前集合的最后一个元素(所构成的一个新集合)</returns> public MarcNodeList last() { MarcNodeList results = new MarcNodeList(); if (this.count > 0) { results.add(this[this.count - 1]); } return(results); }
// 复制出一个新的集合 // 注意,不但数组(框架)被复制,其中每个元素都重新复制 /// <summary> /// 根据当前集合复制出一个新的集合对象。本方法采取的是否深度复制策略,即新集合中的每个元素都是复制品 /// </summary> /// <returns>新的集合</returns> public MarcNodeList clone() { MarcNodeList result = new MarcNodeList(); foreach (MarcNode node in this) { result.add(node.clone()); } return(result); }
// 返回某个元素 /// <summary> /// 获得指定下标位置的元素 /// </summary> /// <param name="index">下标</param> /// <returns>指定的元素(所构成的一个新集合)</returns> public MarcNodeList getAt(int index) { MarcNodeList results = new MarcNodeList(); if (index < 0 || index >= this.count) { throw new ArgumentException("index值 " + index.ToString() + " 超出许可范围", "index"); } results.add(this[index]); return(results); }
// 从数组中移走全部对象 // 注意,本函数并不修改所移走的对象的Parent成员。也就是说移走的对象并未完全被detach // 返回移出的nodes /// <summary> /// 从当前集合中移走全部元素。注意,本函数并不修改所移走的元素的 Parent 成员。也就是说移走的元素并未完全被摘除 /// </summary> /// <returns>已经被移走的全部元素</returns> public MarcNodeList remove() { MarcNodeList results = new MarcNodeList(); for (int i = 0; i < this.count; i++) { MarcNode node = this[i]; MarcNode temp = node.remove(); if (temp != null) { results.add(node); } } return(results); }
// 在目标集合中每个元素的DOM位置后面(同级)插入源集合内的元素 // 注1: 如果目标集合为空,则本函数不作任何操作。这样可以防止元素被摘除但没有插入到任何位置 // 注2:将 源 插入到 目标 元素的DOM位置后面。如果源头元素在DOM树上,则先摘除它然后插入到新位置,不是复制。 // 注3: 如果目标集合中包含多于一个元素,则分为多轮插入。第二轮以后插入的对象,是源集合中的对象复制出来的新对象 /// <summary> /// 在目标集合中每个元素的 DOM 位置后面(同级)插入源集合内的元素 /// </summary> /// <param name="source_nodes">源集合</param> /// <param name="target_nodes">目标集合</param> public static void insertAfter( MarcNodeList source_nodes, MarcNodeList target_nodes) { if (source_nodes.count == 0) { return; } if (target_nodes.count == 0) { return; } // record.SelectNodes("field[@name='690']")[0].ChildNodes.after(SUBFLD + "x第一个" + SUBFLD + "z第二个"); if (target_nodes is ChildNodeList) { // 数组框架复制,但其中的元素不是复制而是引用 MarcNodeList temp = new MarcNodeList(); temp.add(target_nodes); target_nodes = temp; } // 先(从原有DOM位置)摘除当前集合内的全部元素 source_nodes.detach(); int i = 0; foreach (MarcNode target_node in target_nodes) { MarcNode target = target_node; foreach (MarcNode source_node in source_nodes) { MarcNode source = source_node; if (i > 0) // 第一轮以后,源对象每个都要复制后插入目标位置 { source = source.clone(); target.after(source); } else { target.after(source); } target = source; // 插入后参考位置要顺延 } i++; } }
/// <summary> /// 在目标集合中每个元素的 DOM 位置前面(同级)插入源集合内的元素 /// </summary> /// <param name="source_nodes">源集合</param> /// <param name="target_nodes">目标集合</param> public static void insertBefore( MarcNodeList source_nodes, MarcNodeList target_nodes) { if (source_nodes.count == 0) { return; } if (target_nodes.count == 0) { return; } if (target_nodes is ChildNodeList) { // 数组框架复制,但其中的元素不是复制而是引用 MarcNodeList temp = new MarcNodeList(); temp.add(target_nodes); target_nodes = temp; } // 先(从原有DOM位置)摘除当前集合内的全部元素 source_nodes.detach(); int i = 0; foreach (MarcNode target_node in target_nodes) { MarcNode target = target_node; foreach (MarcNode source_node in source_nodes) { MarcNode source = source_node; if (i > 0) // 第一轮以后,源对象每个都要复制后插入目标位置 { source = source.clone(); target.before(source); } else { target.before(source); } target = source; // 插入后参考位置要顺延 } i++; } }
// 在目标集合中每个元素的DOM位置 下级开头 插入源集合内的元素 /// <summary> /// 在目标集合中每个元素的 DOM 位置下级开头插入源集合内的元素 /// </summary> /// <param name="source_nodes">源集合</param> /// <param name="target_nodes">目标集合</param> public static void prepend( MarcNodeList source_nodes, MarcNodeList target_nodes) { if (source_nodes.count == 0) { return; } if (target_nodes.count == 0) { return; } // 防范目标集合被动态修改后发生foreach报错 if (target_nodes is ChildNodeList) { // 数组框架复制,但其中的元素不是复制而是引用 MarcNodeList temp = new MarcNodeList(); temp.add(target_nodes); target_nodes = temp; } // 先(从原有DOM位置)摘除当前集合内的全部元素 source_nodes.detach(); int i = 0; foreach (MarcNode target_node in target_nodes) { foreach (MarcNode source_node in source_nodes) { MarcNode source = source_node; if (i > 0) // 第一轮以后,源对象每个都要复制后插入目标位置 { source = source.clone(); target_node.prepend(source); } else { target_node.prepend(source); } } i++; } }
// 针对DOM树进行 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*/) { MarcNodeList results = new MarcNodeList(); MarcNavigator nav = new MarcNavigator(this); // 出发点在当前对象 XPathNodeIterator ni = nav.Select(strXPath); while (ni.MoveNext() && (nMaxCount == -1 || results.count < nMaxCount)) { NaviItem item = ((MarcNavigator)ni.Current).Item; if (item.Type != NaviItemType.Element) { // if (bSkipNoneElement == false) throw new Exception("xpath '" + strXPath + "' 命中了非元素类型的节点,这是不允许的"); continue; } results.add(item.MarcNode); } return(results); }
/// <summary> /// 根据机内格式 MARC 字符串,创建若干 MarcInnerField 对象 /// </summary> /// <param name="strText">MARC 机内格式字符串。代表内嵌字段的那个局部。例如 "$1200 $axxxx$fxxxx$1225 $axxxx"</param> /// <param name="strLeadingString">返回引导字符串。也就是第一个子字段符号前的部分</param> /// <returns>新创建的 MarcInnerField 对象数组</returns> public static MarcNodeList createInnerFields( string strText, out string strLeadingString) { strLeadingString = ""; MarcNodeList results = new MarcNodeList(); strText = strText.Replace(SUBFLD + "1", FLDEND); List <string> segments = new List <string>(); StringBuilder prefix = new StringBuilder(); // 第一个 30 出现以前的一段文字 StringBuilder segment = new StringBuilder(); // 正在追加的内容段落 for (int i = 0; i < strText.Length; i++) { char ch = strText[i]; if (ch == FLDEND[0]) { // 如果先前有累积的,推走 if (segment.Length > 0) { segments.Add(segment.ToString()); segment.Clear(); } //segment.Append(ch); segment.Append(SUBFLD + "1"); } else { if (segment.Length > 0 || segments.Count > 0) { segment.Append(ch); } else { prefix.Append(ch);// 第一个子字段符号以前的内容放在这里 } } } if (segment.Length > 0) { segments.Add(segment.ToString()); segment.Clear(); } if (prefix.Length > 0) { strLeadingString = prefix.ToString(); } foreach (string s in segments) { string strSegment = s; MarcInnerField field = null; field = new MarcInnerField(); // 如果长度不足 5 字符,补齐 // 5 字符是 $1200 的意思 if (strSegment.Length < 5) { strSegment = strSegment.PadRight(5, '?'); } field.Text = strSegment; results.add(field); // Debug.Assert(field.Parent == parent, ""); } return(results); }
// 根据机内格式的片断字符串,构造若干MarcSubfield对象 // parameters: // parent 要赋给新创建的MarcSubfield对象的Parent值 // strLeadingString [out] 第一个 31 字符以前的文本部分 /// <summary> /// 根据机内格式 MARC 字符串,创建若干 MarcSubfield 对象 /// </summary> /// <param name="strText">MARC 机内格式字符串</param> /// <param name="strLeadingString">返回前导部分字符串。也就是 strText 中第一个子字段符号以前的部分</param> /// <returns>新创建的 MarcSubfield 对象集合</returns> public static MarcNodeList createSubfields( string strText, out string strLeadingString) { strLeadingString = ""; MarcNodeList results = new MarcNodeList(); List <string> segments = new List <string>(); StringBuilder prefix = new StringBuilder(); // 第一个 31 出现以前的一段文字 StringBuilder segment = new StringBuilder(); // 正在追加的内容段落 for (int i = 0; i < strText.Length; i++) { char ch = strText[i]; if (ch == 31) { // 如果先前有累积的,推走 if (segment.Length > 0) { segments.Add(segment.ToString()); segment.Clear(); } segment.Append(ch); } else { if (segment.Length > 0 || segments.Count > 0) { segment.Append(ch); } else { prefix.Append(ch);// 第一个子字段符号以前的内容放在这里 } } } if (segment.Length > 0) { segments.Add(segment.ToString()); segment.Clear(); } if (prefix.Length > 0) { strLeadingString = prefix.ToString(); } foreach (string s in segments) { MarcSubfield subfield = new MarcSubfield(); if (s.Length < 2) { subfield.Text = MarcQuery.SUBFLD + "?"; // TODO: 或者可以忽略? } else { subfield.Text = s; } results.add(subfield); // Debug.Assert(subfield.Parent == parent, ""); } return(results); }
/// <summary> /// 根据机内格式 MARC 字符串,创建若干 MarcField (或 MarcOuterField) 对象 /// </summary> /// <param name="strText">MARC 机内格式字符串</param> /// <param name="strOuterFieldDef">嵌套字段的定义。缺省为 null,表示不使用嵌套字段。这是一个列举字段名的逗号间隔的列表('*'为通配符),或者 '@' 字符后面携带一个正则表达式</param> /// <returns>新创建的 MarcField 对象集合</returns> public static MarcNodeList createFields( string strText, string strOuterFieldDef = null) { MarcNodeList results = new MarcNodeList(); List <string> segments = new List <string>(); StringBuilder field_text = new StringBuilder(4096); for (int i = 0; i < strText.Length; i++) { char ch = strText[i]; if (ch == 30 || ch == 29) { // 上一个字段结束 segments.Add(field_text.ToString()); field_text.Clear(); } else { field_text.Append(ch); } } // 剩余的内容 if (field_text.Length > 0) { segments.Add(field_text.ToString()); field_text.Clear(); } foreach (string segment in segments) { string strSegment = segment; // 如果长度不足 3 字符,补齐? if (strSegment.Length < 3) { strSegment = strSegment.PadRight(3, '?'); } // 创建头标区以后的普通字段 MarcNode field = null; if (string.IsNullOrEmpty(strOuterFieldDef) == false) { string strFieldName = strSegment.Substring(0, 3); // return: // -1 error // 0 not match // 1 match int nRet = MatchName(strFieldName, strOuterFieldDef); if (nRet == 1) { field = new MarcOuterField(); } else { field = new MarcField(); } } else { field = new MarcField(); } field.Text = strSegment; results.add(field); // Debug.Assert(field.Parent == parent, ""); } return(results); }