// 把对字段的修改合并到书目记录中 // return: // -1 出错 // 0 书目记录没有发生修改 // 1 书目记录发生了修改 int MergeChange(LineInfo line_info, BiblioInfo biblio_info, out string strError) { strError = ""; int nRet = 0; string strXml = biblio_info.NewXml; if (string.IsNullOrEmpty(strXml) == true) strXml = biblio_info.OldXml; string strMARC = ""; string strMarcSyntax = ""; // 将XML格式转换为MARC格式 // 自动从数据记录中获得MARC语法 nRet = MarcUtil.Xml2Marc(strXml, true, null, out strMarcSyntax, out strMARC, out strError); if (nRet == -1) { strError = "XML 转换到 MARC 记录时出错: " + strError; return -1; } if (string.IsNullOrEmpty(line_info.State) == true && string.IsNullOrEmpty(line_info.NewField) == true) { strError = "一般修改情况下的 line_info.NewField 不应该为空"; return -1; } MarcRecord record = new MarcRecord(strMARC); MarcNodeList fields = record.select("field[@name='856']"); if (fields.count > line_info.Index) { if (line_info.State == "delete") fields[line_info.Index].detach(); else fields[line_info.Index].Text = line_info.NewField; } else { if (line_info.State == "delete") return 0; Debug.Assert(false, "除非插入情况,否则走不到这里"); // 添加足够的 856 字段 MarcField tail = null; for (int i = fields.count; i < line_info.Index + 1; i++) { tail = new MarcField("856", " "); record.ChildNodes.insertSequence(tail, InsertSequenceStyle.PreferTail); } Debug.Assert(tail != null, ""); tail.Text = line_info.NewField; } strMARC = record.Text; nRet = MarcUtil.Marc2XmlEx(strMARC, strMarcSyntax, ref strXml, out strError); if (nRet == -1) { strError = "MARC 转换到 XML 记录时出错: " + strError; return -1; } biblio_info.NewXml = strXml; return 1; }
// 新加入一行 public ListViewItem AddLine( string strBiblioRecPath, BiblioInfo biblio_info, MarcField field, int index) { // 将 BiblioInfo 储存起来 BiblioInfo existing = (BiblioInfo)this.m_biblioTable[strBiblioRecPath]; if (existing == null) this.m_biblioTable[strBiblioRecPath] = biblio_info; ListViewItem item = new ListViewItem(); SetItemColumns(item, strBiblioRecPath, field, index); this.listView_records.Items.Add(item); LineInfo line_info = new LineInfo(); line_info.OldField = field.Text; line_info.Index = index; item.Tag = line_info; return item; }
void SetContent(string strValue) { // 拆分为字段 this.ChildNodes.Clear(); this.m_strContent = ""; if (String.IsNullOrEmpty(strValue) == true) return; // 整理尾部字符 char tail = strValue[strValue.Length - 1]; if (tail == 29) strValue = strValue.Substring(0, strValue.Length - 1); if (String.IsNullOrEmpty(strValue) == true) return; tail = strValue[strValue.Length - 1]; if (tail != 30) strValue += (char)30; StringBuilder field_text = new StringBuilder(4096); MarcField field = null; for (int i = 0; i < strValue.Length; i++) { char ch = strValue[i]; if (ch == 30 || ch == 29) { // 上一个字段结束。创建一个字段的时机 string strText = field_text.ToString(); if (this.ChildNodes.Count == 0) { // 创建第一个字段,也就是头标区 string strHeader = ""; // 头标区 string strRest = ""; // 余下的部分 // 长度不足 24 字符 if (string.IsNullOrEmpty(strText) == true || strText.Length < 24) { // 需要补齐 24 字符 strHeader = strText.PadRight(24, '?'); } else { // 长度大于或者等于 24 字符 strHeader = strText.Substring(0, 24); strRest = strText.Substring(24); } // header Debug.Assert(strHeader.Length == 24, ""); field = new MarcField(this); field.IsHeader = true; field.Text = strHeader; this.ChildNodes.Add(field); Debug.Assert(field.Parent == this, ""); // 余下的部分再创建一个字段 if (string.IsNullOrEmpty(strRest) == false) { // 如果长度不足 3 字符,补齐? if (strRest.Length < 3) strRest = strRest.PadRight(3, '?'); field = new MarcField(this); field.Text = strRest; this.ChildNodes.Add(field); Debug.Assert(field.Parent == this, ""); } field_text.Clear(); continue; } // 创建头标区以后的普通字段 field = new MarcField(this); // 如果长度不足 3 字符,补齐? if (strText.Length < 3) strText = strText.PadRight(3, '?'); field = new MarcField(this); field.Text = strText; this.ChildNodes.Add(field); Debug.Assert(field.Parent == this, ""); field_text.Clear(); } else { field_text.Append(ch); } } }
// 给 MARC21 记录中 245 字段内的子字段添加正确的标点符号 /// <summary> /// 给 MARC21 记录中 245 字段内的子字段添加正确的标点符号 /// </summary> /// <param name="field">MARC 字段</param> /// <param name="strStyle">风格</param> /// <returns>记录是否发生了修改</returns> public static bool PunctuationMarc21Field245(MarcField field, string strStyle) { List <SubfieldInfo> infos = new List <SubfieldInfo>(); foreach (MarcSubfield subfield in field.ChildNodes) { SubfieldInfo info = new SubfieldInfo(); info.Subfield = subfield; infos.Add(info); } // 添加标点符号 // $a题名 (不可重复) // $b题名其余部分 空: (少数情况;) // $c责任者说明 空/ // $f首尾日期 , // $g主体日期(集中出版日期) 自己() // $h载体 自己[] // $k资料形式 空: // $n著作分卷/分节号 . // $p著作分卷/分节题名 (在$a$b或者另一个$p后,就是 .。跟在 $n 后面就是 ,) // $s版本 . // 最后一个子字段尾部要加入一个 . { MarcSubfield prev_field = null; foreach (SubfieldInfo info in infos) { switch (info.Subfield.Name) { case "a": if (prev_field != null) { info.LeadingPunctuation = " "; } break; case "b": // 注:如果前一个子字段末尾是 ';',则用 ';' info.LeadingPunctuation = ":"; break; case "c": info.LeadingPunctuation = "/"; break; case "f": info.LeadingPunctuation = ","; break; case "g": info.Punctuation = "()"; break; case "h": info.Punctuation = "[]"; break; case "k": info.LeadingPunctuation = ":"; break; case "n": info.LeadingPunctuation = "."; break; case "p": if (prev_field != null && prev_field.Name == "n") { info.LeadingPunctuation = ","; } else { info.LeadingPunctuation = "."; } break; case "s": info.LeadingPunctuation = "."; break; } prev_field = info.Subfield; } } string strOld = field.Content; { SubfieldInfo prev_info = null; foreach (SubfieldInfo info in infos) { if (prev_info != null) { ResetPunctuation(prev_info.Subfield, prev_info.Punctuation, info.LeadingPunctuation); } prev_info = info; } // 最后一个子字段加上尾部符号 . if (string.IsNullOrEmpty(prev_info.Subfield.Content) == true || prev_info.Subfield.Content[prev_info.Subfield.Content.Length - 1] != '.') { prev_info.Subfield.Content += "."; } } if (strOld != field.Content) { return(true); } return(false); }
/// <summary> /// 根据提供的主题词字符串 修改 MARC 记录中的 610 或 653 字段 /// </summary> /// <param name="strMARC">要操作的 MARC 记录字符串。机内格式</param> /// <param name="strMarcSyntax">MARC 格式</param> /// <param name="subjects">主题词字符串集合</param> /// <param name="strError">返回出错信息</param> /// <returns>-1: 出错; 0: 成功</returns> public static int ChangeSubject(ref string strMARC, string strMarcSyntax, List<string> subjects, out string strError) { strError = ""; MarcRecord record = new MarcRecord(strMARC); MarcNodeList nodes = null; if (strMarcSyntax == "unimarc") nodes = record.select("field[@name='610' and @indicator1=' ']"); else if (strMarcSyntax == "usmarc") nodes = record.select("field[@name='653' and @indicator1=' ']"); else { strError = "未知的 MARC 格式类型 '" + strMarcSyntax + "'"; return -1; } if (subjects == null || subjects.Count == 0) { // 删除那些可以删除的 610 字段 foreach (MarcNode node in nodes) { MarcNodeList subfields = node.select("subfield[@name='a']"); if (subfields.count == node.ChildNodes.count) { // 如果除了 $a 以外没有其他任何子字段,则字段可以删除 node.detach(); } } } else { MarcNode field610 = null; // 只留下一个 610 字段 if (nodes.count > 1) { int nCount = nodes.count; foreach (MarcNode node in nodes) { MarcNodeList subfields = node.select("subfield[@name='a']"); if (subfields.count == node.ChildNodes.count) { // 如果除了 $a 以外没有其他任何子字段,则字段可以删除 node.detach(); nCount--; } if (nCount <= 1) break; } // 重新选定 if (strMarcSyntax == "unimarc") nodes = record.select("field[@name='610' and @indicator1=' ']"); else if (strMarcSyntax == "usmarc") nodes = record.select("field[@name='653' and @indicator1=' ']"); field610 = nodes[0]; } else if (nodes.count == 0) { // 创建一个新的 610 字段 if (strMarcSyntax == "unimarc") field610 = new MarcField("610", " "); else if (strMarcSyntax == "usmarc") field610 = new MarcField("653", " "); record.ChildNodes.insertSequence(field610); } else { Debug.Assert(nodes.count == 1, ""); field610 = nodes[0]; } // 删除全部 $a 子字段 field610.select("subfield[@name='a']").detach(); // 添加若干个 $a 子字段 Debug.Assert(subjects.Count > 0, ""); MarcNodeList source = new MarcNodeList(); for (int i = 0; i < subjects.Count; i++) { source.add(new MarcSubfield("a", subjects[i])); } // 寻找适当位置插入 field610.ChildNodes.insertSequence(source[0]); if (source.count > 1) { // 在刚插入的对象后面插入其余的对象 MarcNodeList list = new MarcNodeList(source[0]); source.removeAt(0); // 排除刚插入的一个 list.after(source); } } strMARC = record.Text; return 0; }
public string GetMarc() { MarcRecord record = new MarcRecord(this._header); MarcField current_field_node = null; foreach (EasyLine line in this.Items) { if (line is FieldLine) { FieldLine field = line as FieldLine; MarcField field_node = null; if (field.IsControlField == true) field_node = new MarcField(field.Name, "", field.Content); else field_node = new MarcField(field.Name, field.Indicator, ""); record.ChildNodes.add(field_node); current_field_node = field_node; } else if (line is SubfieldLine) { SubfieldLine subfield = line as SubfieldLine; MarcSubfield subfield_node = new MarcSubfield(subfield.Name, subfield.Content); current_field_node.ChildNodes.add(subfield_node); } } return record.Text; }
// 设置 ListViewItem 的各列 void SetItemColumns(ListViewItem item, string strBiblioRecPath, MarcField field, int index) { // 设置各列内容 string u = field.select("subfield[@name='u']").FirstContent; string x = field.select("subfield[@name='x']").FirstContent; // 读取参数的时候,不在意内部顺序问题 Hashtable table = StringUtil.ParseParameters(x, ';', ':'); string strType = (string)table["type"]; string strRights = (string)table["rights"]; string strSize = (string)table["size"]; string strSource = (string)table["source"]; if (string.IsNullOrEmpty(strBiblioRecPath) == false) ListViewUtil.ChangeItemText(item, COLUMN_RECPATH, strBiblioRecPath); ListViewUtil.ChangeItemText(item, COLUMN_FIELDINDEX, index.ToString()); ListViewUtil.ChangeItemText(item, COLUMN_INDICATOR1, field.Indicator1.ToString()); ListViewUtil.ChangeItemText(item, COLUMN_INDICATOR2, field.Indicator2.ToString()); ListViewUtil.ChangeItemText(item, COLUMN_URL, u); ListViewUtil.ChangeItemText(item, COLUMN_F, field.select("subfield[@name='f']").FirstContent); ListViewUtil.ChangeItemText(item, COLUMN_Q, field.select("subfield[@name='q']").FirstContent); ListViewUtil.ChangeItemText(item, COLUMN_S, field.select("subfield[@name='s']").FirstContent); ListViewUtil.ChangeItemText(item, COLUMN_Y, field.select("subfield[@name='y']").FirstContent); ListViewUtil.ChangeItemText(item, COLUMN_Z, field.select("subfield[@name='z']").FirstContent); ListViewUtil.ChangeItemText(item, COLUMN_X, x); ListViewUtil.ChangeItemText(item, COLUMN_RIGHTS, strRights); ListViewUtil.ChangeItemText(item, COLUMN_SIZE, strSize); ListViewUtil.ChangeItemText(item, COLUMN_SOURCE, strSource); ListViewUtil.ChangeItemText(item, COLUMN_TYPE, strType); ListViewUtil.ChangeItemText(item, COLUMN_2, field.select("subfield[@name='2']").FirstContent); ListViewUtil.ChangeItemText(item, COLUMN_3, field.select("subfield[@name='3']").FirstContent); ListViewUtil.ChangeItemText(item, COLUMN_8, field.select("subfield[@name='8']").FirstContent); }
/// <summary> /// 创建平行字段 /// </summary> /// <param name="field">要创建平行字段的,包含汉字字符串的源字段</param> /// <param name="bTo880">将 field 字段名转为 880</param> /// <param name="getPinyin">获得拼音的函数地址</param> /// <param name="strError">返回出错信息</param> /// <returns>-1: 出错; 0: 成功; 1: field 不是中文的字段($6表示),无法创建平行字段</returns> public static int CreateParallelField(MarcField field, bool bTo880, Delegate_getPinyin getPinyin, out string strError) { strError = ""; if (field.ChildNodes.count == 0) return 1; MarcRecord record = (MarcRecord)field.Parent; MarcField main_field = null; string strFieldName = ""; string strNumber = ""; string strScriptId = ""; string strOrientation = ""; // 观察平行字段是否已经存在? string content_6 = field.select("subfield[@name='6']").FirstContent; if (string.IsNullOrEmpty(content_6) == false) { // 拆解 $6 内容 _parseSubfield6(content_6, out strFieldName, out strNumber, out strScriptId, out strOrientation); if (string.IsNullOrEmpty(strScriptId) == true) { strError = "field 的 $6 表明不是中文的字段,无法创建平行字段"; return 1; } // 找到关联的字段 main_field = _findField(record, strFieldName, field.Name, strNumber); } bool bNewField = false; if (main_field == null) { string strMainFieldName = field.Name; if (field.Name == "880") { // 只能靠 $6 中 linking tag if (string.IsNullOrEmpty(strFieldName) == true) { strError = "当前字段为 880 字段,但没有 $6 子字段,无法获得对应的字段名,因此函数调用失败"; return -1; } strMainFieldName = strFieldName; } main_field = new MarcField(strMainFieldName, field.Indicator, ""); if (field.Name != "880") field.before(main_field); else record.ChildNodes.insertSequence(main_field, InsertSequenceStyle.PreferTail); bNewField = true; } else { // 内容全部删除。只是占用原有位置 main_field.Content = ""; main_field.Indicator = field.Indicator; } if (string.IsNullOrEmpty(strNumber) == true) strNumber = _getNewNumber(record); { // $6 MarcSubfield subfield_6 = new MarcSubfield("6", _buildSubfield6(bTo880 == true? "880" : field.Name, strNumber, "", strOrientation) ); main_field.ChildNodes.add(subfield_6); } int nHanziCount = 0; List<MarcSubfield> remove_subfields = new List<MarcSubfield>(); // 其余子字段逐个加入 foreach (MarcSubfield subfield in field.ChildNodes) { if (subfield.Name == "6") continue; // 2014/10/20 if (subfield.Name == "9" || char.IsUpper(subfield.Name[0]) == true) { remove_subfields.Add(subfield); continue; } string strPinyin = getPinyin(subfield.Content, out strError); if (strPinyin == null) { strError = "创建拼音的过程出错: " + strError; return -1; } if (strPinyin != subfield.Content) nHanziCount++; main_field.ChildNodes.add(new MarcSubfield(subfield.Name, strPinyin)); } // 2014/10/20 if (remove_subfields.Count > 0) { foreach (MarcSubfield subfield in remove_subfields) { subfield.detach(); } } if (nHanziCount == 0 && bNewField == true) { main_field.detach(); return 1; } // 当前字段加入 $6 { if (string.IsNullOrEmpty(strScriptId) == true) strScriptId = "$1"; MarcSubfield subfield_6 = null; MarcNodeList temp = field.select("subfield[@name='6']"); if (temp.count > 0) { subfield_6 = temp[0] as MarcSubfield; subfield_6.Content = _buildSubfield6(main_field.Name, strNumber, strScriptId, strOrientation); } else { subfield_6 = new MarcSubfield("6", _buildSubfield6(main_field.Name, strNumber, strScriptId, strOrientation) ); field.ChildNodes.insert(0, subfield_6); } } if (bTo880) { field.Name = "880"; } return 0; }
// 清除一个事项的修改信息 void ClearOneChange(ListViewItem item) { LineInfo info = (LineInfo)item.Tag; if (info == null) return; if (string.IsNullOrEmpty(info.State) == false) { info.State = ""; Debug.Assert(String.IsNullOrEmpty(info.NewField) == true, "在 State 有值的情况下 NewField 应该为空"); item.BackColor = SystemColors.Window; item.ForeColor = SystemColors.WindowText; this.m_nChangedCount--; Debug.Assert(this.m_nChangedCount >= 0, ""); return; } if (String.IsNullOrEmpty(info.NewField) == false) { info.NewField = ""; // 刷新除了记录路径和书目摘要的其余列的显示 MarcField field = new MarcField(info.OldField); SetItemColumns(item, null, field, info.Index); item.BackColor = SystemColors.Window; item.ForeColor = SystemColors.WindowText; this.m_nChangedCount--; Debug.Assert(this.m_nChangedCount >= 0, ""); } // TODO: 要允许 insert 或 delete 动作可以被清除,需要设计成在保存前才往书目记录里面兑现修改。 }
// 快速修改记录 // return: // -1 出错 // 0 放弃 // 1 成功 internal int QuickChangeItemRecords(out string strError) { strError = ""; int nRet = 0; if (this.listView_records.SelectedItems.Count == 0) { strError = "尚未选择要快速修改的 856 字段事项"; return -1; } List<OneAction> actions = null; XmlDocument cfg_dom = null; { ChangeItemActionDialog dlg = new ChangeItemActionDialog(); MainForm.SetControlFont(dlg, this.Font, false); dlg.ElementCaption = "子字段"; dlg.DbType = "856"; dlg.Text = "快速修改 856 字段 -- 请指定动作参数"; dlg.MainForm = this.MainForm; //dlg.GetValueTable -= new GetValueTableEventHandler(dlg_GetValueTable); //dlg.GetValueTable += new GetValueTableEventHandler(dlg_GetValueTable); dlg.UiState = this.MainForm.AppInfo.GetString( "marc856search_form", "ChangeItemActionDialog_uiState", ""); this.MainForm.AppInfo.LinkFormState(dlg, "marc856searchform_quickchangedialog_state"); dlg.ShowDialog(this); this.MainForm.AppInfo.UnlinkFormState(dlg); this.MainForm.AppInfo.SetString( "marc856search_form", "ChangeItemActionDialog_uiState", dlg.UiState); if (dlg.DialogResult == System.Windows.Forms.DialogResult.Cancel) return 0; // 放弃 actions = dlg.Actions; cfg_dom = dlg.CfgDom; } DateTime now = DateTime.Now; // TODO: 检查一下,看看是否一项修改动作都没有 this.MainForm.OperHistory.AppendHtml("<div class='debug begin'>" + HttpUtility.HtmlEncode(DateTime.Now.ToLongTimeString()) + " 开始执行快速修改 856 字段</div>"); stop.Style = StopStyle.EnableHalfStop; stop.OnStop += new StopEventHandler(this.DoStop); stop.Initial("快速修改 856 字段 ..."); stop.BeginLoop(); EnableControls(false); this.listView_records.Enabled = false; int nProcessCount = 0; int nChangedCount = 0; try { stop.SetProgressRange(0, this.listView_records.SelectedItems.Count); List<ListViewItem> items = new List<ListViewItem>(); foreach (ListViewItem item in this.listView_records.SelectedItems) { if (string.IsNullOrEmpty(item.Text) == true) continue; items.Add(item); } bool bOldSource = true; // 是否要从 OldXml 开始做起 int nChangeCount = this.GetItemsChangeCount(items); if (nChangeCount > 0) { bool bHideMessageBox = true; DialogResult result = MessageDialog.Show(this, "当前选定的 " + items.Count.ToString() + " 个事项中有 " + nChangeCount + " 项修改尚未保存。\r\n\r\n请问如何进行修改? \r\n\r\n(重新修改) 重新进行修改,忽略以前内存中的修改; \r\n(继续修改) 以上次的修改为基础继续修改; \r\n(放弃) 放弃整个操作", MessageBoxButtons.YesNoCancel, MessageBoxDefaultButton.Button1, null, ref bHideMessageBox, new string[] { "重新修改", "继续修改", "放弃" }); if (result == DialogResult.Cancel) { strError = "放弃"; return 0; } if (result == DialogResult.No) { bOldSource = false; } } int i = 0; foreach (ListViewItem item in items) { Application.DoEvents(); // 出让界面控制权 if (stop != null && stop.State != 0) { strError = "用户中断"; return -1; } stop.SetProgressValue(i); LineInfo info = (LineInfo)item.Tag; if (info == null) { strError = "item.Tag == null"; return -1; } Debug.Assert(info != null, ""); string strField = ""; if (bOldSource == true) { strField = info.OldField; // 放弃上一次的修改 if (string.IsNullOrEmpty(info.State) == false) { info.State = ""; this.m_nChangedCount--; if (string.IsNullOrEmpty(info.NewField) == false) strField = info.NewField; else strField = info.OldField; } else { if (string.IsNullOrEmpty(info.NewField) == false) { info.NewField = ""; this.m_nChangedCount--; } } } else { if (string.IsNullOrEmpty(info.State) == false) { // 在删除的基础上继续修改 --- 等于承认删除状态,并无法修改,只好跳过 i++; continue; } if (string.IsNullOrEmpty(info.NewField) == false) strField = info.NewField; else strField = info.OldField; } string strBiblioRecPath = ListViewUtil.GetItemText(item, COLUMN_RECPATH); this.MainForm.OperHistory.AppendHtml("<div class='debug recpath'>" + HttpUtility.HtmlEncode(strBiblioRecPath + ":" + info.Index) + "</div>"); string strDebugInfo = ""; // 修改一个订购记录 XmlDocument // return: // -1 出错 // 0 没有实质性修改 // 1 发生了修改 nRet = Modify856Field( cfg_dom, actions, ref strField, now, out strDebugInfo, out strError); if (nRet == -1) return -1; this.MainForm.OperHistory.AppendHtml("<div class='debug normal'>" + HttpUtility.HtmlEncode(strDebugInfo).Replace("\r\n", "<br/>") + "</div>"); nProcessCount++; if (nRet == 1) { Debug.Assert(info != null, ""); if (info != null) { if (string.IsNullOrEmpty(info.NewField) == true) this.m_nChangedCount++; info.NewField = strField; } // 刷新除了记录路径和书目摘要的其余列的显示 MarcField field = new MarcField(info.NewField); SetItemColumns(item, null, field, info.Index); item.BackColor = SystemColors.Info; item.ForeColor = SystemColors.InfoText; } i++; nChangedCount++; } } finally { EnableControls(true); this.listView_records.Enabled = true; stop.EndLoop(); stop.OnStop -= new StopEventHandler(this.DoStop); stop.Initial(""); stop.HideProgress(); stop.Style = StopStyle.None; this.MainForm.OperHistory.AppendHtml("<div class='debug end'>" + HttpUtility.HtmlEncode(DateTime.Now.ToLongTimeString()) + " 结束快速修改 856 字段</div>"); } DoViewComment(false); strError = "修改 856 字段 " + nChangedCount.ToString() + " 个 (共处理 " + nProcessCount.ToString() + " 个)\r\n\r\n(注意修改并未自动保存。请在观察确认后,使用保存命令将修改保存回书目库)"; return 1; }
/// <summary> /// 创建平行字段 /// </summary> /// <param name="field">要创建平行字段的,包含汉字字符串的源字段</param> /// <param name="bTo880">将 field 字段名转为 880</param> /// <param name="getPinyin">获得拼音的函数地址</param> /// <param name="strError">返回出错信息</param> /// <returns>-1: 出错; 0: 成功; 1: field 不是中文的字段($6表示),无法创建平行字段</returns> public static int CreateParallelField(MarcField field, bool bTo880, Delegate_getPinyin getPinyin, out string strError) { strError = ""; if (field.ChildNodes.count == 0) { return(1); } MarcRecord record = (MarcRecord)field.Parent; MarcField main_field = null; string strFieldName = ""; string strNumber = ""; string strScriptId = ""; string strOrientation = ""; // 观察平行字段是否已经存在? string content_6 = field.select("subfield[@name='6']").FirstContent; if (string.IsNullOrEmpty(content_6) == false) { // 拆解 $6 内容 _parseSubfield6(content_6, out strFieldName, out strNumber, out strScriptId, out strOrientation); if (string.IsNullOrEmpty(strScriptId) == true) { strError = "field 的 $6 表明不是中文的字段,无法创建平行字段"; return(1); } // 找到关联的字段 main_field = _findField(record, strFieldName, field.Name, strNumber); } bool bNewField = false; if (main_field == null) { string strMainFieldName = field.Name; if (field.Name == "880") { // 只能靠 $6 中 linking tag if (string.IsNullOrEmpty(strFieldName) == true) { strError = "当前字段为 880 字段,但没有 $6 子字段,无法获得对应的字段名,因此函数调用失败"; return(-1); } strMainFieldName = strFieldName; } main_field = new MarcField(strMainFieldName, field.Indicator, ""); if (field.Name != "880") { field.before(main_field); } else { record.ChildNodes.insertSequence(main_field, InsertSequenceStyle.PreferTail); } bNewField = true; } else { // 内容全部删除。只是占用原有位置 main_field.Content = ""; main_field.Indicator = field.Indicator; } if (string.IsNullOrEmpty(strNumber) == true) { strNumber = _getNewNumber(record); } { // $6 MarcSubfield subfield_6 = new MarcSubfield("6", _buildSubfield6(bTo880 == true? "880" : field.Name, strNumber, "", strOrientation) ); main_field.ChildNodes.add(subfield_6); } int nHanziCount = 0; List <MarcSubfield> remove_subfields = new List <MarcSubfield>(); // 其余子字段逐个加入 foreach (MarcSubfield subfield in field.ChildNodes) { if (subfield.Name == "6") { continue; } // 2014/10/20 if (subfield.Name == "9" || char.IsUpper(subfield.Name[0]) == true) { remove_subfields.Add(subfield); continue; } string strPinyin = getPinyin(subfield.Content, out strError); if (strPinyin == null) { strError = "创建拼音的过程出错: " + strError; return(-1); } if (strPinyin != subfield.Content) { nHanziCount++; } main_field.ChildNodes.add(new MarcSubfield(subfield.Name, strPinyin)); } // 2014/10/20 if (remove_subfields.Count > 0) { foreach (MarcSubfield subfield in remove_subfields) { subfield.detach(); } } if (nHanziCount == 0 && bNewField == true) { main_field.detach(); return(1); } // 当前字段加入 $6 { if (string.IsNullOrEmpty(strScriptId) == true) { strScriptId = "$1"; } MarcSubfield subfield_6 = null; MarcNodeList temp = field.select("subfield[@name='6']"); if (temp.count > 0) { subfield_6 = temp[0] as MarcSubfield; subfield_6.Content = _buildSubfield6(main_field.Name, strNumber, strScriptId, strOrientation); } else { subfield_6 = new MarcSubfield("6", _buildSubfield6(main_field.Name, strNumber, strScriptId, strOrientation) ); field.ChildNodes.insert(0, subfield_6); } } if (bTo880) { field.Name = "880"; } return(0); }
/// <summary> /// 将 USMARC 记录从 平行模式转换为 880 模式 /// </summary> /// <param name="record">要处理的记录</param> public static void To880(MarcRecord record) { List <MarcField> field_880s = new List <MarcField>(); foreach (MarcField field in record.ChildNodes) { if (field.Name == "880") { continue; } string content_6 = field.select("subfield[@name='6']").FirstContent; if (string.IsNullOrEmpty(content_6) == true) { continue; } // 拆解 $6 内容 string strFieldName = ""; string strNumber = ""; string strScriptId = ""; string strOrientation = ""; _parseSubfield6(content_6, out strFieldName, out strNumber, out strScriptId, out strOrientation); if (string.IsNullOrEmpty(strScriptId) == true) { continue; } // 至此 field 就是并列字段 // 找到关联的主字段 MarcField main_field = _findField(record, strFieldName, field.Name, strNumber); if (main_field != null) { // 修改并列字段的字段名为 880 field.Name = "880"; field.select("subfield[@name='6']").Content = _buildSubfield6(main_field.Name, strNumber, strScriptId, strOrientation); // 修改主字段的 $6 main_field.select("subfield[@name='6']").Content = _buildSubfield6("880", strNumber, "", ""); // 将 880 字段移动到顺次位置 } else { // 找不到关联的字段,把并列字段的字段名修改为 880 即可 field.Name = "880"; } field_880s.Add(field); } foreach (MarcField field in field_880s) { field.detach(); } foreach (MarcField field in field_880s) { record.ChildNodes.insertSequence(field, InsertSequenceStyle.PreferTail); } }
/// <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); }
/// <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; }
// 修改一个 856 字段 // return: // -1 出错 // 0 没有实质性修改 // 1 发生了修改 int Modify856Field( XmlDocument cfg_dom, List<OneAction> actions, ref string strField, DateTime now, out string strDebugInfo, out string strError) { strError = ""; strDebugInfo = ""; bool bChanged = false; int nRet = 0; MarcField field = new MarcField(strField); StringBuilder debug = new StringBuilder(4096); foreach (OneAction action in actions) { // 找到元素名 if (string.IsNullOrEmpty(action.FieldName) == true) continue; string strElementName = ""; if (action.FieldName[0] == '{' || action.FieldName[0] == '<') { strElementName = OneActionDialog.Unquote(action.FieldName); } else { nRet = OneActionDialog.GetElementName( cfg_dom, action.FieldName, out strElementName, out strError); if (nRet == -1) return -1; } // 将值字符串中的宏替换 string strFieldValue = action.FieldValue; if (strFieldValue.IndexOf("%") != -1) { this._macroFileName = Path.Combine(this.MainForm.UserDir, "856_macrotable.xml"); if (File.Exists(this._macroFileName) == false) { strError = "宏定义文件 '" + this._macroFileName + "' 不存在,无法进行宏替换"; return -1; } string strResult = ""; // 解析宏 nRet = MacroUtil.Parse( false, strFieldValue, ParseOneMacro, out strResult, out strError); if (nRet == -1) { strError = "替换字符串 '" + strFieldValue + "' 中的宏时出错: " + strError; return -1; } strFieldValue = strResult; } if (string.IsNullOrEmpty(action.Action) == true) { // 替换内容 #if NO ChangeSubfield(ref strField, strElementName, strFieldValue, ref debug, ref bChanged); #endif if (SetSubfield(field, strElementName, strFieldValue, ref debug) == true) bChanged = true; } else { // add/remove string strState = GetSubfield(field, strElementName); string strOldState = strState; if (action.Action == "delete") { SetSubfield(field, strElementName, null, ref debug); bChanged = true; continue; } if (action.Action == "add") { if (String.IsNullOrEmpty(action.FieldValue) == false) StringUtil.SetInList(ref strState, strFieldValue, // action.FieldValue, true); } if (action.Action == "remove") { if (String.IsNullOrEmpty(action.FieldValue) == false) StringUtil.SetInList(ref strState, strFieldValue, // action.FieldValue, false); } if (strOldState != strState) { SetSubfield(field, strElementName, strState, ref debug); bChanged = true; // debug.Append("<" + strElementName + "> '" + strOldState + "' --> '" + strState + "'\r\n"); } } } strDebugInfo = debug.ToString(); if (bChanged == true) { strField = field.Text; return 1; } return 0; }
/// <summary> /// 将 USMARC 记录从 880 模式转换为 平行模式 /// </summary> /// <param name="record">要处理的记录</param> public static void ToParallel(MarcRecord record) { // 选定全部 880 字段 MarcNodeList fields = record.select("field[@name='880']"); if (fields.count == 0) return; foreach (MarcField field in fields) { string content_6 = field.select("subfield[@name='6']").FirstContent; if (string.IsNullOrEmpty(content_6) == true) continue; // 拆解 $6 内容 string strFieldName = ""; string strNumber = ""; string strScriptId = ""; string strOrientation = ""; _parseSubfield6(content_6, out strFieldName, out strNumber, out strScriptId, out strOrientation); if (string.IsNullOrEmpty(strScriptId) == true) { // 修正 $6 // 例子 ISBN 9789860139976 strScriptId = "$1"; field.select("subfield[@name='6']").Content = _buildSubfield6(strFieldName, strNumber, strScriptId, strOrientation); } // 找到关联的字段 MarcField main_field = _findField(record, strFieldName, field.Name, strNumber); if (main_field != null) { // 创建一个新的字段,把 880 字段内容复制过去 MarcField new_field = new MarcField(strFieldName, field.Indicator, field.Content); // 新字段插入到关联字段后面 main_field.after(new_field); // 删除 880 字段 field.detach(); main_field.select("subfield[@name='6']").Content = _buildSubfield6(strFieldName, strNumber, "", ""); } else { // 找不到关联的字段,把 880 字段的字段名修改了即可 field.Name = strFieldName; } } }
// 获得一个子字段内容,或局部内容 // parameters: // strSubfieldName 可能为 "a",也可能为 "x.rights" 形态 static string GetSubfield(MarcField field, string strPath) { if (string.IsNullOrEmpty(strPath) == true || strPath.Length < 1) throw new ArgumentException("strPath 参数值应为一个字符以上", "strPath"); string strSubfieldName = ""; string strPartName = ""; StringUtil.ParseTwoPart(strPath, ".", out strSubfieldName, out strPartName); string strContent = field.select("subfield[@name='"+strSubfieldName+"']").FirstContent; if (string.IsNullOrEmpty(strPartName) == true) return strContent; // 读取参数的时候,不在意内部顺序问题 Hashtable table = StringUtil.ParseParameters(strContent, ';', ':'); return (string)table[strPartName]; }
// 将亚马逊 XML 格式转换为 UNIMARC 格式 // parameters: // strStyle 转换风格。!856 表示不包含 856 字段 public static int AmazonXmlToUNIMARC(XmlNode root, string strStyle, out string strMARC, out string strError) { strMARC = ""; strError = ""; XmlNamespaceManager nsmgr = new XmlNamespaceManager(new NameTable()); nsmgr.AddNamespace("amazon", AmazonSearch.NAMESPACE); MarcRecord record = new MarcRecord(); // *** 001 string strASIN = DomUtil.GetElementText(root, "amazon:ASIN", nsmgr); if (string.IsNullOrEmpty(strASIN) == false) record.ChildNodes.add(new MarcField("001", "ASIN:" + strASIN)); // *** 010 // ISBN #if NO List<string> isbns = GetFieldValues(root, nsmgr, "amazon:ItemAttributes/amazon:ISBN"); if (isbns.Count == 0) isbns = GetFieldValues(root, nsmgr, "amazon:ItemAttributes/amazon:EAN"); #endif List<string> isbns = GetFieldValues(root, nsmgr, "amazon:ItemAttributes/amazon:EAN"); if (isbns.Count == 0) isbns = GetFieldValues(root, nsmgr, "amazon:ItemAttributes/amazon:ISBN"); // Binding List<string> bindings = GetFieldValues(root, nsmgr, "amazon:ItemAttributes/amazon:Binding"); // 价格 List<string> prices = GetPriceValues(root, nsmgr, "amazon:ItemAttributes/amazon:ListPrice"); for (int i = 0; i < Math.Max(isbns.Count, prices.Count); i++) { string isbn = ""; string binding = ""; string price = ""; if (i < isbns.Count) isbn = isbns[i]; if (i < bindings.Count) binding = bindings[i]; if (i < prices.Count) price = prices[i]; MarcField field = new MarcField("010", " "); record.ChildNodes.add(field); if (string.IsNullOrEmpty(isbn) == false) field.ChildNodes.add(new MarcSubfield("a", isbn)); if (string.IsNullOrEmpty(binding) == false && binding != "平装") field.ChildNodes.add(new MarcSubfield("b", binding)); if (string.IsNullOrEmpty(price) == false) field.ChildNodes.add(new MarcSubfield("d", price)); } // 011 List<string> issns = GetFieldValues(root, nsmgr, "amazon:ItemAttributes/amazon:ISSN"); // 200 List<string> titles = GetFieldValues(root, nsmgr, "amazon:ItemAttributes/amazon:Title"); List<Creator> creators = GetCreatorValues(root, nsmgr, "amazon:ItemAttributes/amazon:Creator"); { MarcField field = new MarcField("200", "1 "); record.ChildNodes.add(field); foreach (string title in titles) { field.ChildNodes.add(new MarcSubfield("a", title)); } int i = 0; foreach (Creator creator in creators) { field.ChildNodes.add(new MarcSubfield(i == 0 ? "f" : "g", creator.Name + creator.Role)); i++; } } // 2015/7/19 // 205 List<string> editions = GetFieldValues(root, nsmgr, "amazon:ItemAttributes/amazon:Edition"); foreach (string edition in editions) { MarcField field = new MarcField("205", " "); record.ChildNodes.add(field); field.ChildNodes.add(new MarcSubfield("a", edition)); } // 210 List<string> publishers = GetFieldValues(root, nsmgr, "amazon:ItemAttributes/amazon:Publisher"); List<string> publication_dates = GetFieldValues(root, nsmgr, "amazon:ItemAttributes/amazon:PublicationDate"); { MarcField field = new MarcField("210", " "); record.ChildNodes.add(field); foreach (string s in publishers) { field.ChildNodes.add(new MarcSubfield("c", s)); } foreach (string s in publication_dates) { // 日期字符串需要变换一下 field.ChildNodes.add(new MarcSubfield("d", GetPublishDateString(s))); } } // 215 a d List<string> pages = GetFieldValues(root, nsmgr, "amazon:ItemAttributes/amazon:NumberOfPages"); List<string> heights = GetHeightValues(root, nsmgr, "amazon:ItemAttributes/amazon:PackageDimensions"); { MarcField field = new MarcField("215", " "); record.ChildNodes.add(field); foreach (string s in pages) { field.ChildNodes.add(new MarcSubfield("a", s + "页")); } foreach (string s in heights) { field.ChildNodes.add(new MarcSubfield("d", s)); } } // 2015/7/19 // 330 List<string> reviews = GetCommentValues(root, nsmgr, "amazon:EditorialReviews/amazon:EditorialReview", "内容简介"); if (reviews.Count > 0) { MarcField field = new MarcField("330", " "); record.ChildNodes.add(field); foreach (string review in reviews) { field.ChildNodes.add(new MarcSubfield("a", review)); } } // 2015/7/19 // 610 List<string> subjects = GetFieldValues(root, nsmgr, "amazon:Subjects/amazon:Subject"); if (subjects.Count > 0) { MarcField field = new MarcField("610", "0 "); record.ChildNodes.add(field); foreach (string subject in subjects) { field.ChildNodes.add(new MarcSubfield("a", subject)); } } // 2015/7/19 // 7xx // authors 里面的元素通常已经被 creators 包含,creators 元素多余 authors。 // 转换策略是,把 authors 里的作为 701,creators 里面余下的作为 702 List<Creator> authors = GetCreatorValues(root, nsmgr, "amazon:ItemAttributes/amazon:Author"); foreach (Creator author in authors) { MarcField field = new MarcField("701", " 0"); record.ChildNodes.add(field); field.ChildNodes.add(new MarcSubfield("a", author.Name)); if (string.IsNullOrEmpty(author.Role) == false) field.ChildNodes.add(new MarcSubfield("4", author.Role)); } foreach (Creator creator in creators) { if (IndexOf(authors, creator.Name) != -1) continue; MarcField field = new MarcField("702", " 0"); record.ChildNodes.add(field); field.ChildNodes.add(new MarcSubfield("a", creator.Name)); if (string.IsNullOrEmpty(creator.Role) == false) field.ChildNodes.add(new MarcSubfield("4", creator.Role)); } if (StringUtil.IsInList("!856", strStyle) == false) { // 856 string[] names = new string[] { "SmallImage", "MediumImage", "LargeImage"}; foreach (string name in names) { List<ImageInfo> small_images = GetImageValues(root, nsmgr, "amazon:" + name); foreach (ImageInfo info in small_images) { MarcField field = new MarcField("856", "4 "); record.ChildNodes.add(field); field.ChildNodes.add(new MarcSubfield("3", "Cover image")); field.ChildNodes.add(new MarcSubfield("u", info.Url)); field.ChildNodes.add(new MarcSubfield("q", GetMime(info.Url))); field.ChildNodes.add(new MarcSubfield("x", "type:FrontCover." + name + ";size:" + info.Size + ";source:Amazon:")); // + dlg.SelectedItem.ASIN } } } strMARC = record.Text; return 0; }
// parameters: // strValue 要修改成的值。如果为 null,表示删除这个子字段/部分。如果为 "" 则表示把内容设为空,但子字段还会被保留 // return: // 是否发生了修改 static bool SetSubfield(MarcField field, string strPath, string strValue, ref StringBuilder debug) { if (string.IsNullOrEmpty(strPath) == true || strPath.Length < 1) throw new ArgumentException("strPath 参数值应为一个字符以上", "strPath"); if (strPath == "indicator1") { if (string.IsNullOrEmpty(strValue) == true) throw new ArgumentException("当操作 indicator 的时候, strValue 参数值不允许为空", "strValue"); if (field.Indicator1 == strValue[0]) return false; field.Indicator1 = strValue[0]; return true; } if (strPath == "indicator2") { if (string.IsNullOrEmpty(strValue) == true) throw new ArgumentException("当操作 indicator 的时候, strValue 参数值不允许为空", "strValue"); if (field.Indicator2 == strValue[0]) return false; field.Indicator2 = strValue[0]; return true; } string strSubfieldName = ""; string strPartName = ""; StringUtil.ParseTwoPart(strPath, ".", out strSubfieldName, out strPartName); MarcNodeList subfields = field.select("subfield[@name='" + strSubfieldName + "']"); if (subfields.count == 0) { if (strValue == null) return false; // 正好,也不用删除了 string strContent = strValue; if (string.IsNullOrEmpty(strPartName) == false) strContent = strPartName + ":" + strValue; field.ChildNodes.insertSequence(new MarcSubfield(strSubfieldName, strContent)); debug.Append("新增 <" + strPath + "> '" + strContent + "'\r\n"); return true; } else { // 对整个子字段内容进行操作。只修改第一个子字段内容 if (string.IsNullOrEmpty(strPartName) == true) { if (strValue == null) { subfields[0].detach(); return true; } if (subfields[0].Content == strValue) return false; subfields[0].Content = strValue; return true; } string strContent = subfields[0].Content; ParamList table = ParamList.Build(strContent, ';', ':'); if (strValue == null) table.Remove(strPartName); else table[strPartName] = strValue; string strNewContent = table.ToString(';', ':'); if (strContent == strNewContent) return false; subfields[0].Content = strNewContent; debug.Append("<" + strPartName + "> '" + strContent + "' --> '" + strNewContent + "'\r\n"); return true; } }
// 插入一个新的字段 public FieldLine NewField(int index) { EasyLine ref_line = null; if (index < this.Items.Count) ref_line = this.Items[index]; if (ref_line is SubfieldLine) { ref_line = GetFieldLine(ref_line as SubfieldLine); if (ref_line == null) { throw new Exception("index 为 " + index.ToString() + " 的子字段行没有找到字段行"); } index = this.Items.IndexOf(ref_line); Debug.Assert(index != -1, ""); } // 询问字段名 NewSubfieldDialog dlg = new NewSubfieldDialog(); GuiUtil.SetControlFont(dlg, this.Font); // dlg.Font = this.Font; dlg.Text = "新字段"; dlg.AutoComplete = true; if (ref_line != null) dlg.NameString = ref_line.Name; else dlg.NameString = this.DefaultFieldName; dlg.MarcDefDom = this.MarcDefDom; dlg.Lang = this.Lang; dlg.StartPosition = FormStartPosition.CenterScreen; dlg.ShowDialog(this); if (dlg.DialogResult != DialogResult.OK) return null; bool bControlField = Record.IsControlFieldName(dlg.NameString); string strDefaultValue = ""; string strIndicator = " "; if (bControlField == false) strDefaultValue = new string((char)31, 1) + "a"; List<string> results = null; string strError = ""; // 获得宏值 // parameters: // strSubFieldName 子字段名。特殊地,如果为"#indicator",表示想获取该字段的指示符缺省值 // return: // -1 error // 0 not found // 1 found int nRet = GetDefaultValue( 0, // index, dlg.NameString, "", out results, out strError); if (nRet == -1) MessageBox.Show(this, strError); if (results != null && results.Count > 0) { strDefaultValue = results[0]; if (bControlField == false) SplitDefaultValue(strDefaultValue, out strIndicator, out strDefaultValue); } bool bChanged = false; // 辅助剖析子字段的对象 MarcField field_node = new MarcField(dlg.NameString, strIndicator, strDefaultValue); FieldLine field_line = new FieldLine(this); field_line.IsControlField = bControlField; field_line.Name = dlg.NameString; field_line.Caption = GetCaption(dlg.NameString, "", this._includeNumber); if (bControlField == false) { field_line.Indicator = strIndicator; // 从 marcdef 中获得缺省的指示符值 field_line.ExpandState = ExpandState.Expanded; } EasyLine after_line = null; #if FIX bool bExpanded = false; bool bHideChanged = false; #endif if (dlg.InsertBefore == true) { after_line = ref_line; } else { // 如果插入点是字段行,需要跳过下属的子字段行 // EasyLine ref_line = this.Items[index]; if (ref_line is FieldLine) { List<EasyLine> lines = GetSubfieldLines(ref_line as FieldLine); index += lines.Count + 1; } else index++; if (index < this.Items.Count) after_line = this.Items[index]; } #if FIX if (after_line != null) { // 如果插入位置后面一个字段是隐藏状态,则会出现故障,需要先修改为显示状态,插入后再隐藏 if (after_line is FieldLine && after_line.Visible == false) { this.ToggleHide(after_line as FieldLine); bHideChanged = true; } // 如果本字段是收缩状态,则会出现故障,需要先修改为展开状态,插入后再收缩 if (after_line.ExpandState == ExpandState.Collapsed) { this.ToggleExpand(after_line); Debug.Assert(after_line.ExpandState == ExpandState.Expanded, ""); bExpanded = true; } } #endif InsertNewLine(index++, field_line, false); bChanged = true; // 如果必要,创建子字段对象 foreach (MarcSubfield subfield_node in field_node.ChildNodes) { SubfieldLine subfield_line = new SubfieldLine(this); subfield_line.Name = subfield_node.Name; subfield_line.Caption = GetCaption(field_node.Name, subfield_node.Name, this._includeNumber); subfield_line.Content = subfield_node.Content; InsertNewLine(index++, subfield_line, false); bChanged = true; } #if FIX // 把参考行恢复到以前的状态 if (after_line != null && bExpanded == true) { this.ToggleExpand(after_line); Debug.Assert(after_line.ExpandState == ExpandState.Collapsed, ""); } if (after_line != null && bHideChanged == true) { this.ToggleHide(after_line as FieldLine); } #endif if (bChanged == true) this.FireTextChanged(); return field_line; }
static string BuildOpacText(string strField) { if (string.IsNullOrEmpty(strField) == true) return ""; StringBuilder text = new StringBuilder(); MarcField field = new MarcField(strField); text.Append("指示符1:" + field.Indicator1 + "\r\n"); text.Append("指示符2:" + field.Indicator2 + "\r\n"); foreach(MarcSubfield subfield in field.ChildNodes) { if (subfield.Name == "x") { string [] parts = subfield.Content.Split(new char []{';'}); foreach(string part in parts) { string left = ""; string right = ""; StringUtil.ParseTwoPart(part, ":", out left, out right); text.Append("$" + subfield.Name + "." + left + ":" + right + "\r\n"); } continue; } text.Append("$" + subfield.Name + ":" + subfield.Content + "\r\n"); } return text.ToString(); }
/// <summary> /// 创建一个新的 MarcField 节点对象,从当前对象复制出全部内容和下级节点 /// </summary> /// <returns>新的节点对象</returns> public override MarcNode clone() { MarcNode new_node = new MarcField(); new_node.Text = this.Text; new_node.Parent = null; // 尚未和任何对象连接 return new_node; }
int SaveChangedRecords(List<ListViewItem> items, out string strError) { strError = ""; int nRet = 0; int nReloadCount = 0; int nSavedCount = 0; List<string> changed_biblio_recpaths = new List<string>(); Hashtable relation_table = new Hashtable(); // 书目记录路径 --> List<ListViewItem> stop.Style = StopStyle.EnableHalfStop; stop.OnStop += new StopEventHandler(this.DoStop); stop.Initial("正在保存书目记录 ..."); stop.BeginLoop(); this.EnableControls(false); this.listView_records.Enabled = false; try { // 创建书目记录和册事项的对照关系。注意这是针对全部行的,不仅仅是已经选择的行。因为删除操作可能会涉及到没有选择的行的 index 列内容刷新显示 foreach (ListViewItem item in this.listView_records.Items) { if (stop != null && stop.State != 0) { strError = "已中断"; return -1; } string strBiblioRecPath = item.Text; if (string.IsNullOrEmpty(strBiblioRecPath) == true) continue; { // 记载关系 List<ListViewItem> array = (List<ListViewItem>)relation_table[strBiblioRecPath]; if (array == null) { array = new List<ListViewItem>(); relation_table[strBiblioRecPath] = array; } array.Add(item); } } foreach (ListViewItem item in items) { if (stop != null && stop.State != 0) { strError = "已中断"; return -1; } string strBiblioRecPath = item.Text; if (string.IsNullOrEmpty(strBiblioRecPath) == true) continue; LineInfo line_info = (LineInfo)item.Tag; if (line_info == null) { strError = "line_info == null"; return -1; } if (IsItemChanged(item) == false) continue; BiblioInfo biblio_info = (BiblioInfo)this.m_biblioTable[strBiblioRecPath]; if (biblio_info == null) { strError = "1 在 m_biblioTable 中没有找到路径为 '" + strBiblioRecPath + "' 的书目记录信息"; return -1; // goto CONTINUE; } { // 把对字段的修改合并到书目记录中 // return: // -1 出错 // 0 书目记录没有发生修改 // 1 书目记录发生了修改 nRet = MergeChange(line_info, biblio_info, out strError); if (nRet == -1) return -1; // 记载发生过修改的书目记录路径 if (nRet == 1) { if (changed_biblio_recpaths.IndexOf(strBiblioRecPath) == -1) changed_biblio_recpaths.Add(strBiblioRecPath); } } if (line_info.State == "delete") { // 把同一书目记录的删除位置以后的 856 字段的 index 都减去 1 nRet = ChangeFieldIndex( relation_table, item, -1, out strError); if (nRet == -1) return -1; this.listView_records.Items.Remove(item); this.m_nChangedCount--; Debug.Assert(this.m_nChangedCount >= 0, ""); continue; } item.BackColor = SystemColors.Window; item.ForeColor = SystemColors.WindowText; this.m_nChangedCount--; Debug.Assert(this.m_nChangedCount >= 0, ""); Debug.Assert(string.IsNullOrEmpty(line_info.NewField) == false, ""); if (string.IsNullOrEmpty(line_info.NewField) == false) { line_info.OldField = line_info.NewField; line_info.NewField = ""; } { // 刷新浏览行的显示 MarcField field = new MarcField(line_info.OldField); SetItemColumns(item, null, field, line_info.Index); } } // TODO: 如果要优化算法的话,可以建立书目记录和浏览行之间的联系,在书目记录保存成功后才修改 line_info.NewField 和刷新浏览行显示。这样的好处是,一旦中途出错,还有干净重新保存的可能 stop.SetProgressRange(0, changed_biblio_recpaths.Count); int i = 0; foreach(string strBiblioRecPath in changed_biblio_recpaths) { BiblioInfo biblio_info = (BiblioInfo)this.m_biblioTable[strBiblioRecPath]; if (biblio_info == null) { strError = "2 在 m_biblioTable 中没有找到路径为 '" + strBiblioRecPath + "' 的书目记录信息"; return -1; // goto CONTINUE; } if (string.IsNullOrEmpty(biblio_info.NewXml) == true) { Debug.Assert(false, ""); goto CONTINUE; } // 暂不处理外来记录的保存 // TODO: 此时警告不能保存? if (biblio_info.RecPath.IndexOf("@") != -1) { Debug.Assert(false, ""); goto CONTINUE; } string strOutputPath = ""; stop.SetMessage("正在保存书目记录 " + strBiblioRecPath); byte[] baNewTimestamp = null; long lRet = Channel.SetBiblioInfo( stop, "change", strBiblioRecPath, "xml", biblio_info.NewXml, biblio_info.Timestamp, "", out strOutputPath, out baNewTimestamp, out strError); if (lRet == -1) { if (Channel.ErrorCode == ErrorCode.TimestampMismatch) { DialogResult result = MessageBox.Show(this, "保存书目记录 " + strBiblioRecPath + " 时遭遇时间戳不匹配: " + strError + "。\r\n\r\n此记录已无法被保存。\r\n\r\n请问现在是否要顺便重新装载此记录? \r\n\r\n(Yes 重新装载;\r\nNo 不重新装载、但继续处理后面的记录保存; \r\nCancel 中断整批保存操作)", "Marc856SearchForm", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1); if (result == System.Windows.Forms.DialogResult.Cancel) break; if (result == System.Windows.Forms.DialogResult.No) goto CONTINUE; // 重新装载书目记录到 OldXml string[] results = null; // byte[] baTimestamp = null; lRet = Channel.GetBiblioInfos( stop, strBiblioRecPath, "", new string[] { "xml" }, // formats out results, out baNewTimestamp, out strError); if (lRet == 0) { // TODO: 警告后,把 item 行移除? return -1; } if (lRet == -1) return -1; if (results == null || results.Length == 0) { strError = "results error"; return -1; } biblio_info.OldXml = results[0]; biblio_info.Timestamp = baNewTimestamp; nReloadCount++; goto CONTINUE; } return -1; } // 检查是否有部分字段被拒绝 if (Channel.ErrorCode == ErrorCode.PartialDenied) { DialogResult result = MessageBox.Show(this, "保存书目记录 " + strBiblioRecPath + " 时部分字段被拒绝。\r\n\r\n此记录已部分保存成功。\r\n\r\n请问现在是否要顺便重新装载此记录以便观察? \r\n\r\n(Yes 重新装载(到旧记录部分);\r\nNo 不重新装载、但继续处理后面的记录保存; \r\nCancel 中断整批保存操作)", "BiblioSearchForm", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1); if (result == System.Windows.Forms.DialogResult.Cancel) break; if (result == System.Windows.Forms.DialogResult.No) goto CONTINUE; // 重新装载书目记录到 OldXml string[] results = null; // byte[] baTimestamp = null; lRet = Channel.GetBiblioInfos( stop, strBiblioRecPath, "", new string[] { "xml" }, // formats out results, out baNewTimestamp, out strError); if (lRet == 0) { // TODO: 警告后,把 item 行移除? return -1; } if (lRet == -1) return -1; if (results == null || results.Length == 0) { strError = "results error"; return -1; } biblio_info.OldXml = results[0]; biblio_info.Timestamp = baNewTimestamp; nReloadCount++; goto CONTINUE; } biblio_info.Timestamp = baNewTimestamp; biblio_info.OldXml = biblio_info.NewXml; biblio_info.NewXml = ""; nSavedCount++; CONTINUE: stop.SetProgressValue(i); i++; } } finally { stop.EndLoop(); stop.OnStop -= new StopEventHandler(this.DoStop); stop.Initial(""); stop.HideProgress(); stop.Style = StopStyle.None; this.EnableControls(true); this.listView_records.Enabled = true; } #if NO // 刷新书目摘要 nRet = FillBiblioSummaryColumn(items, 0, true, true, out strError); if (nRet == -1) return -1; #endif DoViewComment(false); strError = ""; if (nSavedCount > 0) strError += "共保存书目记录 " + nSavedCount + " 条"; if (nReloadCount > 0) { if (string.IsNullOrEmpty(strError) == false) strError += " ; "; strError += "有 " + nReloadCount + " 条书目记录因为时间戳不匹配或部分字段被拒绝而重新装载旧记录部分(请观察后重新保存)"; } return 0; }
// fangbian diaoyong /// <summary> /// 在下级节点末尾追加一个字段节点 /// </summary> /// <param name="field">字段节点</param> public void add(MarcField field) { this.ChildNodes.add(field); }
// 模拟进行插入分类号的操作,并显示出 MARC 新旧对照格式 void SimulateAddClassNumber() { MarcRecord record = new MarcRecord(this.RelationCollection.MARC); bool bChanged = false; foreach(RelationControl control in this.flowLayoutPanel_relationList.Controls) { string strNewClass = control.TargetText; if (string.IsNullOrEmpty(strNewClass) == true) continue; ControlInfo info = (ControlInfo)control.Tag; string strTargetFieldName = info.Relation.TargetDef.Substring(0, 3); string strTargetSubfieldName = info.Relation.TargetDef.Substring(3); List<string> class_list = StringUtil.SplitList(strNewClass); foreach(string text in class_list) { MarcField field = new MarcField('$', strTargetFieldName + " " + "$" + strTargetSubfieldName + text); record.ChildNodes.insertSequence(field, InsertSequenceStyle.PreferTail); bChanged = true; } } if (bChanged) this.OutputMARC = record.Text; else this.OutputMARC = ""; DisplayMarc(this.RelationCollection.MARC, bChanged ? this.OutputMARC : null); }