// 从册条码号(+册记录路径)获得种记录摘要,或者从订购记录路径、期记录路径、评注记录路径获得种记录摘要 // 权限: 需要具有getbibliosummary权限 // parameters: // strBiblioRecPathExclude 除开列表中的这些种路径, 才返回摘要内容, 否则仅仅返回种路径即可 public LibraryServerResult GetBiblioSummary( SessionInfo sessioninfo, RmsChannel channel, string strItemBarcode, string strConfirmItemRecPath, string strBiblioRecPathExclude, out string strBiblioRecPath, out string strSummary) { strBiblioRecPath = ""; strSummary = ""; string strError = ""; LibraryServerResult result = new LibraryServerResult(); // 权限判断 // 权限字符串 if (StringUtil.IsInList("getbibliosummary", sessioninfo.RightsOrigin) == false && StringUtil.IsInList("order", sessioninfo.RightsOrigin) == false) { result.Value = -1; result.ErrorInfo = "获取种摘要信息被拒绝。不具备order、getbibliosummary权限。"; result.ErrorCode = ErrorCode.AccessDenied; return result; } int nRet = 0; long lRet = 0; if (string.IsNullOrEmpty(strItemBarcode) == true && string.IsNullOrEmpty(strConfirmItemRecPath) == true) { strError = "strItemBarcode和strConfirmItemRecPath参数值不能同时为空"; goto ERROR1; } string strItemXml = ""; string strOutputItemPath = ""; string strMetaData = ""; /* RmsChannel channel = sessioninfo.Channels.GetChannel(this.WsUrl); if (channel == null) { strError = "channel == null"; goto ERROR1; } * */ // 特殊情况,通过种路径 string strHead = "@bibliorecpath:"; if (strItemBarcode.Length > strHead.Length && strItemBarcode.Substring(0, strHead.Length) == strHead) { strBiblioRecPath = strItemBarcode.Substring(strHead.Length); // 检查书目库名是否合法 string strTempBiblioDbName = ResPath.GetDbName(strBiblioRecPath); if (this.IsBiblioDbName(strTempBiblioDbName) == false) { strError = "strItemBarcode参数中析出的书目库路径 '" + strBiblioRecPath + "' 中,书目库名 '" + strTempBiblioDbName + "' 不是系统定义的书目库名"; goto ERROR1; } goto LOADBIBLIO; } bool bByRecPath = false; // 是否经过记录路径来获取的? if (string.IsNullOrEmpty(strItemBarcode) == false) { // 获得册记录 // return: // -1 error // 0 not found // 1 命中1条 // >1 命中多于1条 nRet = this.GetItemRecXml( channel, strItemBarcode, out strItemXml, out strOutputItemPath, out strError); if (nRet == 0) { result.Value = 0; result.ErrorInfo = "册记录没有找到"; result.ErrorCode = ErrorCode.NotFound; return result; } if (nRet == -1) goto ERROR1; } // 如果命中多于一条(或者没有条码号),并且已经有确定的册记录路径辅助判断 if (string.IsNullOrEmpty(strItemBarcode) == true || (nRet > 1 && String.IsNullOrEmpty(strConfirmItemRecPath) == false)) { // 检查路径中的库名,是不是实体库、订购库、期库、评注库名 nRet = CheckRecPath(strConfirmItemRecPath, "item,order,issue,comment", out strError); if (nRet != 1) goto ERROR1; byte[] item_timestamp = null; lRet = channel.GetRes(strConfirmItemRecPath, out strItemXml, out strMetaData, out item_timestamp, out strOutputItemPath, out strError); if (lRet == -1) { strError = "根据strConfirmItemRecPath '" + strConfirmItemRecPath + "' 获得记录失败: " + strError; goto ERROR1; } bByRecPath = true; } // 从册记录中获得从属的种id string strBiblioRecID = ""; XmlDocument dom = new XmlDocument(); try { dom.LoadXml(strItemXml); } catch (Exception ex) { strError = "册记录XML装载到DOM出错:" + ex.Message; goto ERROR1; } if (bByRecPath == true && string.IsNullOrEmpty(strItemBarcode) == false) // 2011/9/6 { // 这种情况需要核实册条码号 string strTempItemBarcode = DomUtil.GetElementText(dom.DocumentElement, "//barcode"); if (strTempItemBarcode != strItemBarcode) { strError = "通过册条码号 '" + strItemBarcode + "' 获取实体记录发现命中多条,然后自动用记录路径 '" + strConfirmItemRecPath + "' 来获取实体记录,虽然获取成功,但是发现所获取的记录中<barcode>元素中的册条码号 '" + strTempItemBarcode + "' 不符合要求的册条码号 '" + strItemBarcode + "。(后面)这种情况可能是由于实体记录发生过移动造成的。"; goto ERROR1; } } strBiblioRecID = DomUtil.GetElementText(dom.DocumentElement, "parent"); // if (String.IsNullOrEmpty(strBiblioRecID) == true) { strError = "种下属记录XML中<parent>元素缺乏或者值为空, 因此无法定位种记录"; goto ERROR1; } // 从配置文件中获得和实体库对应的书目库名 /* // 准备工作: 映射数据库名 nRet = this.GetGlobalCfg(sessioninfo.Channels, out strError); if (nRet == -1) goto ERROR1; * */ string strItemDbName = ResPath.GetDbName(strOutputItemPath); string strBiblioDbName = ""; // 根据书目下属库名, 找到对应的书目库名 // return: // -1 出错 // 0 没有找到 // 1 找到 nRet = this.GetBiblioDbNameByChildDbName(strItemDbName, out strBiblioDbName, out strError); if (nRet == -1) goto ERROR1; if (nRet == 0) { strError = "下属库名 '" + strItemDbName + "' 没有找到所从属的书目库名"; goto ERROR1; } string strBiblioXml = ""; strBiblioRecPath = strBiblioDbName + "/" + strBiblioRecID; LOADBIBLIO: // 看看是否在排除列表中 if (String.IsNullOrEmpty(strBiblioRecPathExclude) == false && IsInBarcodeList(strBiblioRecPath, strBiblioRecPathExclude) == true) { result.Value = 1; return result; } /* strSummary = ""; result.Value = 1; return result; * */ // 获得本地配置文件 string strLocalPath = ""; string strRemotePath = BrowseFormat.CanonicalizeScriptFileName( ResPath.GetDbName(strBiblioRecPath), "./cfgs/summary.fltx"); nRet = this.CfgsMap.MapFileToLocal( // sessioninfo.Channels, channel, strRemotePath, out strLocalPath, out strError); if (nRet == -1) goto ERROR1; if (nRet == 0) { // 配置.fltx文件不存在, 再试探.cs文件 strRemotePath = BrowseFormat.CanonicalizeScriptFileName( ResPath.GetDbName(strBiblioRecPath), "./cfgs/summary.cs"); nRet = this.CfgsMap.MapFileToLocal( // sessioninfo.Channels, channel, strRemotePath, out strLocalPath, out strError); if (nRet == -1) goto ERROR1; if (nRet == 0) { strError = strRemotePath + "不存在..."; goto ERROR1; } } bool bFltx = false; // 如果是一般.cs文件, 还需要获得.cs.ref配置文件 if (IsCsFileName(strRemotePath) == true) { string strTempPath = ""; nRet = this.CfgsMap.MapFileToLocal( // sessioninfo.Channels, channel, strRemotePath + ".ref", out strTempPath, out strError); if (nRet == -1) goto ERROR1; bFltx = false; } else { bFltx = true; } // 取得种记录 byte[] timestamp = null; lRet = channel.GetRes(strBiblioRecPath, out strBiblioXml, out strMetaData, out timestamp, out strOutputItemPath, out strError); if (lRet == -1) { strError = "获得种记录 '" + strBiblioRecPath + "' 时出错: " + strError; goto ERROR1; } string strMarc = ""; string strMarcSyntax = ""; { // 转换为MARC格式 // 将MARCXML格式的xml记录转换为marc机内格式字符串 // parameters: // bWarning ==true, 警告后继续转换,不严格对待错误; = false, 非常严格对待错误,遇到错误后不继续转换 // strMarcSyntax 指示marc语法,如果=="",则自动识别 // strOutMarcSyntax out参数,返回marc,如果strMarcSyntax == "",返回找到marc语法,否则返回与输入参数strMarcSyntax相同的值 nRet = MarcUtil.Xml2Marc(strBiblioXml, true, "", // this.CurMarcSyntax, out strMarcSyntax, out strMarc, out strError); if (nRet == -1) goto ERROR1; } string strFragment = ""; if (StringUtil.IsInList("coverimage", strBiblioRecPathExclude) == true) { // 获得封面图像 URL string strImageUrl = ScriptUtil.GetCoverImageUrl(strMarc, "SmallImage"); if (string.IsNullOrEmpty(strImageUrl) == false) { if (StringUtil.HasHead(strImageUrl, "uri:") == true) { strImageUrl = "object-path:" + strBiblioRecPath + "/object/" + strImageUrl.Substring(4); strFragment = "<img class='biblio pending' name='" + strImageUrl + "'/>"; } else { strFragment = "<img class='biblio' src='" + strImageUrl + "'/>"; } } } // 将种记录数据从XML格式转换为HTML格式 if (string.IsNullOrEmpty(strBiblioXml) == false) { if (bFltx == true) { string strFilterFileName = strLocalPath; nRet = this.ConvertBiblioXmlToHtml( strFilterFileName, strMarc, // strBiblioXml, strMarcSyntax, strBiblioRecPath, out strSummary, out strError); } else { nRet = this.ConvertRecordXmlToHtml( strLocalPath, strLocalPath + ".ref", strBiblioXml, strBiblioRecPath, // 2009/10/18 out strSummary, out strError); } if (nRet == -1) goto ERROR1; } else strSummary = ""; strSummary = strFragment + strSummary; result.Value = 1; return result; ERROR1: result.Value = -1; result.ErrorInfo = strError; result.ErrorCode = ErrorCode.SystemError; return result; }
// 装载记录 // 把strRecordPath表示的记录装载到窗口中,并且在窗口第一行 // 路径内容设置好 // parameters: // strRecordPath 记录路径。如果==null,表示直接用textBox_recPath中当前的内容作为路径 // strExtStyle 如果为null,表示获取strRecordPath或textbox表示的记录。如果为"next"或"prev", // 则表示取其后或前一条记录 // return: // -2 放弃 // -1 出错 // 0 正常 // 1 到头或者到尾 public int LoadRecord(string strRecordPath, string strExtStyle, out string strError) { strError = ""; EnableControlsInLoading(true); try { if (this.Changed == true) { DialogResult result = MessageBox.Show(this, "装载新内容前, 发现当前窗口中已有内容修改后未来得及保存。是否要继续装载新内容到窗口中(这样将丢失先前修改过的内容)?\r\n\r\n(是)继续装载新内容 (否)不装载新内容", "dp2rms", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2); if (result != DialogResult.Yes) { strError = "装载新内容操作被放弃..."; return -2; } } if (strRecordPath != null) textBox_recPath.Text = strRecordPath; ResPath respath = new ResPath(textBox_recPath.Text); this.Text = respath.ReverseFullPath; string strContent; string strMetaData; // string strError; byte [] baTimeStamp = null; string strOutputPath; // 使用Channel RmsChannel channelSave = channel; channel = Channels.GetChannel(respath.Url); Debug.Assert(channel != null, "Channels.GetChannel 异常"); try { string strStyle = "content,data,metadata,timestamp,outputpath,withresmetadata"; // if (strExtStyle != null && strExtStyle != "") { strStyle += "," + strExtStyle; } stop.OnStop += new StopEventHandler(this.DoStop); stop.Initial("正在装载记录" + respath.FullPath); stop.BeginLoop(); long lRet = channel.GetRes(respath.Path, strStyle, // this.eventClose, out strContent, out strMetaData, out baTimeStamp, out strOutputPath, out strError); stop.EndLoop(); stop.OnStop -= new StopEventHandler(this.DoStop); stop.Initial(""); this.TimeStamp = baTimeStamp; // 设置时间戳很重要。即便xml不合法,也应设置好时间戳,否则窗口无法进行正常删除。 this.strDatabaseOriginPath = respath.Url+"?"+strOutputPath; // 保存从数据库中来的原始path if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFoundSubRes) { // 下级资源不存在, 警告一下就行了 MessageBox.Show(this, strError); goto CONTINUELOAD; } else if (channel.ErrorCode == ChannelErrorCode.NotFound) { if (strExtStyle == "prev") strError = "到头"; else if (strExtStyle == "next") strError = "到尾"; return 1; } else { // this.TimeStamp = null; strError = "从路径 '"+respath.Path+"' 获取记录时出错: " + strError; return -1; } } } finally { channel = channelSave; } CONTINUELOAD: respath.Path = strOutputPath; textBox_recPath.Text = respath.FullPath; //string strTemp = ByteArray.GetHexTimeStampString(baTimeStamp); this.m_strMetaData = strMetaData; // 记忆XML记录的元数据 int nRet = SetRecordToControls(strContent, out strError); if (nRet == -1) return -1; return 0; } finally { EnableControlsInLoading(false); } }
// 根据数据库模板的定义,刷新一个已经存在的数据库的定义 // return: // -1 // 0 keys定义没有更新 // 1 keys定义更新了 int RefreshDatabase(RmsChannel channel, string strTemplateDir, string strDatabaseName, string strIncludeFilenames, string strExcludeFilenames, out string strError) { strError = ""; int nRet = 0; strIncludeFilenames = strIncludeFilenames.ToLower(); strExcludeFilenames = strExcludeFilenames.ToLower(); bool bKeysChanged = false; DirectoryInfo di = new DirectoryInfo(strTemplateDir); FileInfo[] fis = di.GetFiles(); // 创建所有文件对象 for (int i = 0; i < fis.Length; i++) { string strName = fis[i].Name; if (strName == "." || strName == "..") continue; if (FileUtil.IsBackupFile(strName) == true) continue; /* if (strName.ToLower() == "keys" || strName.ToLower() == "browse") continue; * */ // 如果Include和exclude里面都有一个文件名,优先依exclude(排除) if (StringUtil.IsInList(strName, strExcludeFilenames) == true) continue; if (strIncludeFilenames != "*") { if (StringUtil.IsInList(strName, strIncludeFilenames) == false) continue; } string strFullPath = fis[i].FullName; nRet = ConvertGb2312TextfileToUtf8(strFullPath, out strError); if (nRet == -1) return -1; string strExistContent = ""; string strNewContent = ""; Stream new_stream = new FileStream(strFullPath, FileMode.Open); { StreamReader sr = new StreamReader(new_stream, Encoding.UTF8); strNewContent = ConvertCrLf(sr.ReadToEnd()); } new_stream.Seek(0, SeekOrigin.Begin); try { string strPath = strDatabaseName + "/cfgs/" + strName; // 获取已有的配置文件对象 byte[] timestamp = null; string strOutputPath = ""; string strMetaData = ""; string strStyle = "content,data,metadata,timestamp,outputpath"; MemoryStream exist_stream = new MemoryStream(); try { long lRet = channel.GetRes( strPath, exist_stream, null, // stop, strStyle, null, // byte [] input_timestamp, out strMetaData, out timestamp, out strOutputPath, out strError); if (lRet == -1) { // 配置文件不存在,怎么返回错误码的? if (channel.ErrorCode == ChannelErrorCode.NotFound) { timestamp = null; goto DO_CREATE; } return -1; } exist_stream.Seek(0, SeekOrigin.Begin); { StreamReader sr = new StreamReader(exist_stream, Encoding.UTF8); strExistContent = ConvertCrLf(sr.ReadToEnd()); } } finally { if (exist_stream != null) exist_stream.Close(); } // 比较本地的和服务器的有无区别,无区别就不要上载了 if (strExistContent == strNewContent) { continue; } DO_CREATE: // 在服务器端创建对象 // parameters: // strStyle 风格。当创建目录的时候,为"createdir",否则为空 // return: // -1 错误 // 1 已经存在同名对象 // 0 正常返回 nRet = NewServerSideObject( channel, strPath, "", new_stream, timestamp, out strError); if (nRet == -1) return -1; if (nRet == 1) { strError = "NewServerSideObject()发现已经存在同名对象: " + strError; return -1; } if (strName.ToLower() == "keys") bKeysChanged = true; } finally { new_stream.Close(); } } if (bKeysChanged == true) { // 对数据库及时调用刷新keys表的API long lRet = channel.DoRefreshDB( "begin", strDatabaseName, false, out strError); if (lRet == -1) { strError = "数据库 '" + strDatabaseName + "' 的定义已经被成功刷新,但在刷新内核Keys表操作时失败: " + strError; return -1; } return 1; } return 0; }
// return: // -1 出错 // 0 没有找到 // 1 找到 int GetMarcDefCfgFile(string strUrl, string strDbName, out Stream s, out string strError) { strError = ""; s = null; if (String.IsNullOrEmpty(strUrl) == true) { /* strError = "URL为空"; goto ERROR1; */ return 0; } string strPath = strDbName + "/cfgs/marcdef"; // 使用Channel RmsChannel channelSave = channel; channel = Channels.GetChannel(strUrl); Debug.Assert(channel != null, "Channels.GetChannel 异常"); try { string strContent; // string strError; stop.OnStop += new StopEventHandler(this.DoStop); stop.Initial("正在下载文件" + strPath); stop.BeginLoop(); byte[] baTimeStamp = null; string strMetaData; string strOutputPath; long lRet = channel.GetRes( MainForm.cfgCache, strPath, out strContent, out strMetaData, out baTimeStamp, out strOutputPath, out strError); stop.EndLoop(); stop.OnStop -= new StopEventHandler(this.DoStop); stop.Initial(""); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) return 0; strError = "获得配置文件 '" +strPath+ "' 时出错:" + strError; goto ERROR1; } else { byte [] baContent = StringUtil.GetUtf8Bytes(strContent, true); MemoryStream stream = new MemoryStream(baContent); s = stream; } } finally { channel = channelSave; } return 1; ERROR1: return -1; }
private void MarcEditor_GetConfigDom(object sender, GetConfigDomEventArgs e) { if (String.IsNullOrEmpty(textBox_recPath.Text) == true) { e.ErrorInfo = "记录路径为空,无法获得配置文件 '" + e.Path + "'"; return; } ResPath respath = new ResPath(textBox_recPath.Text); // 得到干净的文件名 string strCfgFileName = e.Path; int nRet = strCfgFileName.IndexOf("#"); if (nRet != -1) { strCfgFileName = strCfgFileName.Substring(0, nRet); } string strPath = ResPath.GetDbName(respath.Path) + "/cfgs/" + strCfgFileName; // 在cache中寻找 e.XmlDocument = this.MainForm.DomCache.FindObject(strPath); if (e.XmlDocument != null) return; // 使用Channel RmsChannel channelSave = channel; channel = Channels.GetChannel(respath.Url); Debug.Assert(channel != null, "Channels.GetChannel 异常"); m_nInGetCfgFile++; try { string strContent; string strError; stop.OnStop += new StopEventHandler(this.DoStop); stop.Initial("正在下载文件" + strPath); stop.BeginLoop(); byte[] baTimeStamp = null; string strMetaData; string strOutputPath; long lRet = channel.GetRes( MainForm.cfgCache, strPath, out strContent, out strMetaData, out baTimeStamp, out strOutputPath, out strError); stop.EndLoop(); stop.OnStop -= new StopEventHandler(this.DoStop); stop.Initial(""); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) { e.ErrorInfo = ""; return; } e.ErrorInfo = "获得配置文件 '" + strPath + "' 时出错:" + strError; return; } XmlDocument dom = new XmlDocument(); try { dom.LoadXml(strContent); } catch (Exception ex) { e.ErrorInfo = "配置文件 '" + strPath + "' 装入XMLDUM时出错: " + ex.Message; return; } e.XmlDocument = dom; this.MainForm.DomCache.SetObject(strPath, dom); // 保存到缓存 } finally { channel = channelSave; m_nInGetCfgFile--; } }
int DownloadOneFile(string strID, out string strError) { strError = ""; ResPath respath = new ResPath(textBox_recPath.Text); string strResPath = respath.Path + "/object/" + strID; strResPath = strResPath.Replace(":", "/"); string strLocalPath = this.listView_resFiles.GetLocalFileName(strID); SaveFileDialog dlg = new SaveFileDialog(); dlg.Title = "请指定要保存的本地文件名"; dlg.CreatePrompt = false; dlg.FileName = strLocalPath == "" ? strID + ".res" : strLocalPath; dlg.InitialDirectory = Environment.CurrentDirectory; // dlg.Filter = "projects files (outer*.xml)|outer*.xml|All files (*.*)|*.*" ; dlg.RestoreDirectory = true ; if(dlg.ShowDialog() != DialogResult.OK) { strError = "放弃"; return -1; } // 使用Channel RmsChannel channelSave = channel; channel = Channels.GetChannel(respath.Url); Debug.Assert(channel != null, "Channels.GetChannel 异常"); try { stop.OnStop += new StopEventHandler(this.DoStop); stop.Initial("正在下载资源文件 " + strResPath); stop.BeginLoop(); byte [] baOutputTimeStamp = null; EnableControlsInLoading(true); string strMetaData; string strOutputPath = ""; long lRet = channel.GetRes(strResPath, dlg.FileName, stop, out strMetaData, out baOutputTimeStamp, out strOutputPath, out strError); EnableControlsInLoading(false); stop.EndLoop(); stop.OnStop -= new StopEventHandler(this.DoStop); stop.Initial(""); if (lRet == -1) { MessageBox.Show(this, "下载资源文件失败,原因: "+strError); goto ERROR1; } } finally { channel = channelSave; } return 0; ERROR1: return -1; }
// 自动加工数据 public void AutoGenerate() { // 库名部分路径 ResPath respath = new ResPath(textBox_recPath.Text); respath.MakeDbName(); string strError; string strCode; string strRef; // 使用Channel RmsChannel channelSave = channel; channel = Channels.GetChannel(respath.Url); Debug.Assert(channel != null, "Channels.GetChannel 异常"); try { string strCfgPath = respath.Path + "/cfgs/autoGenerate.cs"; string strCfgRefPath = respath.Path + "/cfgs/autoGenerate.cs.ref"; stop.OnStop += new StopEventHandler(this.DoStop); stop.Initial("正在下载文件" + strCfgPath); stop.BeginLoop(); byte[] baTimeStamp = null; string strMetaData; string strOutputPath; long lRet = channel.GetRes( MainForm.cfgCache, strCfgPath, out strCode, out strMetaData, out baTimeStamp, out strOutputPath, out strError); stop.EndLoop(); stop.OnStop -= new StopEventHandler(this.DoStop); stop.Initial(""); if (lRet == -1) { MessageBox.Show(this, strError); return; } stop.OnStop += new StopEventHandler(this.DoStop); stop.Initial("正在下载文件" + strCfgRefPath); stop.BeginLoop(); lRet = channel.GetRes( MainForm.cfgCache, strCfgRefPath, out strRef, out strMetaData, out baTimeStamp, out strOutputPath, out strError); stop.EndLoop(); stop.OnStop -= new StopEventHandler(this.DoStop); stop.Initial(""); if (lRet == -1) { MessageBox.Show(this, strError); return; } } finally { channel = channelSave; } // 执行代码 int nRet = RunScript(strCode, strRef, out strError); if (nRet == -1) { MessageBox.Show(this, strError); return; } }
// 下载资源,保存到备份文件 public static int WriteResToBackupFile( IWin32Window owner, Stream outputfile, string strXmlRecPath, string[] res_ids, RmsChannel channel, DigitalPlatform.Stop stop, out string strError) { strError = ""; long lRet; for (int i = 0; i < res_ids.Length; i++) { Application.DoEvents(); // 出让界面控制权 if (stop.State != 0) { DialogResult result = MessageBox.Show(owner, "确实要中断当前批处理操作?", "dp2batch", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2); if (result == DialogResult.Yes) { strError = "用户中断"; return -1; } else { stop.Continue(); } } string strID = res_ids[i].Trim(); if (strID == "") continue; string strResPath = strXmlRecPath + "/object/" + strID; string strMetaData; if (stop != null) stop.SetMessage("正在下载 " + strResPath); long lResStart = 0; // 写res的头。 // 如果不能预先确知整个res的长度,可以用随便一个lTotalLength值调用本函数, // 但是需要记忆下函数所返回的lStart,最后调用EndWriteResToBackupFile()。 // 如果能预先确知整个res的长度,则最后不必调用EndWriteResToBackupFile() lRet = Backup.BeginWriteResToBackupFile( outputfile, 0, // 未知 out lResStart); byte[] baOutputTimeStamp = null; string strOutputPath; REDO_GETRES: lRet = channel.GetRes(strResPath, (Stream)null, // 故意不获取资源体 stop, "metadata,timestamp,outputpath", null, out strMetaData, // 但是要获得metadata out baOutputTimeStamp, out strOutputPath, out strError); if (lRet == -1) { // TODO: 允许重试 DialogResult redo_result = MessageBox.Show(owner, "获取记录 '" + strResPath + "' 时出现错误: " + strError + "\r\n\r\n重试,还是中断当前批处理操作?\r\n(Retry 重试;Cancel 中断批处理)", "dp2batch", MessageBoxButtons.RetryCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1); if (redo_result == DialogResult.Cancel) return -1; goto REDO_GETRES; } byte[] timestamp = baOutputTimeStamp; ResPath respath = new ResPath(); respath.Url = channel.Url; respath.Path = strOutputPath; // strResPath; // strMetaData还要加入资源id? ExportUtil.ChangeMetaData(ref strMetaData, strID, null, null, null, respath.FullPath, ByteArray.GetHexTimeStampString(baOutputTimeStamp)); lRet = Backup.WriteResMetadataToBackupFile(outputfile, strMetaData); if (lRet == -1) return -1; long lBodyStart = 0; // 写res body的头。 // 如果不能预先确知body的长度,可以用随便一个lBodyLength值调用本函数, // 但是需要记忆下函数所返回的lBodyStart,最后调用EndWriteResBodyToBackupFile()。 // 如果能预先确知body的长度,则最后不必调用EndWriteResBodyToBackupFile() lRet = Backup.BeginWriteResBodyToBackupFile( outputfile, 0, // 未知 out lBodyStart); if (lRet == -1) return -1; if (stop != null) stop.SetMessage("正在下载 " + strResPath + " 的数据体"); REDO_GETRES_1: lRet = channel.GetRes(strResPath, outputfile, stop, "content,data,timestamp", //"content,data,timestamp" timestamp, out strMetaData, out baOutputTimeStamp, out strOutputPath, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.EmptyRecord) { // 空记录 } else { // TODO: 允许重试 DialogResult redo_result = MessageBox.Show(owner, "获取记录 '" + strResPath + "' 时出现错误: " + strError + "\r\n\r\n重试,还是中断当前批处理操作?\r\n(Retry 重试;Cancel 中断批处理)", "dp2batch", MessageBoxButtons.RetryCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1); if (redo_result == DialogResult.Cancel) return -1; goto REDO_GETRES_1; } } long lBodyLength = outputfile.Position - lBodyStart - 8; // res body收尾 lRet = Backup.EndWriteResBodyToBackupFile( outputfile, lBodyLength, lBodyStart); if (lRet == -1) return -1; long lTotalLength = outputfile.Position - lResStart - 8; lRet = Backup.EndWriteResToBackupFile( outputfile, lTotalLength, lResStart); if (lRet == -1) return -1; } /* if (stop != null) stop.SetMessage("保存资源到备份文件全部完成"); */ return 0; }
// 校验起止号 // return: // 0 不存在记录 // 1 存在记录 int VerifyRange(RmsChannel channel, string strDbName, out string strError) { bool bStartNotFound = false; bool bEndNotFound = false; strError = ""; // 如果edit中为空,则假定为“全部范围” if (textBox_startNo.Text == "") textBox_startNo.Text = "1"; if (textBox_endNo.Text == "") textBox_endNo.Text = "9999999999"; bool bAsc = true; Int64 nStart = 0; Int64 nEnd = 9999999999; try { nStart = Convert.ToInt64(textBox_startNo.Text); } catch { } try { nEnd = Convert.ToInt64(textBox_endNo.Text); } catch { } if (nStart > nEnd) bAsc = false; else bAsc = true; string strPath = strDbName + "/" + textBox_startNo.Text; string strStyle = "outputpath"; if (bAsc == true) strStyle += ",next,myself"; else strStyle += ",prev,myself"; string strResult; string strMetaData; byte [] baOutputTimeStamp; string strOutputPath; string strError0 = ""; string strStartID = ""; string strEndID = ""; // 获得资源 // return: // -1 出错。具体出错原因在this.ErrorCode中。this.ErrorInfo中有出错信息。 // 0 成功 long lRet = channel.GetRes(strPath, strStyle, out strResult, out strMetaData, out baOutputTimeStamp, out strOutputPath, out strError0); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) { strStartID = textBox_startNo.Text; bStartNotFound = true; } else strError += "校验startno时出错: " + strError0 + " "; } else { // 取得返回的id strStartID = ResPath.GetRecordId(strOutputPath); } if (strStartID == "") { strError = "strStartID为空..."; return -1; } strPath = strDbName + "/" + textBox_endNo.Text; strStyle = "outputpath"; if (bAsc == true) strStyle += ",prev,myself"; else strStyle += ",next,myself"; // 获得资源 // return: // -1 出错。具体出错原因在this.ErrorCode中。this.ErrorInfo中有出错信息。 // 0 成功 lRet = channel.GetRes(strPath, strStyle, out strResult, out strMetaData, out baOutputTimeStamp, out strOutputPath, out strError0); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) { strEndID = textBox_endNo.Text; bEndNotFound = true; } else strError += "校验endno时出错: " + strError0 + " "; } else { // 取得返回的id strEndID = ResPath.GetRecordId(strOutputPath); } if (strEndID == "") { strError = "strEndID为空..."; return -1; } /// bool bSkip = false; Int64 nTemp = 0; try { nTemp = Convert.ToInt64(strStartID); } catch { strError = "strStartID值 '" + strStartID + "' 不是数字..."; return -1; } if (bAsc == true) { if (nTemp > nEnd) { bSkip = true; } } else { if (nTemp < nEnd) { bSkip = true; } } if (bSkip == false) { textBox_startNo.Text = strStartID; } /// bSkip = false; try { nTemp = Convert.ToInt64(strEndID); } catch { strError = "strEndID值 '" + strEndID + "' 不是数字..."; return -1; } if (bAsc == true) { if (nTemp < nStart) { bSkip = true; } } else { if (nTemp > nStart) { bSkip = true; } } if (bSkip == false) { textBox_endNo.Text = strEndID; } if (bStartNotFound == true && bEndNotFound == true) return 0; return 1; }
void DoExportXmlFile(string strOutputFileName) { string strError = ""; FileStream outputfile = null; XmlTextWriter writer = null; if (textBox_dbPath.Text == "") { MessageBox.Show(this, "尚未选择源库..."); return; } ResPath respath = new ResPath(textBox_dbPath.Text); channel = this.Channels.GetChannel(respath.Url); string strDbName = respath.Path; if (strOutputFileName != null && strOutputFileName != "") { // 探测文件是否存在 FileInfo fi = new FileInfo(strOutputFileName); if (fi.Exists == true && fi.Length > 0) { DialogResult result = MessageBox.Show(this, "文件 '" + strOutputFileName + "' 已存在,是否覆盖?\r\n\r\n--------------------\r\n注:(是)覆盖 (否)中断处理", "dp2batch", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2); if (result != DialogResult.Yes) { strError = "放弃处理..."; goto ERROR1; } } // 打开文件 outputfile = File.Create( strOutputFileName); writer = new XmlTextWriter(outputfile, Encoding.UTF8); writer.Formatting = Formatting.Indented; writer.Indentation = 4; } try { Int64 nStart; Int64 nEnd; Int64 nCur; bool bAsc = GetDirection(out nStart, out nEnd); // 设置进度条范围 Int64 nMax = nEnd - nStart; if (nMax < 0) nMax *= -1; nMax ++; ProgressRatio = nMax / 10000; if (ProgressRatio < 1.0) ProgressRatio = 1.0; progressBar_main.Minimum = 0; progressBar_main.Maximum = (int)(nMax/ProgressRatio); progressBar_main.Value = 0; bool bFirst = true; // 是否为第一次取记录 string strID = this.textBox_startNo.Text; stop.Initial(new Delegate_doStop(this.DoStop), "正在导出数据"); stop.BeginLoop(); EnableControls(false); if (writer != null) { writer.WriteStartDocument(); writer.WriteStartElement("dprms","collection",DpNs.dprms); //writer.WriteStartElement("collection"); //writer.WriteAttributeString("xmlns:marc", // "http://www.loc.gov/MARC21/slim"); } // 循环 for(;;) { Application.DoEvents(); // 出让界面控制权 if (stop.State != 0) { strError = "用户中断"; goto ERROR1; } string strStyle = ""; if (outputfile != null) strStyle = "data,content,timestamp,outputpath"; else strStyle = "timestamp,outputpath"; // 优化 if (bFirst == true) strStyle += ""; else { if (bAsc == true) strStyle += ",next"; else strStyle += ",prev"; } string strPath = strDbName + "/" + strID; string strXmlBody = ""; string strMetaData = ""; byte[] baOutputTimeStamp = null; string strOutputPath = ""; bool bFoundRecord = false; // 获得资源 // return: // -1 出错。具体出错原因在this.ErrorCode中。this.ErrorInfo中有出错信息。 // 0 成功 long lRet = channel.GetRes(strPath, strStyle, out strXmlBody, out strMetaData, out baOutputTimeStamp, out strOutputPath, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) { if (checkBox_forceLoop.Checked == true && bFirst == true) { AutoCloseMessageBox.Show(this, "记录 " + strID + " 不存在。\r\n\r\n按 确认 继续。"); bFirst = false; goto CONTINUE; } else { if (bFirst == true) { strError = "记录 " + strID + " 不存在。处理结束。"; } else { if (bAsc == true) strError = "记录 " + strID + " 是最末一条记录。处理结束。"; else strError = "记录 " + strID + " 是最前一条记录。处理结束。"; } } } else if (channel.ErrorCode == ChannelErrorCode.EmptyRecord) { bFirst = false; bFoundRecord = false; // 把id解析出来 strID = ResPath.GetRecordId(strOutputPath); goto CONTINUE; } goto ERROR1; } bFirst = false; bFoundRecord = true; // 把id解析出来 strID = ResPath.GetRecordId(strOutputPath); CONTINUE: stop.SetMessage(strID); // 是否超过循环范围 try { nCur = Convert.ToInt64(strID); } catch { // ??? nCur = 0; } if (bAsc == true && nCur > nEnd) break; if (bAsc == false && nCur < nEnd) break; if (bFoundRecord == true && writer != null) { // 写磁盘 XmlDocument dom = new XmlDocument(); try { dom.LoadXml(strXmlBody); ResPath respathtemp = new ResPath(); respathtemp.Url = channel.Url; respathtemp.Path = strOutputPath; // DomUtil.SetAttr(dom.DocumentElement, "xmlns:dprms", DpNs.dprms); // 给根元素设置几个参数 DomUtil.SetAttr(dom.DocumentElement, "path", DpNs.dprms, respathtemp.FullPath); DomUtil.SetAttr(dom.DocumentElement, "timestamp", DpNs.dprms, ByteArray.GetHexTimeStampString(baOutputTimeStamp)); // DomUtil.SetAttr(dom.DocumentElement, "xmlns:marc", null); dom.DocumentElement.WriteTo(writer); } catch (Exception ex) { strError = ex.Message; // 询问是否继续 goto ERROR1; } /* if (nRet == -1) { // 询问是否继续 goto ERROR1; } */ } // 删除 if (checkBox_export_delete.Checked == true) { byte [] baOutputTimeStamp1 = null; strPath = strOutputPath; // 得到实际的路径 lRet = channel.DoDeleteRecord( strPath, baOutputTimeStamp, out baOutputTimeStamp1, out strError); if (lRet == -1) { // 询问是否继续 goto ERROR1; } } if (bAsc == true) { progressBar_main.Value = (int)((nCur-nStart + 1)/ProgressRatio); } else { // ? progressBar_main.Value = (int)((nStart-nCur + 1)/ProgressRatio); } // 对已经作过的进行判断 if (bAsc == true && nCur >= nEnd) break; if (bAsc == false && nCur <= nEnd) break; } stop.EndLoop(); stop.Initial(null, ""); EnableControls(true); } finally { if (writer != null) { writer.WriteEndElement(); writer.WriteEndDocument(); writer.Close(); writer = null; } if (outputfile != null) { outputfile.Close(); outputfile = null; } } END1: channel = null; if (checkBox_export_delete.Checked == true) MessageBox.Show(this, "数据导出和删除完成。"); else MessageBox.Show(this, "数据导出完成。"); return; ERROR1: stop.EndLoop(); stop.Initial(null, ""); EnableControls(true); channel = null; MessageBox.Show(this, strError); return; }
// return: // -1 error // 0 正常结束 // 1 希望跳过后来的OnEnd() int DoExportFile( string[] dbpaths, string strOutputFileName, ExportFileType exportType, Encoding targetEncoding, out string strError) { strError = ""; int nRet = 0; string strDeleteStyle = ""; if (this.checkBox_export_fastMode.Checked == true) strDeleteStyle = "fastmode"; string strInfo = ""; // 汇总信息,在完成后显示 FileStream outputfile = null; // Backup和Xml格式输出都需要这个 XmlTextWriter writer = null; // Xml格式输出时需要这个 bool bAppend = true; Debug.Assert(dbpaths != null, ""); if (dbpaths.Length == 0) { strError = "尚未指定源库..."; goto ERROR1; } if (String.IsNullOrEmpty(strOutputFileName) == false) { // 探测输出文件是否已经存在 FileInfo fi = new FileInfo(strOutputFileName); bAppend = true; if (fi.Exists == true && fi.Length > 0) { if (exportType == ExportFileType.BackupFile || exportType == ExportFileType.ISO2709File) { DialogResult result = MessageBox.Show(this, "文件 '" + strOutputFileName + "' 已存在,是否追加?\r\n\r\n--------------------\r\n注:(是)追加 (否)覆盖 (取消)中断处理", "dp2batch", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1); if (result == DialogResult.Yes) { bAppend = true; } if (result == DialogResult.No) { bAppend = false; } if (result == DialogResult.Cancel) { strError = "放弃处理..."; goto ERROR1; } } else if (exportType == ExportFileType.XmlFile) { DialogResult result = MessageBox.Show(this, "文件 '" + strOutputFileName + "' 已存在,是否覆盖?\r\n\r\n--------------------\r\n注:(是)覆盖 (否)中断处理", "dp2batch", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2); if (result != DialogResult.Yes) { strError = "放弃处理..."; goto ERROR1; } } } // 打开文件 if (exportType == ExportFileType.BackupFile || exportType == ExportFileType.ISO2709File) { outputfile = File.Open( strOutputFileName, FileMode.OpenOrCreate, // 原来是Open,后来修改为OpenOrCreate。这样对临时文件被系统管理员手动意外删除(但是xml文件中仍然记载了任务)的情况能够适应。否则会抛出FileNotFoundException异常 FileAccess.Write, FileShare.ReadWrite); } else if (exportType == ExportFileType.XmlFile) { outputfile = File.Create( strOutputFileName); writer = new XmlTextWriter(outputfile, Encoding.UTF8); writer.Formatting = Formatting.Indented; writer.Indentation = 4; } } if ((exportType == ExportFileType.BackupFile || exportType == ExportFileType.ISO2709File) && outputfile != null) { if (bAppend == true) outputfile.Seek(0, SeekOrigin.End); // 具有追加的能力 else outputfile.SetLength(0); } WriteLog("开始输出"); try { // string[] dbpaths = textBox_dbPath.Text.Split(new char[] { ';' }); for (int f = 0; f < dbpaths.Length; f++) { string strOneDbPath = dbpaths[f]; ResPath respath = new ResPath(strOneDbPath); channel = this.Channels.GetChannel(respath.Url); string strDbName = respath.Path; if (String.IsNullOrEmpty(strInfo) == false) strInfo += "\r\n"; strInfo += "" + strDbName; // 实际处理的首尾号 string strRealStartNo = ""; string strRealEndNo = ""; /* DialogResult result; if (checkBox_export_delete.Checked == true) { result = MessageBox.Show(this, "确实要删除 '" + respath.Path + "' 内指定范围的记录?\r\n\r\n---------\r\n(是)删除 (否)放弃批处理", "dp2batch", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2); if (result != DialogResult.Yes) continue; } * * */ //channel = this.Channels.GetChannel(respath.Url); //string strDbName = respath.Path; // 如果为多库输出 if (dbpaths.Length > 0) { // 如果为全选 if (this.radioButton_all.Checked == true) { // 恢复为最大范围 this.textBox_startNo.Text = "1"; this.textBox_endNo.Text = "9999999999"; } // 校验起止号 if (checkBox_verifyNumber.Checked == true) { nRet = VerifyRange(channel, strDbName, out strError); if (nRet == -1) MessageBox.Show(this, strError); if (nRet == 0) { // 库中无记录 AutoCloseMessageBox.Show(this, "数据库 " + strDbName + " 中无记录。"); strInfo += "(无记录)"; WriteLog("发现数据库 " + strDbName + " 中无记录"); continue; } } else { if (this.textBox_startNo.Text == "") { strError = "尚未指定起始号"; goto ERROR1; } if (this.textBox_endNo.Text == "") { strError = "尚未指定结束号"; goto ERROR1; } } } string strOutputStartNo = ""; string strOutputEndNo = ""; // 虽然界面不让校验起止号,但是也要校验,为了设置好进度条 if (checkBox_verifyNumber.Checked == false) { // 校验起止号 // return: // 0 不存在记录 // 1 存在记录 nRet = VerifyRange(channel, strDbName, this.textBox_startNo.Text, this.textBox_endNo.Text, out strOutputStartNo, out strOutputEndNo, out strError); } //try //{ Int64 nStart = 0; Int64 nEnd = 0; Int64 nCur = 0; bool bAsc = true; bAsc = GetDirection( this.textBox_startNo.Text, this.textBox_endNo.Text, out nStart, out nEnd); // 探测到的号码 long nOutputEnd = 0; long nOutputStart = 0; if (checkBox_verifyNumber.Checked == false) { GetDirection( strOutputStartNo, strOutputEndNo, out nOutputStart, out nOutputEnd); } // 设置进度条范围 if (checkBox_verifyNumber.Checked == true) { Int64 nMax = nEnd - nStart; if (nMax < 0) nMax *= -1; nMax++; /* ProgressRatio = nMax / 10000; if (ProgressRatio < 1.0) ProgressRatio = 1.0; progressBar_main.Minimum = 0; progressBar_main.Maximum = (int)(nMax / ProgressRatio); progressBar_main.Value = 0; * */ stop.SetProgressRange(0, nMax); } else { Int64 nMax = nOutputEnd - nOutputStart; if (nMax < 0) nMax *= -1; nMax++; stop.SetProgressRange(0, nMax); } bool bFirst = true; // 是否为第一次取记录 string strID = this.textBox_startNo.Text; stop.OnStop += new StopEventHandler(this.DoStop); stop.Initial("正在导出数据"); stop.BeginLoop(); EnableControls(false); if (exportType == ExportFileType.XmlFile && writer != null) { writer.WriteStartDocument(); writer.WriteStartElement("dprms", "collection", DpNs.dprms); //writer.WriteStartElement("collection"); //writer.WriteAttributeString("xmlns:marc", // "http://www.loc.gov/MARC21/slim"); } WriteLog("开始输出数据库 '" + strDbName + "' 内的数据记录"); m_nRecordCount = 0; // 循环 for (; ; ) { Application.DoEvents(); // 出让界面控制权 if (stop.State != 0) { WriteLog("打开对话框 '确实要中断当前批处理操作?'"); DialogResult result = MessageBox.Show(this, "确实要中断当前批处理操作?", "dp2batch", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2); WriteLog("关闭对话框 '确实要中断当前批处理操作?'"); if (result == DialogResult.Yes) { strError = "用户中断"; goto ERROR1; } else { stop.Continue(); } } string strDirectionComment = ""; string strStyle = ""; if (outputfile != null) strStyle = "data,content,timestamp,outputpath"; else strStyle = "timestamp,outputpath"; // 优化 if (bFirst == true) { strStyle += ""; } else { if (bAsc == true) { strStyle += ",next"; strDirectionComment = "的后一条记录"; } else { strStyle += ",prev"; strDirectionComment = "的前一条记录"; } } string strPath = strDbName + "/" + strID; string strXmlBody = ""; string strMetaData = ""; byte[] baOutputTimeStamp = null; string strOutputPath = ""; bool bFoundRecord = false; bool bNeedRetry = true; REDO_GETRES: // 获得资源 // return: // -1 出错。具体出错原因在this.ErrorCode中。this.ErrorInfo中有出错信息。 // 0 成功 long lRet = channel.GetRes(strPath, strStyle, out strXmlBody, out strMetaData, out baOutputTimeStamp, out strOutputPath, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) { if (bFirst == true) { if (checkBox_forceLoop.Checked == true) { string strText = "记录 " + strID + strDirectionComment + " 不存在。\r\n\r\n按 确认 继续。"; WriteLog("打开对话框 '" + strText.Replace("\r\n", "\\n") + "'"); AutoCloseMessageBox.Show(this, strText); WriteLog("关闭对话框 '" + strText.Replace("\r\n", "\\n") + "'"); bFirst = false; goto CONTINUE; } else { // 如果不要强制循环,此时也不能结束,否则会让用户以为数据库里面根本没有数据 string strText = "您为数据库 " + strDbName + " 指定的首记录 " + strID + strDirectionComment + " 不存在。\r\n\r\n(注:为避免出现此提示,可在操作前勾选“校准首尾ID”)\r\n\r\n按 确认 继续向后找..."; WriteLog("打开对话框 '" + strText.Replace("\r\n", "\\n") + "'"); AutoCloseMessageBox.Show(this, strText); WriteLog("关闭对话框 '" + strText.Replace("\r\n", "\\n") + "'"); bFirst = false; goto CONTINUE; } } else { Debug.Assert(bFirst == false, ""); if (bFirst == true) { strError = "记录 " + strID + strDirectionComment + " 不存在。处理结束。"; } else { if (bAsc == true) strError = "记录 " + strID + " 是最末一条记录。处理结束。"; else strError = "记录 " + strID + " 是最前一条记录。处理结束。"; } if (dbpaths.Length > 1) break; // 多库情况,继续其它库循环 else { bNeedRetry = false; // 单库情况,也没有必要出现重试对话框 WriteLog("打开对话框 '" + strError.Replace("\r\n", "\\n") + "'"); MessageBox.Show(this, strError); WriteLog("关闭对话框 '" + strError.Replace("\r\n", "\\n") + "'"); break; } } } else if (channel.ErrorCode == ChannelErrorCode.EmptyRecord) { bFirst = false; bFoundRecord = false; // 把id解析出来 strID = ResPath.GetRecordId(strOutputPath); goto CONTINUE; } // 允许重试 if (bNeedRetry == true) { string strText = "获取记录 '" + strPath + "' (style='" + strStyle + "')时出现错误: " + strError + "\r\n\r\n重试,还是中断当前批处理操作?\r\n(Retry 重试;Cancel 中断批处理)"; WriteLog("打开对话框 '" + strText.Replace("\r\n", "\\n") + "'"); DialogResult redo_result = MessageBox.Show(this, strText, "dp2batch", MessageBoxButtons.RetryCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1); WriteLog("关闭对话框 '" + strText.Replace("\r\n", "\\n") + "'"); if (redo_result == DialogResult.Cancel) goto ERROR1; goto REDO_GETRES; } else { goto ERROR1; } } // 2008/11/9 if (String.IsNullOrEmpty(strXmlBody) == true) { bFirst = false; bFoundRecord = false; // 把id解析出来 strID = ResPath.GetRecordId(strOutputPath); goto CONTINUE; } bFirst = false; bFoundRecord = true; // 把id解析出来 strID = ResPath.GetRecordId(strOutputPath); stop.SetMessage("已导出记录 " + strOutputPath + " " + m_nRecordCount.ToString()); if (String.IsNullOrEmpty(strRealStartNo) == true) { strRealStartNo = strID; } strRealEndNo = strID; CONTINUE: // 是否超过循环范围 try { nCur = Convert.ToInt64(strID); } catch { // ??? nCur = 0; } if (checkBox_verifyNumber.Checked == false) { // 如果当前记录号码突破预计的头部和尾部 if (nCur > nOutputEnd || nCur < nOutputStart) { if (nCur > nOutputEnd) nOutputEnd = nCur; if (nCur < nOutputStart) nOutputStart = nCur; // 重新计算和设置进度条 long nMax = nOutputEnd - nOutputStart; if (nMax < 0) nMax *= -1; nMax++; stop.SetProgressRange(0, nMax); } } if (bAsc == true && nCur > nEnd) break; if (bAsc == false && nCur < nEnd) break; string strMarc = ""; // 将Xml转换为MARC if (exportType == ExportFileType.ISO2709File && bFoundRecord == true) // 2008/11/13 { nRet = GetMarc(strXmlBody, out strMarc, out strError); if (nRet == -1) { strError = "记录 " + strOutputPath + " 在将XML格式转换为MARC时出错: " + strError; goto ERROR1; } } if (this.MarcFilter != null) { // 触发filter中的Record相关动作 // TODO: 有可能strMarc为空哟,需要测试一下 nRet = MarcFilter.DoRecord( null, strMarc, m_nRecordCount, out strError); if (nRet == -1) goto ERROR1; } // 触发Script的Outputing()代码 if (bFoundRecord == true && this.AssemblyMain != null) { // 这些变量要先初始化,因为filter代码可能用到这些Batch成员. batchObj.XmlRecord = strXmlBody; batchObj.MarcSyntax = this.CurMarcSyntax; batchObj.MarcRecord = strMarc; // MARC记录体 batchObj.MarcRecordChanged = false; // 为本轮Script运行准备初始状态 batchObj.SearchPanel.ServerUrl = channel.Url; batchObj.ServerUrl = channel.Url; batchObj.RecPath = strOutputPath; // 记录路径 batchObj.RecIndex = m_nRecordCount; // 当前记录在一批中的序号 batchObj.TimeStamp = baOutputTimeStamp; BatchEventArgs args = new BatchEventArgs(); batchObj.Outputing(this, args); /* if (args.Continue == ContinueType.SkipMiddle) goto CONTINUEDBS; if (args.Continue == ContinueType.SkipBeginMiddle) goto CONTINUEDBS; */ if (args.Continue == ContinueType.SkipAll) goto CONTINUEDBS; // 观察用于输出的MARC记录是否被改变 if (batchObj.MarcRecordChanged == true) strMarc = batchObj.MarcRecord; // 观察XML记录是否被改变 if (batchObj.XmlRecordChanged == true) strXmlBody = batchObj.XmlRecord; } if (bFoundRecord == true && outputfile != null) { if (exportType == ExportFileType.BackupFile) { // 写磁盘 nRet = WriteRecordToBackupFile( outputfile, strDbName, strID, strMetaData, strXmlBody, baOutputTimeStamp, out strError); if (nRet == -1) { // 询问是否继续 goto ERROR1; } } else if (exportType == ExportFileType.ISO2709File) { // 写磁盘 nRet = WriteRecordToISO2709File( outputfile, strDbName, strID, strMarc, baOutputTimeStamp, targetEncoding, this.OutputCrLf, this.AddG01, this.Remove998, out strError); if (nRet == -1) { // 询问是否继续 goto ERROR1; } } else if (exportType == ExportFileType.XmlFile) { XmlDocument dom = new XmlDocument(); try { dom.LoadXml(strXmlBody); ResPath respathtemp = new ResPath(); respathtemp.Url = channel.Url; respathtemp.Path = strOutputPath; // DomUtil.SetAttr(dom.DocumentElement, "xmlns:dprms", DpNs.dprms); // 给根元素设置几个参数 DomUtil.SetAttr(dom.DocumentElement, "path", DpNs.dprms, respathtemp.FullPath); DomUtil.SetAttr(dom.DocumentElement, "timestamp", DpNs.dprms, ByteArray.GetHexTimeStampString(baOutputTimeStamp)); // DomUtil.SetAttr(dom.DocumentElement, "xmlns:marc", null); dom.DocumentElement.WriteTo(writer); } catch (Exception ex) { strError = ExceptionUtil.GetAutoText(ex); // 询问是否继续 goto ERROR1; } } } // 删除 if (checkBox_export_delete.Checked == true) { byte[] baOutputTimeStamp1 = null; strPath = strOutputPath; // 得到实际的路径 lRet = channel.DoDeleteRes( strPath, baOutputTimeStamp, strDeleteStyle, out baOutputTimeStamp1, out strError); if (lRet == -1) { // 询问是否继续 goto ERROR1; } stop.SetMessage("已删除记录" + strPath + " " + m_nRecordCount.ToString()); } if (bFoundRecord == true) m_nRecordCount++; if (bAsc == true) { //progressBar_main.Value = (int)((nCur - nStart + 1) / ProgressRatio); stop.SetProgressValue(nCur - nStart + 1); } else { // ? // progressBar_main.Value = (int)((nStart - nCur + 1) / ProgressRatio); stop.SetProgressValue(nStart - nCur + 1); } // 对已经作过的进行判断 if (bAsc == true && nCur >= nEnd) break; if (bAsc == false && nCur <= nEnd) break; } // end of for one database stop.EndLoop(); stop.OnStop -= new StopEventHandler(this.DoStop); stop.Initial(""); EnableControls(true); //} CONTINUEDBS: strInfo += " : " + m_nRecordCount.ToString() + "条 (ID " + strRealStartNo + "-" + strRealEndNo + ")"; } // end of dbpaths loop } // end of try finally { if (writer != null) { writer.WriteEndElement(); writer.WriteEndDocument(); writer.Close(); writer = null; } if (outputfile != null) { outputfile.Close(); outputfile = null; } } // END1: channel = null; if (checkBox_export_delete.Checked == true) strError = "数据导出和删除完成。\r\n---\r\n" + strInfo; else strError = "数据导出完成。\r\n---\r\n" + strInfo; WriteLog("结束输出"); return 0; ERROR1: stop.EndLoop(); stop.OnStop -= new StopEventHandler(this.DoStop); stop.Initial(""); EnableControls(true); channel = null; return -1; }
// 获得用户记录 // return: // -1 error // 0 not found // >=1 检索命中的条数 public static int GetUserRecord( RmsChannel channel, string strUserName, out string strRecPath, out string strXml, out byte[] baTimeStamp, out string strError) { strError = ""; strXml = ""; strRecPath = ""; baTimeStamp = null; if (strUserName == "") { strError = "用户名为空"; return -1; } string strQueryXml = "<target list='" + Defs.DefaultUserDb.Name + ":" + Defs.DefaultUserDb.SearchPath.UserName + "'><item><word>" + strUserName + "</word><match>exact</match><relation>=</relation><dataType>string</dataType><maxCount>10</maxCount></item><lang>chi</lang></target>"; long nRet = channel.DoSearch(strQueryXml, "default", "", // strOutputStyle out strError); if (nRet == -1) { strError = "检索帐户库时出错: " + strError; return -1; } if (nRet == 0) return 0; // not found long nSearchCount = nRet; List<string> aPath = null; nRet = channel.DoGetSearchResult( "default", 1, "zh", null, // stop, out aPath, out strError); if (nRet == -1) { strError = "检索注册用户库获取检索结果时出错: " + strError; return -1; } if (aPath.Count == 0) { strError = "检索注册用户库获取的检索结果为空"; return -1; } // strRecID = ResPath.GetRecordId((string)aPath[0]); strRecPath = (string)aPath[0]; string strStyle = "content,data,timestamp,withresmetadata"; string strMetaData; string strOutputPath; nRet = channel.GetRes((string)aPath[0], strStyle, out strXml, out strMetaData, out baTimeStamp, out strOutputPath, out strError); if (nRet == -1) { strError = "获取注册用户库记录体时出错: " + strError; return -1; } return (int)nSearchCount; }
// 将内核网络配置文件映射到本地 // return: // -1 出错 // 0 不存在 // 1 找到 public int MapFileToLocal( // RmsChannelCollection Channels, RmsChannel channel, string strPath, out string strLocalPath, out string strError) { strLocalPath = ""; strError = ""; strLocalPath = this.RootDir + "/" + strPath; // 确保目录存在 PathUtil.CreateDirIfNeed(Path.GetDirectoryName(strLocalPath)); this.locks.LockForRead(strLocalPath); try { // 看看物理文件是否存在 FileInfo fi = new FileInfo(strLocalPath); if (fi.Exists == true) { if (fi.Length == 0) return 0; // not exist return 1; } } finally { this.locks.UnlockForRead(strLocalPath); } // 确保目录存在 PathUtil.CreateDirIfNeed(Path.GetDirectoryName(strLocalPath)); this.locks.LockForWrite(strLocalPath); try { #if NO RmsChannel channel = Channels.GetChannel(this.ServerUrl); if (channel == null) { strError = "GetChannel error"; return -1; } #endif string strMetaData = ""; byte[] baOutputTimestamp = null; string strOutputPath = ""; long lRet = channel.GetRes(strPath, strLocalPath, (Stop)null, out strMetaData, out baOutputTimestamp, out strOutputPath, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) { // 为了避免以后再次从网络获取耗费时间, 需要在本地写一个0字节的文件 FileStream fs = File.Create(strLocalPath); fs.Close(); return 0; } return -1; } return 1; } finally { this.locks.UnlockForWrite(strLocalPath); } }
// 移动或者复制书目记录 // strExistingXml和请求中传来的old xml的时间戳比较,在本函数外、调用前进行 // parameters: // strAction 动作。为"onlycopybiblio" "onlymovebiblio"之一。增加 copy / move // strNewBiblio 需要在目标记录中更新的内容。如果 == null,表示不特意更新 // strMergeStyle 如何合并两条记录的元数据部分? reserve_source / reserve_target。 空表示 reserve_source int DoBiblioOperMove( string strAction, SessionInfo sessioninfo, RmsChannel channel, string strOldRecPath, string strExistingSourceXml, // byte[] baExistingSourceTimestamp, // 请求中提交过来的时间戳 string strNewRecPath, string strNewBiblio, // 已经经过Merge预处理的新记录XML string strMergeStyle, out string strOutputTargetXml, out byte[] baOutputTimestamp, out string strOutputRecPath, out string strError) { strError = ""; long lRet = 0; baOutputTimestamp = null; strOutputRecPath = ""; strOutputTargetXml = ""; // 最后保存成功的记录 // 检查路径 if (strOldRecPath == strNewRecPath) { strError = "当action为\"" + strAction + "\"时,strNewRecordPath路径 '" + strNewRecPath + "' 和strOldRecPath '" + strOldRecPath + "' 必须不相同"; goto ERROR1; } if (String.IsNullOrEmpty(strNewRecPath) == true) { strError = "DoBiblioOperMove() strNewRecPath参数值不能为空"; goto ERROR1; } // 检查即将覆盖的目标位置是不是有记录,如果有,则不允许进行move操作。 bool bAppendStyle = false; // 目标路径是否为追加形态? string strTargetRecId = ResPath.GetRecordId(strNewRecPath); string strExistTargetXml = ""; if (strTargetRecId == "?" || String.IsNullOrEmpty(strTargetRecId) == true) { // 2009/11/1 if (String.IsNullOrEmpty(strTargetRecId) == true) strNewRecPath += "/?"; bAppendStyle = true; } string strOutputPath = ""; string strMetaData = ""; if (bAppendStyle == false) { byte[] exist_target_timestamp = null; // 获取覆盖目标位置的现有记录 lRet = channel.GetRes(strNewRecPath, out strExistTargetXml, out strMetaData, out exist_target_timestamp, out strOutputPath, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) { // 如果记录不存在, 说明不会造成覆盖态势 /* strExistSourceXml = "<root />"; exist_source_timestamp = null; strOutputPath = info.NewRecPath; * */ } else { strError = "移动操作发生错误, 在读入即将覆盖的目标位置 '" + strNewRecPath + "' 原有记录阶段:" + strError; goto ERROR1; } } else { #if NO // 如果记录存在,则目前不允许这样的操作 strError = "移动(move)操作被拒绝。因为在即将覆盖的目标位置 '" + strNewRecPath + "' 已经存在书目记录。请先删除(delete)这条记录,再进行移动(move)操作"; goto ERROR1; #endif } } /* // 把两个记录装入DOM XmlDocument domSourceExist = new XmlDocument(); XmlDocument domNew = new XmlDocument(); try { domSourceExist.LoadXml(strExistingSourceXml); } catch (Exception ex) { strError = "strExistXml装载进入DOM时发生错误: " + ex.Message; goto ERROR1; } try { domNew.LoadXml(strNewBiblio); } catch (Exception ex) { strError = "strNewBiblio装载进入DOM时发生错误: " + ex.Message; goto ERROR1; } * */ // 只有order权限的情况 if (StringUtil.IsInList("setbiblioinfo", sessioninfo.RightsOrigin) == false && StringUtil.IsInList("order", sessioninfo.RightsOrigin) == true) { if (strAction == "onlymovebiblio" || strAction == "move") { string strSourceDbName = ResPath.GetDbName(strOldRecPath); // 源头书目库为 非工作库 情况 if (IsOrderWorkBiblioDb(strSourceDbName) == false) { // 非工作库不能删除记录 if (IsOrderWorkBiblioDb(strSourceDbName) == false) { // 非工作库。要求原来记录不存在 strError = "当前帐户只有order权限而没有setbiblioinfo权限,不能用" + strAction + "功能删除源书目记录 '" + strOldRecPath + "'"; goto ERROR1; } } } } // 移动记录 byte[] output_timestamp = null; string strIdChangeList = ""; // TODO: Copy后还要写一次?因为Copy并不写入新记录。 // 其实Copy的意义在于带走资源。否则还不如用Save+Delete lRet = channel.DoCopyRecord(strOldRecPath, strNewRecPath, strAction == "onlymovebiblio" || strAction == "move" ? true : false, // bDeleteSourceRecord strMergeStyle, out strIdChangeList, out output_timestamp, out strOutputRecPath, out strError); if (lRet == -1) { strError = "DoCopyRecord() error :" + strError; goto ERROR1; } // TODO: 兑现对 856 字段的合并,和来自源的 856 字段的 $u 修改 if (String.IsNullOrEmpty(strNewBiblio) == false) { this.BiblioLocks.LockForWrite(strOutputRecPath); try { // TODO: 如果新的、已存在的xml没有不同,或者新的xml为空,则这步保存可以省略 string strOutputBiblioRecPath = ""; lRet = channel.DoSaveTextRes(strOutputRecPath, strNewBiblio, false, "content", // ,ignorechecktimestamp output_timestamp, out baOutputTimestamp, out strOutputBiblioRecPath, out strError); if (lRet == -1) goto ERROR1; } finally { this.BiblioLocks.UnlockForWrite(strOutputRecPath); } } { // TODO: 是否和前面一起锁定? byte[] exist_target_timestamp = null; // 获取最后的记录 lRet = channel.GetRes(strOutputRecPath, out strOutputTargetXml, out strMetaData, out exist_target_timestamp, out strOutputPath, out strError); } return 0; ERROR1: return -1; }
// 保存记录到模板配置文件 // parameters: public void SaveToTemplate() { // 选择目标数据库 OpenResDlg dlg = new OpenResDlg(); dlg.Font = GuiUtil.GetDefaultFont(); dlg.Text = "请选择目标数据库"; dlg.EnabledIndices = new int[] { ResTree.RESTYPE_DB }; dlg.ap = this.MainForm.AppInfo; dlg.ApCfgTitle = "detailform_openresdlg"; dlg.Path = textBox_recPath.Text; dlg.Initial( MainForm.Servers, this.Channels); // dlg.StartPosition = FormStartPosition.CenterScreen; dlg.ShowDialog(this); if (dlg.DialogResult != DialogResult.OK) return; // 下载模板配置文件 ResPath respath = new ResPath(dlg.Path); string strError; string strContent; byte[] baTimeStamp = null; string strMetaData; string strOutputPath; string strCfgFilePath = respath.Path + "/cfgs/template"; long lRet = 0; // 使用Channel RmsChannel channelSave = channel; channel = Channels.GetChannel(respath.Url); Debug.Assert(channel != null, "Channels.GetChannel 异常"); try { stop.OnStop += new StopEventHandler(this.DoStop); stop.Initial("正在下载文件" + strCfgFilePath); stop.BeginLoop(); lRet = channel.GetRes( MainForm.cfgCache, strCfgFilePath, out strContent, out strMetaData, out baTimeStamp, out strOutputPath, out strError); stop.EndLoop(); stop.OnStop -= new StopEventHandler(this.DoStop); stop.Initial(""); if (lRet == -1) { this.TimeStamp = null; MessageBox.Show(this, strError); return; } } finally { channel = channelSave; } SelectRecordTemplateDlg tempdlg = new SelectRecordTemplateDlg(); tempdlg.Font = GuiUtil.GetDefaultFont(); int nRet = tempdlg.Initial(strContent, out strError); if (nRet == -1) goto ERROR1; tempdlg.Text = "请选择要修改的模板记录"; tempdlg.CheckNameExist = false; // 按OK按钮时不警告"名字不存在",这样允许新建一个模板 tempdlg.ap = this.MainForm.AppInfo; tempdlg.ApCfgTitle = "detailform_selecttemplatedlg"; tempdlg.ShowDialog(this); if (tempdlg.DialogResult != DialogResult.OK) return; string strXmlBody = ""; bool bHasUploadedFile = false; nRet = GetXmlRecord(out strXmlBody, out bHasUploadedFile, out strError); if (nRet == -1) goto ERROR1; // 修改配置文件内容 if (tempdlg.textBox_name.Text != "") { // 替换或者追加一个记录 nRet = tempdlg.ReplaceRecord(tempdlg.textBox_name.Text, strXmlBody, out strError); if (nRet == -1) { goto ERROR1; } } if (tempdlg.Changed == false) // 没有必要保存回去 return; string strOutputXml = tempdlg.OutputXml; // 使用Channel channelSave = channel; // 重新获得一次channel, 是因为前面GetXmlRecord()函数有可能摧毁这个变量 channel = Channels.GetChannel(respath.Url); Debug.Assert(channel != null, "Channels.GetChannel 异常"); try { // 存回配置文件 stop.OnStop += new StopEventHandler(this.DoStop); stop.Initial("正在保存配置文件 " + strCfgFilePath); stop.BeginLoop(); byte [] baOutputTimeStamp = null; // string strOutputPath = ""; EnableControlsInLoading(true); lRet = channel.DoSaveTextRes(strCfgFilePath, strOutputXml, true, // bInlucdePreamble "", // style baTimeStamp, out baOutputTimeStamp, out strOutputPath, out strError); EnableControlsInLoading(false); stop.EndLoop(); stop.OnStop -= new StopEventHandler(this.DoStop); stop.Initial(""); if (lRet == -1) { strError = "保存配置文件"+ strCfgFilePath +"失败,原因: "+strError; goto ERROR1; } } finally { channel = channelSave; } MessageBox.Show(this, "修改模板配置文件成功。"); return; ERROR1: MessageBox.Show(this, strError); }
// 执行API中的"change"操作 // 1) 操作成功后, NewRecord中有实际保存的新记录,NewTimeStamp为新的时间戳 // 2) 如果返回TimeStampMismatch错,则OldRecord中有库中发生变化后的“原记录”,OldTimeStamp是其时间戳 // return: // -1 出错 // 0 成功 public int DoOperChange( bool bForce, // string strUserID, SessionInfo sessioninfo, RmsChannel channel, EntityInfo info, ref XmlDocument domOperLog, ref List<EntityInfo> ErrorInfos) { int nRedoCount = 0; EntityInfo error = null; bool bExist = true; // info.RecPath所指的记录是否存在? int nRet = 0; long lRet = 0; string strError = ""; // 检查一下路径 if (String.IsNullOrEmpty(info.NewRecPath) == true) { strError = "info.NewRecPath中的路径不能为空"; goto ERROR1; } string strTargetRecId = ResPath.GetRecordId(info.NewRecPath); if (strTargetRecId == "?") { strError = "info.NewRecPath路径 '" + strTargetRecId + "' 中记录ID部分不能为'?'"; goto ERROR1; } if (String.IsNullOrEmpty(strTargetRecId) == true) { strError = "info.NewRecPath路径 '" + strTargetRecId + "' 中记录ID部分不能为空"; goto ERROR1; } if (info.OldRecPath != info.NewRecPath) { strError = "当action为\"change\"时,info.NewRecordPath路径 '" + info.NewRecPath + "' 和info.OldRecPath '" + info.OldRecPath + "' 必须相同"; goto ERROR1; } string strExistXml = ""; byte[] exist_timestamp = null; string strOutputPath = ""; string strMetaData = ""; // 先读出数据库中即将覆盖位置的已有记录 REDOLOAD: lRet = channel.GetRes(info.NewRecPath, out strExistXml, out strMetaData, out exist_timestamp, out strOutputPath, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) { // 如果记录不存在, 则构造一条空的记录 bExist = false; strExistXml = "<root />"; exist_timestamp = null; strOutputPath = info.NewRecPath; } else { error = new EntityInfo(info); error.ErrorInfo = "保存操作发生错误, 在读入原有记录阶段:" + strError; error.ErrorCode = channel.OriginErrorCode; ErrorInfos.Add(error); return -1; } } // 把两个记录装入DOM XmlDocument domExist = new XmlDocument(); XmlDocument domNew = new XmlDocument(); try { domExist.LoadXml(strExistXml); } catch (Exception ex) { strError = "strExistXml装载进入DOM时发生错误: " + ex.Message; goto ERROR1; } try { domNew.LoadXml(info.NewRecord); } catch (Exception ex) { strError = "info.NewRecord装载进入DOM时发生错误: " + ex.Message; goto ERROR1; } // 观察时间戳是否发生变化 nRet = ByteArray.Compare(info.OldTimestamp, exist_timestamp); if (nRet != 0) { // 时间戳不相等了 // 需要把info.OldRecord和strExistXml进行比较,看看和业务有关的元素(要害元素)值是否发生了变化。 // 如果这些要害元素并未发生变化,就继续进行合并、覆盖保存操作 XmlDocument domOld = new XmlDocument(); try { domOld.LoadXml(info.OldRecord); } catch (Exception ex) { strError = "info.OldRecord装载进入DOM时发生错误: " + ex.Message; goto ERROR1; } if (bForce == false) { // 比较两个记录, 看看和事项有关的字段是否发生了变化 // return: // 0 没有变化 // 1 有变化 nRet = IsItemInfoChanged(domOld, domExist); } if (nRet == 1 || bForce == true) // 2008/10/19 { error = new EntityInfo(info); // 错误信息中, 返回了修改过的原记录和新时间戳 error.OldRecord = strExistXml; error.OldTimestamp = exist_timestamp; if (bExist == false) error.ErrorInfo = "保存操作发生错误: 数据库中的原记录 (路径为'" + info.OldRecPath + "') 已被删除。"; else error.ErrorInfo = "保存操作发生错误: 数据库中的原记录 (路径为'" + info.OldRecPath + "') 已发生过修改"; error.ErrorCode = ErrorCodeValue.TimestampMismatch; ErrorInfos.Add(error); return -1; } // exist_timestamp此时已经反映了库中被修改后的记录的时间戳 } // 合并新旧记录 string strWarning = ""; string strNewXml = ""; if (bForce == false) { // 2011/2/11 nRet = CanChange( sessioninfo, "change", domExist, domNew, out strError); if (nRet == -1) goto ERROR1; if (nRet == 0) { error = new EntityInfo(info); error.ErrorInfo = strError; error.ErrorCode = ErrorCodeValue.AccessDenied; ErrorInfos.Add(error); return -1; } // 2010/4/8 nRet = this.App.SetOperation( ref domNew, "lastModified", sessioninfo.UserID, "", out strError); if (nRet == -1) goto ERROR1; // return: // -1 出错 // 0 正确 // 1 有部分修改没有兑现。说明在strError中 nRet = MergeTwoItemXml( sessioninfo, domExist, domNew, out strNewXml, out strError); if (nRet == -1) goto ERROR1; if (nRet == 1) strWarning = strError; } else { // 2008/10/19 strNewXml = domNew.OuterXml; } // 保存新记录 byte[] output_timestamp = null; lRet = channel.DoSaveTextRes(info.NewRecPath, strNewXml, false, // include preamble? "content", exist_timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch) { if (nRedoCount > 10) { strError = "反复保存均遇到时间戳冲突, 超过10次重试仍然失败"; goto ERROR1; } // 发现时间戳不匹配 // 重复进行提取已存在记录\比较的过程 nRedoCount++; goto REDOLOAD; } error = new EntityInfo(info); error.ErrorInfo = "保存操作发生错误:" + strError; error.ErrorCode = channel.OriginErrorCode; ErrorInfos.Add(error); return -1; } else // 成功 { DomUtil.SetElementText(domOperLog.DocumentElement, "action", "change"); // 新记录 XmlNode node = DomUtil.SetElementText(domOperLog.DocumentElement, "record", strNewXml); DomUtil.SetAttr(node, "recPath", info.NewRecPath); // 旧记录 node = DomUtil.SetElementText(domOperLog.DocumentElement, "oldRecord", strExistXml); DomUtil.SetAttr(node, "recPath", info.OldRecPath); // 保存成功,需要返回信息元素。因为需要返回新的时间戳 error = new EntityInfo(info); error.NewTimestamp = output_timestamp; error.NewRecord = strNewXml; error.ErrorInfo = "保存操作成功。NewTimeStamp中返回了新的时间戳,NewRecord中返回了实际保存的新记录(可能和提交的新记录稍有差异)。"; if (string.IsNullOrEmpty(strWarning) == false) { error.ErrorInfo = "保存操作成功。但" + strWarning; error.ErrorCode = ErrorCodeValue.PartialDenied; } else error.ErrorCode = ErrorCodeValue.NoError; ErrorInfos.Add(error); } return 0; ERROR1: error = new EntityInfo(info); error.ErrorInfo = strError; error.ErrorCode = ErrorCodeValue.CommonError; ErrorInfos.Add(error); return -1; }
// 保存记录 // parameters: // strRecordPath 记录路径。如果==null,表示直接用textBox_recPath中当前的内容作为路径 public void SaveRecord(string strRecordPath) { if (strRecordPath != null) textBox_recPath.Text = strRecordPath; if (textBox_recPath.Text == "") { MessageBox.Show(this, "路径不能为空"); return; } ResPath respath = new ResPath(textBox_recPath.Text); Uri uri = null; try { uri = new Uri(respath.Url); } catch (Exception ex) { MessageBox.Show(this, "路径错误: " + ex.Message); return; } // 保存到文件 if (uri.IsFile) { MessageBox.Show(this, "暂时不支持保存到文件"); return; } string strError; string strXml = ""; bool bHasUploadedFile = false; int nRet = GetXmlRecord(out strXml, out bHasUploadedFile, out strError); if (nRet == -1) { MessageBox.Show(this, strError); return; } byte [] baOutputTimeStamp = null; string strOutputPath = ""; long lRet = 0; int nUploadCount = 0; // 使用Channel RmsChannel channelSave = channel; channel = Channels.GetChannel(respath.Url); Debug.Assert(channel != null, "Channels.GetChannel 异常"); try { stop.OnStop += new StopEventHandler(this.DoStop); stop.Initial("正在保存记录 " + respath.FullPath); stop.BeginLoop(); EnableControlsInLoading(true); //string strTemp = ByteArray.GetHexTimeStampString(this.TimeStamp); if (String.IsNullOrEmpty(this.strDatabaseOriginPath) == false && bHasUploadedFile == true && respath.FullPath != this.strDatabaseOriginPath) { ResPath respath_old = new ResPath(this.strDatabaseOriginPath); if (respath_old.Url != respath.Url) { MessageBox.Show(this, "目前暂不支持跨服务器情况下的资源复制。本记录中原有的已上载资源,在另存到目标库的时丢失(为空),请注意保存完后手动上载。"); goto SKIPCOPYRECORD; } // 复制记录 // return: // -1 出错。错误信息在strError中 // 0或者其他 成功 nRet = channel.DoCopyRecord(respath_old.Path, respath.Path, false, // bool bDeleteOriginRecord, out baOutputTimeStamp, out strOutputPath, out strError); if (nRet == -1) { MessageBox.Show(this, "复制资源时发生错误: " + strError); } else { // 为继续保存最新XML记录作准备 respath.Path = strOutputPath; // ?形式路径其实已经确定 this.TimeStamp = baOutputTimeStamp; } } SKIPCOPYRECORD: lRet = channel.DoSaveTextRes(respath.Path, strXml, false, // bInlucdePreamble "", // style this.TimeStamp, out baOutputTimeStamp, out strOutputPath, out strError); EnableControlsInLoading(false); stop.EndLoop(); stop.OnStop -= new StopEventHandler(this.DoStop); stop.Initial(""); if (lRet == -1) { MessageBox.Show(this, "保存记录失败,原因: "+strError); return; } // this.TimeStamp = baOutputTimeStamp; respath.Path = strOutputPath; textBox_recPath.Text = respath.FullPath; //// this.strDatabaseOriginPath = respath.Url + "?" + strOutputPath; // 保存从数据库中来的原始path stop.OnStop += new StopEventHandler(this.DoStop); stop.Initial("正在保存资源 " + respath.FullPath); stop.BeginLoop(); EnableControlsInLoading(true); Debug.Assert(channel != null, ""); // 保存对象资源,循环对象列表就可以了 nUploadCount = this.listView_resFiles.DoUpload( respath.Path, channel, stop, out strError); EnableControlsInLoading(false); stop.EndLoop(); stop.OnStop -= new StopEventHandler(this.DoStop); stop.Initial(""); } finally { channel = channelSave; } if (nUploadCount == -1) { MessageBox.Show(this, "XML记录保存成功, 但保存资源失败,原因: "+strError); return; } if (nUploadCount > 0) { // 使用Channel channelSave = channel; channel = Channels.GetChannel(respath.Url); Debug.Assert(channel != null, "Channels.GetChannel 异常"); // 需要重新获得时间戳 string strStyle = "timestamp,metadata"; // withresmetadata string strMetaData = ""; string strContent = ""; try { lRet = channel.GetRes(respath.Path, strStyle, out strContent, out strMetaData, out baOutputTimeStamp, out strOutputPath, out strError); if (lRet == -1) { MessageBox.Show(this, "重新获得时间戳 '" + respath.FullPath + "' 失败。原因 : " + strError); return; } } finally { channel = channelSave; } this.TimeStamp = baOutputTimeStamp; // 设置时间戳很重要。即便xml不合法,也应设置好时间戳,否则窗口无法进行正常删除。 this.m_strMetaData = strMetaData; // 记忆XML记录的元数据 } this.Changed = false; MessageBox.Show(this, "保存记录 '" + respath.FullPath + "' 成功。"); }
// TODO: 是否检查流通信息,需要可以通过参数控制 // 检索书目记录下属的事项记录,返回少量必要的信息,可以提供后面实做删除时使用 // parameters: // strStyle return_record_xml 要在DeleteEntityInfo结构中返回OldRecord内容 // check_circulation_info 检查是否具有流通信息。如果具有则会报错 2012/12/19 把缺省行为变为此参数 // return: // -1 error // 0 not exist item dbname // 1 exist item dbname public int SearchChildItems(RmsChannel channel, string strBiblioRecPath, string strStyle, out long lHitCount, out List<DeleteEntityInfo> entityinfos, out string strError) { strError = ""; lHitCount = 0; entityinfos = new List<DeleteEntityInfo>(); int nRet = 0; bool bReturnRecordXml = StringUtil.IsInList("return_record_xml", strStyle); bool bCheckCirculationInfo = StringUtil.IsInList("check_circulation_info", strStyle); bool bOnlyGetCount = StringUtil.IsInList("only_getcount", strStyle); string strBiblioDbName = ResPath.GetDbName(strBiblioRecPath); string strBiblioRecId = ResPath.GetRecordId(strBiblioRecPath); // 获得书目库对应的事项库名 string strItemDbName = ""; nRet = this.GetItemDbName(strBiblioDbName, out strItemDbName, out strError); if (nRet == -1) goto ERROR1; if (String.IsNullOrEmpty(strItemDbName) == true) return 0; // 检索实体库中全部从属于特定id的记录 string strQueryXml = "<target list='" + StringUtil.GetXmlStringSimple(strItemDbName + ":" + "父记录") + "'><item><word>" + strBiblioRecId + "</word><match>exact</match><relation>=</relation><dataType>string</dataType><maxCount>-1</maxCount></item><lang>" + "zh" + "</lang></target>"; long lRet = channel.DoSearch(strQueryXml, "entities", "", // strOuputStyle out strError); if (lRet == -1) goto ERROR1; if (lRet == 0) { strError = "没有找到属于书目记录 '" + strBiblioRecPath + "' 的任何"+this.ItemName+"记录"; return 0; } lHitCount = lRet; // 仅返回命中条数 if (bOnlyGetCount == true) return 0; int nResultCount = (int)lRet; int nMaxCount = 10000; if (nResultCount > nMaxCount) { strError = "命中"+this.ItemName+"记录数 " + nResultCount.ToString() + " 超过 "+nMaxCount.ToString()+", 暂时不支持针对它们的删除操作"; goto ERROR1; } int nStart = 0; int nPerCount = 100; for (; ; ) { List<string> aPath = null; lRet = channel.DoGetSearchResult( "entities", nStart, nPerCount, "zh", null, out aPath, out strError); if (lRet == -1) goto ERROR1; if (aPath.Count == 0) { strError = "aPath.Count == 0"; goto ERROR1; } // 获得每条记录 for (int i = 0; i < aPath.Count; i++) { string strMetaData = ""; string strXml = ""; byte[] timestamp = null; string strOutputPath = ""; lRet = channel.GetRes(aPath[i], out strXml, out strMetaData, out timestamp, out strOutputPath, out strError); DeleteEntityInfo entityinfo = new DeleteEntityInfo(); if (lRet == -1) { /* entityinfo.RecPath = aPath[i]; entityinfo.ErrorCode = channel.OriginErrorCode; entityinfo.ErrorInfo = channel.ErrorInfo; entityinfo.OldRecord = ""; entityinfo.OldTimestamp = null; entityinfo.NewRecord = ""; entityinfo.NewTimestamp = null; entityinfo.Action = ""; * */ if (channel.ErrorCode == ChannelErrorCode.NotFound) continue; strError = "获取"+this.ItemName+"记录 '" + aPath[i] + "' 时发生错误: " + strError; goto ERROR1; // goto CONTINUE; } entityinfo.RecPath = strOutputPath; entityinfo.OldTimestamp = timestamp; if (bReturnRecordXml == true) entityinfo.OldRecord = strXml; if (bCheckCirculationInfo == true) { // 检查是否有借阅信息 // 把记录装入DOM XmlDocument domExist = new XmlDocument(); try { domExist.LoadXml(strXml); } catch (Exception ex) { strError = this.ItemName + "记录 '" + aPath[i] + "' 装载进入DOM时发生错误: " + ex.Message; goto ERROR1; } /* entityinfo.ItemBarcode = DomUtil.GetElementText(domExist.DocumentElement, "barcode"); * */ // TODO: 在日志恢复阶段调用本函数时,是否还有必要检查是否具有流通信息?似乎这时应强制删除为好 // 观察已经存在的记录是否有流通信息 // return: // -1 出错 // 0 没有 // 1 有。报错信息在strError中 nRet = this.HasCirculationInfo(domExist, out strError); if (nRet == -1) goto ERROR1; if (nRet == 1) { strError = "拟删除的" + this.ItemName + "记录 '" + entityinfo.RecPath + "' 中" + strError + "(此种情况可能不限于这一条),不能删除。因此全部删除操作均被放弃。"; goto ERROR1; } } // CONTINUE: entityinfos.Add(entityinfo); } nStart += aPath.Count; if (nStart >= nResultCount) break; } return 1; ERROR1: return -1; }
// 回调函数 int DownloadOneFileMetaData(string strID, out string strResultXml, out byte[] timestamp, out string strError) { timestamp = null; strError = ""; ResPath respath = new ResPath(textBox_recPath.Text); string strResPath = respath.Path + "/object/" + strID; strResPath = strResPath.Replace(":", "/"); // 使用Channel RmsChannel channelSave = channel; channel = Channels.GetChannel(respath.Url); Debug.Assert(channel != null, "Channels.GetChannel 异常"); try { stop.OnStop += new StopEventHandler(this.DoStop); stop.Initial("正在下载资源文件的元数据 " + strResPath); stop.BeginLoop(); byte [] baOutputTimeStamp = null; string strOutputPath = ""; EnableControlsInLoading(true); // 只得到metadata long lRet = channel.GetRes(strResPath, (Stream)null, stop, "metadata,timestamp,outputpath", null, out strResultXml, out baOutputTimeStamp, out strOutputPath, out strError); EnableControlsInLoading(false); stop.EndLoop(); stop.OnStop -= new StopEventHandler(this.DoStop); stop.Initial(""); if (lRet == -1) { MessageBox.Show(this, "下载资源文件元数据失败,原因: "+strError); goto ERROR1; } timestamp = baOutputTimeStamp; } finally { channel = channelSave; } return 0; ERROR1: return -1; }
// 删除属于同一书目记录的全部实体记录 // 这是需要提供EntityInfo数组的版本 // return: // -1 error // 0 没有找到属于书目记录的任何实体记录,因此也就无从删除 // >0 实际删除的实体记录数 public int DeleteBiblioChildItems( // RmsChannelCollection Channels, RmsChannel channel, List<DeleteEntityInfo> entityinfos, XmlDocument domOperLog, out string strError) { strError = ""; if (entityinfos == null || entityinfos.Count == 0) return 0; int nDeletedCount = 0; XmlNode root = null; if (domOperLog != null) { root = domOperLog.CreateElement("deleted"+this.ItemNameInternal+"Records"); domOperLog.DocumentElement.AppendChild(root); } #if NO RmsChannel channel = Channels.GetChannel(this.App.WsUrl); if (channel == null) { strError = "get channel error"; goto ERROR1; } #endif // 真正实行删除 for (int i = 0; i < entityinfos.Count; i++) { DeleteEntityInfo info = entityinfos[i]; byte[] output_timestamp = null; int nRedoCount = 0; REDO_DELETE: // this.EntityLocks.LockForWrite(info.ItemBarcode); try { long lRet = channel.DoDeleteRes(info.RecPath, info.OldTimestamp, out output_timestamp, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) continue; // 如果不重试,让时间戳出错暴露出来。 // 如果要重试,也得加上重新读入册记录并判断重新判断无借还信息才能删除 if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch) { if (nRedoCount > 10) { strError = "重试了10次还不行。删除"+this.ItemName+"记录 '" + info.RecPath + "' 时发生错误: " + strError; goto ERROR1; } nRedoCount++; // 重新读入记录 string strMetaData = ""; string strXml = ""; string strOutputPath = ""; string strError_1 = ""; lRet = channel.GetRes(info.RecPath, out strXml, out strMetaData, out output_timestamp, out strOutputPath, out strError_1); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) continue; strError = "在删除"+this.ItemName+"记录 '" + info.RecPath + "' 时发生时间戳冲突,于是自动重新获取记录,但又发生错误: " + strError_1; goto ERROR1; // goto CONTINUE; } // 检查是否有借阅信息 // 把记录装入DOM XmlDocument domExist = new XmlDocument(); try { if (String.IsNullOrEmpty(strXml) == false) domExist.LoadXml(strXml); else domExist.LoadXml("<root />"); } catch (Exception ex) { strError = this.ItemName+"记录 '" + info.RecPath + "' XML装载进入DOM时发生错误: " + ex.Message; goto ERROR1; } /* info.ItemBarcode = DomUtil.GetElementText(domExist.DocumentElement, "barcode"); * */ // 观察已经存在的记录是否有流通信息 // return: // -1 出错 // 0 没有 // 1 有。报错信息在strError中 int nRet = this.HasCirculationInfo(domExist, out strError); if (nRet == -1) goto ERROR1; if (nRet == 1) { strError = "拟删除的"+this.ItemName+"记录 '" + info.RecPath + "' 中"+strError+"(此种情况可能不限于这一条),不能删除。"; goto ERROR1; } info.OldTimestamp = output_timestamp; goto REDO_DELETE; } strError = "删除"+this.ItemName+"记录 '" + info.RecPath + "' 时发生错误: " + strError; goto ERROR1; } } finally { // this.EntityLocks.UnlockForWrite(info.ItemBarcode); } // 增补到日志DOM中 if (domOperLog != null) { Debug.Assert(root != null, ""); XmlNode node = domOperLog.CreateElement("record"); root.AppendChild(node); DomUtil.SetAttr(node, "recPath", info.RecPath); } nDeletedCount++; } return nDeletedCount; ERROR1: return -1; }
// 获得一个汉字的拼音 // 所获得的拼音, 是一个分号间隔的字符串, 表示对应于这个汉字的多音 // return: // -1 error // 1 found // 0 not found int GetOnePinyin(string strOneHanzi, out string strPinyin, out string strError) { strPinyin = ""; strError = ""; // 拼音库路径 string strPinyinDbPath = MainForm.AppInfo.GetString("pinyin", "pinyin_db_path", ""); if (String.IsNullOrEmpty(strPinyinDbPath) == true) { strError = "拼音库路径尚未配置。请先用菜单“帮助/系统参数设置”功能配置适当的拼音库路径。"; return -1; } ResPath respath = new ResPath(strPinyinDbPath); string strDbName = respath.Path; // 2007/4/5 改造 加上了 GetXmlStringSimple() string strQueryXml = "<target list='" + strDbName + ":" + "汉字'><item><word>" + StringUtil.GetXmlStringSimple(strOneHanzi) + "</word><match>exact</match><relation>=</relation><dataType>string</dataType><maxCount>10</maxCount></item><lang>chi</lang></target>"; // 使用Channel RmsChannel channelSave = channel; channel = Channels.GetChannel(respath.Url); Debug.Assert(channel != null, "Channels.GetChannel 异常"); try { stop.OnStop += new StopEventHandler(this.DoStop); stop.Initial("正在检索拼音 '" + strOneHanzi + "'"); stop.BeginLoop(); try { long nRet = channel.DoSearch(strQueryXml, "default", out strError); if (nRet == -1) { strError = "检索拼音库时出错: " + strError; return -1; } if (nRet == 0) return 0; // not found List<string> aPath = null; nRet = channel.DoGetSearchResult( "default", 1, this.Lang, stop, out aPath, out strError); if (nRet == -1) { strError = "检索拼音库获取检索结果时出错: " + strError; return -1; } if (aPath.Count == 0) { strError = "检索拼音库获取的检索结果为空"; return -1; } string strStyle = "content,data"; string strContent; string strMetaData; byte[] baTimeStamp; string strOutputPath; nRet = channel.GetRes((string)aPath[0], strStyle, // this.eventClose, out strContent, out strMetaData, out baTimeStamp, out strOutputPath, out strError); if (nRet == -1) { strError = "获取拼音记录体时出错: " + strError; return -1; } // 取出拼音字符串 XmlDocument dom = new XmlDocument(); try { dom.LoadXml(strContent); } catch (Exception ex) { strError = "汉字 '" + strOneHanzi + "' 所获取的拼音记录 " + strContent + " XML数据装载出错: " + ex.Message; return -1; } strPinyin = DomUtil.GetAttr(dom.DocumentElement, "p"); return 1; } finally { stop.EndLoop(); stop.OnStop -= new StopEventHandler(this.DoStop); stop.Initial(""); } } finally { channel = channelSave; } }
// 获得事项记录 // 本函数可获得超过1条以上的路径 // parameters: // timestamp 返回命中的第一条的timestamp // strStyle 如果包含 withresmetadata ,表示要在XML记录中返回<dprms:file>元素内的 __xxx 属性 // return: // -1 error // 0 not found // 1 命中1条 // >1 命中多于1条 public int GetItemRecXml( // RmsChannelCollection channels, RmsChannel channel, List<string> locateParams, string strStyle, out string strXml, int nMax, out List<string> aPath, out byte[] timestamp, out string strError) { aPath = null; strXml = ""; strError = ""; timestamp = null; // 构造检索式 /* string strQueryXml = "<target list='" + StringUtil.GetXmlStringSimple(strIssueDbName + ":" + "出版时间") + "'><item><word>" + StringUtil.GetXmlStringSimple(strPublishTime) + "</word><match>exact</match><relation>=</relation><dataType>string</dataType><maxCount>-1</maxCount></item><lang>zh</lang></target>"; strQueryXml += "<operator value='AND'/>"; strQueryXml += "<target list='" + StringUtil.GetXmlStringSimple(strIssueDbName + ":" + "父记录") + "'><item><word>" + StringUtil.GetXmlStringSimple(strParentID) + "</word><match>exact</match><relation>=</relation><dataType>string</dataType><maxCount>-1</maxCount></item><lang>zh</lang></target>"; strQueryXml = "<group>" + strQueryXml + "</group>"; * */ // 构造用于获取事项记录的XML检索式 string strQueryXml = ""; int nRet = MakeGetItemRecXmlSearchQuery( locateParams, nMax, out strQueryXml, out strError); if (nRet == -1) goto ERROR1; #if NO RmsChannel channel = channels.GetChannel(this.App.WsUrl); if (channel == null) { strError = "get channel error"; return -1; } #endif long lRet = channel.DoSearch(strQueryXml, "default", "", // strOuputStyle out strError); if (lRet == -1) goto ERROR1; // not found if (lRet == 0) { string strText = ""; // 构造定位提示信息。用于报错。 nRet = GetLocateText( locateParams, out strText, out strError); if (nRet == -1) { strError = "定位信息没有找到。并且GetLocateText()函数报错: " + strError; return 0; } strError = strText + " 的事项没有找到"; return 0; } long lHitCount = lRet; // List<string> aPath = null; lRet = channel.DoGetSearchResult( "default", 0, Math.Min(nMax, lHitCount), "zh", null, out aPath, out strError); if (lRet == -1) goto ERROR1; Debug.Assert(aPath != null, ""); if (aPath.Count == 0) { strError = "DoGetSearchResult aPath error"; goto ERROR1; } string strMetaData = ""; string strOutputPath = ""; string strGetStyle = "content,data,metadata,timestamp,outputpath"; if (StringUtil.IsInList("withresmetadata", strStyle) == true) strGetStyle += ",withresmetadata"; lRet = channel.GetRes(aPath[0], strGetStyle, out strXml, out strMetaData, out timestamp, out strOutputPath, out strError); if (lRet == -1) goto ERROR1; return (int)lHitCount; ERROR1: return -1; }
int m_nInGetCfgFile = 0; // 防止GetCfgFile()函数重入 2008/3/6 // marc编辑窗要从外部获得配置文件内容 private void MarcEditor_GetConfigFile(object sender, DigitalPlatform.Marc.GetConfigFileEventArgs e) { if (m_nInGetCfgFile > 0) { e.ErrorInfo = "MarcEditor_GetConfigFile() 重入了"; return; } if (String.IsNullOrEmpty(textBox_recPath.Text)) { e.ErrorInfo = "URL为空"; return; } // 下载配置文件 ResPath respath = new ResPath(textBox_recPath.Text); string strCfgFileName = e.Path; int nRet = strCfgFileName.IndexOf("#"); if (nRet != -1) { strCfgFileName = strCfgFileName.Substring(0, nRet); } string strPath = ResPath.GetDbName(respath.Path) + "/cfgs/" + strCfgFileName; // 使用Channel RmsChannel channelSave = channel; channel = Channels.GetChannel(respath.Url); Debug.Assert(channel != null, "Channels.GetChannel 异常"); m_nInGetCfgFile++; try { string strContent; string strError; stop.OnStop += new StopEventHandler(this.DoStop); stop.Initial("正在下载文件" + strPath); stop.BeginLoop(); byte[] baTimeStamp = null; string strMetaData; string strOutputPath; long lRet = channel.GetRes( MainForm.cfgCache, strPath, out strContent, out strMetaData, out baTimeStamp, out strOutputPath, out strError); stop.EndLoop(); stop.OnStop -= new StopEventHandler(this.DoStop); stop.Initial(""); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) { e.ErrorInfo = ""; return; } e.ErrorInfo = "获得配置文件 '" + strPath + "' 时出错:" + strError; return; } else { byte[] baContent = StringUtil.GetUtf8Bytes(strContent, true); MemoryStream stream = new MemoryStream(baContent); e.Stream = stream; } } finally { channel = channelSave; m_nInGetCfgFile--; } }
// 删除事项记录的操作 int DoOperDelete( SessionInfo sessioninfo, bool bForce, RmsChannel channel, EntityInfo info, List<string> oldLocateParams, /* string strIssueDbName, string strParentID, string strOldPublishTime, * */ XmlDocument domOldRec, ref XmlDocument domOperLog, ref List<EntityInfo> ErrorInfos) { int nRedoCount = 0; EntityInfo error = null; int nRet = 0; long lRet = 0; string strError = ""; /* // 如果newrecpath为空但是oldrecpath有值,就用oldrecpath的值 // 2007/10/23 if (String.IsNullOrEmpty(info.NewRecPath) == true) { if (String.IsNullOrEmpty(info.OldRecPath) == false) info.NewRecPath = info.OldRecPath; }*/ // 2008/6/24 if (String.IsNullOrEmpty(info.NewRecPath) == false) { if (info.NewRecPath != info.OldRecPath) { strError = "action为delete时, 如果info.NewRecPath不空,则其内容必须和info.OldRecPath一致。(info.NewRecPath='" + info.NewRecPath + "' info.OldRecPath='" + info.OldRecPath + "')"; return -1; } } else { info.NewRecPath = info.OldRecPath; } string strText = ""; // 构造定位提示信息。用于报错。 nRet = GetLocateText( oldLocateParams, out strText, out strError); if (nRet == -1) { strError = "GetLocateText()函数报错: " + strError; goto ERROR1; } // 如果记录路径为空, 则先获得记录路径 if (String.IsNullOrEmpty(info.NewRecPath) == true) { List<string> aPath = null; nRet = IsLocateParamNullOrEmpty( oldLocateParams, out strError); if (nRet == -1) goto ERROR1; if (nRet == 1) { strError += "info.OldRecord中的" + strError + " 和 info.RecPath参数值为空,同时出现,这是不允许的"; goto ERROR1; } /* RmsChannel channel = sessioninfo.Channels.GetChannel(this.App.WsUrl); if (channel == null) { strError = "get channel error"; goto ERROR1; } * */ // 本函数只负责查重, 并不获得记录体 // return: // -1 error // 其他 命中记录条数(不超过nMax规定的极限) nRet = this.SearchItemRecDup( // sessioninfo.Channels, channel, oldLocateParams, 100, out aPath, out strError); if (nRet == -1) { strError = "删除操作中事项查重阶段发生错误:" + strError; goto ERROR1; } if (nRet == 0) { error = new EntityInfo(info); error.ErrorInfo = strText + " 的记录已不存在"; error.ErrorCode = ErrorCodeValue.NotFound; ErrorInfos.Add(error); return -1; } if (nRet > 1) { /* string[] pathlist = new string[aPath.Count]; aPath.CopyTo(pathlist); * */ strError = strText + " 已经被下列多条事项记录使用了: " + StringUtil.MakePathList(aPath)/*String.Join(",", pathlist)*/ + "',这是一个严重的系统故障,请尽快通知系统管理员处理。"; goto ERROR1; } info.NewRecPath = aPath[0]; } Debug.Assert(String.IsNullOrEmpty(info.NewRecPath) == false, ""); // Debug.Assert(strEntityDbName != "", ""); byte[] exist_timestamp = null; string strOutputPath = ""; string strMetaData = ""; string strExistingXml = ""; REDOLOAD: // 先读出数据库中此位置的已有记录 lRet = channel.GetRes(info.NewRecPath, out strExistingXml, out strMetaData, out exist_timestamp, out strOutputPath, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) { error = new EntityInfo(info); error.ErrorInfo = strText + " 的事项记录 '" + info.NewRecPath + "' 已不存在"; error.ErrorCode = channel.OriginErrorCode; ErrorInfos.Add(error); return -1; } else { error = new EntityInfo(info); error.ErrorInfo = "删除操作发生错误, 在读入原有记录 '" + info.NewRecPath + "' 阶段:" + strError; error.ErrorCode = channel.OriginErrorCode; ErrorInfos.Add(error); return -1; } } // 把记录装入DOM XmlDocument domExist = new XmlDocument(); try { domExist.LoadXml(strExistingXml); } catch (Exception ex) { strError = "strExistXml装载进入DOM时发生错误: " + ex.Message; goto ERROR1; } // 观察已存在的记录中,唯一性字段是否和要求的一致 // return: // -1 出错 // 0 一致 // 1 不一致。报错信息在strError中 nRet = IsLocateInfoCorrect( oldLocateParams, domExist, out strError); if (nRet != 0) goto ERROR1; if (bForce == false) { // 观察已经存在的记录是否有流通信息 // return: // -1 出错 // 0 没有 // 1 有。报错信息在strError中 nRet = HasCirculationInfo(domExist, out strError); if (nRet != 0) goto ERROR1; } if (bForce == false) { // 记录是否允许删除? // return: // -1 出错。不允许删除。 // 0 不允许删除,因为权限不够等原因。原因在strError中 // 1 可以删除 nRet = CanDelete( sessioninfo, domExist, out strError); if (nRet != 1) goto ERROR1; } // 比较时间戳 // 观察时间戳是否发生变化 nRet = ByteArray.Compare(info.OldTimestamp, exist_timestamp); if (nRet != 0) { // 2008/10/19 if (bForce == true) { error = new EntityInfo(info); error.NewTimestamp = exist_timestamp; // 让前端知道库中记录实际上发生过变化 error.ErrorInfo = "数据库中即将删除的册记录已经发生了变化,请重新装载、仔细核对后再行删除。"; error.ErrorCode = ErrorCodeValue.TimestampMismatch; ErrorInfos.Add(error); return -1; } // 如果前端给出了旧记录,就有和库中记录进行比较的基础 if (String.IsNullOrEmpty(info.OldRecord) == false) { // 比较两个记录, 看看和事项要害信息有关的字段是否发生了变化 // return: // 0 没有变化 // 1 有变化 nRet = IsItemInfoChanged(domExist, domOldRec); if (nRet == 1) { error = new EntityInfo(info); error.NewTimestamp = exist_timestamp; // 让前端知道库中记录实际上发生过变化 error.ErrorInfo = "数据库中即将删除的" + this.ItemName + "记录已经发生了变化,请重新装载、仔细核对后再行删除。"; error.ErrorCode = ErrorCodeValue.TimestampMismatch; ErrorInfos.Add(error); return -1; } } info.OldTimestamp = exist_timestamp; info.NewTimestamp = exist_timestamp; } byte[] output_timestamp = null; lRet = channel.DoDeleteRes(info.NewRecPath, info.OldTimestamp, out output_timestamp, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch) { if (nRedoCount > 10) { strError = "反复删除均遇到时间戳冲突, 超过10次重试仍然失败"; goto ERROR1; } // 发现时间戳不匹配 // 重复进行提取已存在记录\比较的过程 nRedoCount++; goto REDOLOAD; } error = new EntityInfo(info); error.NewTimestamp = output_timestamp; error.ErrorInfo = "删除操作发生错误:" + strError; error.ErrorCode = channel.OriginErrorCode; ErrorInfos.Add(error); return -1; } else { // 成功 DomUtil.SetElementText(domOperLog.DocumentElement, "action", "delete"); // 不创建<record>元素 // 创建<oldRecord>元素 XmlNode node = DomUtil.SetElementText(domOperLog.DocumentElement, "oldRecord", strExistingXml); DomUtil.SetAttr(node, "recPath", info.NewRecPath); // 如果删除成功,则不必要在数组中返回表示成功的信息元素了 } return 0; ERROR1: error = new EntityInfo(info); error.ErrorInfo = strError; error.ErrorCode = ErrorCodeValue.CommonError; ErrorInfos.Add(error); return -1; }
public void LoadTemplate() { if (this.Changed == true) { DialogResult result = MessageBox.Show(this, "装载模板前,发现当前窗口中已有内容修改后未来得及保存。是否要继续装载模板到窗口中(这样将丢失先前修改的内容)?\r\n\r\n(是)继续装载模板 (否)不装载模板", "dp2rms", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2); if (result != DialogResult.Yes) { MessageBox.Show(this, "装载模板操作被放弃..."); return; } } OpenResDlg dlg = new OpenResDlg(); dlg.Font = GuiUtil.GetDefaultFont(); dlg.Text = "请选择目标数据库"; dlg.EnabledIndices = new int[] { ResTree.RESTYPE_DB }; dlg.ap = this.MainForm.AppInfo; dlg.ApCfgTitle = "detailform_openresdlg"; dlg.Path = textBox_recPath.Text; dlg.Initial( MainForm.Servers, this.Channels); // dlg.StartPosition = FormStartPosition.CenterScreen; dlg.ShowDialog(this); if (dlg.DialogResult != DialogResult.OK) return; textBox_recPath.Text = dlg.Path + "/?"; // 为了追加保存 // 下载配置文件 ResPath respath = new ResPath(dlg.Path); // 使用Channel RmsChannel channelSave = channel; channel = Channels.GetChannel(respath.Url); Debug.Assert(channel != null, "Channels.GetChannel 异常"); try { string strContent; string strError; string strCfgFilePath = respath.Path + "/cfgs/template"; stop.OnStop += new StopEventHandler(this.DoStop); stop.Initial("正在下载文件" + strCfgFilePath); stop.BeginLoop(); byte[] baTimeStamp = null; string strMetaData; string strOutputPath; long lRet = channel.GetRes( MainForm.cfgCache, strCfgFilePath, // this.eventClose, out strContent, out strMetaData, out baTimeStamp, out strOutputPath, out strError); stop.EndLoop(); stop.OnStop -= new StopEventHandler(this.DoStop); stop.Initial(""); if (lRet == -1) { this.TimeStamp = null; MessageBox.Show(this, strError); return; } else { // MessageBox.Show(this, strContent); SelectRecordTemplateDlg tempdlg = new SelectRecordTemplateDlg(); tempdlg.Font = GuiUtil.GetDefaultFont(); int nRet = tempdlg.Initial(strContent, out strError); if (nRet == -1) { MessageBox.Show(this, "装载配置文件 '" + strCfgFilePath + "' 发生错误: " + strError); return; } tempdlg.ap = this.MainForm.AppInfo; tempdlg.ApCfgTitle = "detailform_selecttemplatedlg"; tempdlg.ShowDialog(this); if (tempdlg.DialogResult != DialogResult.OK) return; this.TimeStamp = null; this.m_strMetaData = ""; // 记忆XML记录的元数据 this.strDatabaseOriginPath = ""; // 保存从数据库中来的原始path nRet = this.SetRecordToControls(tempdlg.SelectedRecordXml, out strError); if (nRet == -1) { MessageBox.Show(this, strError); return; } this.TimeStamp = baTimeStamp; this.Text = respath.ReverseFullPath; } } finally { channel = channelSave; } }
// 执行API中的"move"操作 // 1) 操作成功后, NewRecord中有实际保存的新记录,NewTimeStamp为新的时间戳 // 2) 如果返回TimeStampMismatch错,则OldRecord中有库中发生变化后的“原记录”,OldTimeStamp是其时间戳 // return: // -1 出错 // 0 成功 int DoOperMove( SessionInfo sessioninfo, // string strUserID, RmsChannel channel, EntityInfo info, ref XmlDocument domOperLog, ref List<EntityInfo> ErrorInfos) { EntityInfo error = null; bool bExist = true; // info.RecPath所指的记录是否存在? int nRet = 0; long lRet = 0; string strError = ""; // 检查路径 if (info.OldRecPath == info.NewRecPath) { strError = "当action为\"move\"时,info.NewRecordPath路径 '" + info.NewRecPath + "' 和info.OldRecPath '" + info.OldRecPath + "' 必须不相同"; goto ERROR1; } // 检查即将覆盖的目标位置是不是有记录,如果有,则不允许进行move操作。 // 如果要进行带覆盖目标位置记录功能的move操作,前端可以先执行一个delete操作,然后再执行move操作。 // 这样规定,是为了避免过于复杂的判断逻辑,也便于前端操作者清楚操作的后果。 // 因为如果允许move带有覆盖目标记录功能,则被覆盖的记录的预删除操作,等于进行了一次事项注销,但这个效用不明显,对前端操作人员准确判断事态并对后果负责(而且可能这种注销需要额外的操作权限),不利 bool bAppendStyle = false; // 目标路径是否为追加形态? string strTargetRecId = ResPath.GetRecordId(info.NewRecPath); if (strTargetRecId == "?" || String.IsNullOrEmpty(strTargetRecId) == true) bAppendStyle = true; string strOutputPath = ""; string strMetaData = ""; if (bAppendStyle == false) { string strExistTargetXml = ""; byte[] exist_target_timestamp = null; // 获取覆盖目标位置的现有记录 lRet = channel.GetRes(info.NewRecPath, out strExistTargetXml, out strMetaData, out exist_target_timestamp, out strOutputPath, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) { // 如果记录不存在, 说明不会造成覆盖态势 /* strExistSourceXml = "<root />"; exist_source_timestamp = null; strOutputPath = info.NewRecPath; * */ } else { error = new EntityInfo(info); error.ErrorInfo = "move操作发生错误, 发生在读入即将覆盖的目标位置 '" + info.NewRecPath + "' 原有记录阶段:" + strError; error.ErrorCode = channel.OriginErrorCode; ErrorInfos.Add(error); return -1; } } else { // 如果记录存在,则目前不允许这样的操作 strError = "移动(move)操作被拒绝。因为在即将覆盖的目标位置 '" + info.NewRecPath + "' 已经存在" + this.ItemName + "记录。请先删除(delete)这条记录,再进行移动(move)操作"; goto ERROR1; } } string strExistSourceXml = ""; byte[] exist_source_timestamp = null; // 先读出数据库中源位置的已有记录 // REDOLOAD: lRet = channel.GetRes(info.OldRecPath, out strExistSourceXml, out strMetaData, out exist_source_timestamp, out strOutputPath, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) { /* // 如果记录不存在, 则构造一条空的记录 bExist = false; strExistSourceXml = "<root />"; exist_source_timestamp = null; strOutputPath = info.NewRecPath; * */ // 这种情况如果放宽,会有严重的副作用,所以不让放宽 strError = "move操作的源记录 '" + info.OldRecPath + "' 在数据库中不存在,所以无法进行移动操作。"; goto ERROR1; } else { error = new EntityInfo(info); error.ErrorInfo = "移动操作发生错误, 在读入库中原有源记录(路径在info.OldRecPath) '" + info.OldRecPath + "' 阶段:" + strError; error.ErrorCode = channel.OriginErrorCode; ErrorInfos.Add(error); return -1; } } // 把两个记录装入DOM XmlDocument domSourceExist = new XmlDocument(); XmlDocument domNew = new XmlDocument(); try { domSourceExist.LoadXml(strExistSourceXml); } catch (Exception ex) { strError = "strExistXml装载进入DOM时发生错误: " + ex.Message; goto ERROR1; } try { domNew.LoadXml(info.NewRecord); } catch (Exception ex) { strError = "info.NewRecord装载进入DOM时发生错误: " + ex.Message; goto ERROR1; } // 观察时间戳是否发生变化 nRet = ByteArray.Compare(info.OldTimestamp, exist_source_timestamp); if (nRet != 0) { // 时间戳不相等了 // 需要把info.OldRecord和strExistXml进行比较,看看和事项有关的元素(要害元素)值是否发生了变化。 // 如果这些要害元素并未发生变化,就继续进行合并、覆盖保存操作 XmlDocument domOld = new XmlDocument(); try { domOld.LoadXml(info.OldRecord); } catch (Exception ex) { strError = "info.OldRecord装载进入DOM时发生错误: " + ex.Message; goto ERROR1; } // 比较两个记录, 看看和事项有关的要害字段是否发生了变化 // return: // 0 没有变化 // 1 有变化 nRet = IsItemInfoChanged(domOld, domSourceExist); if (nRet == 1) { error = new EntityInfo(info); // 错误信息中, 返回了修改过的原记录和新时间戳 error.OldRecord = strExistSourceXml; error.OldTimestamp = exist_source_timestamp; if (bExist == false) error.ErrorInfo = "移动操作发生错误: 数据库中的原记录 (路径为'" + info.OldRecPath + "') 已被删除。"; else error.ErrorInfo = "移动操作发生错误: 数据库中的原记录 (路径为'" + info.OldRecPath + "') 已发生过修改"; error.ErrorCode = ErrorCodeValue.TimestampMismatch; ErrorInfos.Add(error); return -1; } // exist_source_timestamp此时已经反映了库中被修改后的记录的时间戳 } // 2011/2/11 nRet = CanChange( sessioninfo, "move", domSourceExist, domNew, out strError); if (nRet == -1) goto ERROR1; if (nRet == 0) { error = new EntityInfo(info); error.ErrorInfo = strError; error.ErrorCode = ErrorCodeValue.AccessDenied; ErrorInfos.Add(error); return -1; } // 2010/4/8 // nRet = this.App.SetOperation( ref domNew, "moved", sessioninfo.UserID, // strUserID, "", out strError); if (nRet == -1) goto ERROR1; string strWarning = ""; // 合并新旧记录 // return: // -1 出错 // 0 正确 // 1 有部分修改没有兑现。说明在strError中 string strNewXml = ""; nRet = MergeTwoItemXml( sessioninfo, domSourceExist, domNew, out strNewXml, out strError); if (nRet == -1) goto ERROR1; if (nRet == 1) strWarning = strError; // 移动记录 byte[] output_timestamp = null; // TODO: Copy后还要写一次?因为Copy并不写入新记录。 // 其实Copy的意义在于带走资源。否则还不如用Save+Delete lRet = channel.DoCopyRecord(info.OldRecPath, info.NewRecPath, true, // bDeleteSourceRecord out output_timestamp, out strOutputPath, out strError); if (lRet == -1) { strError = "DoCopyRecord() error :" + strError; goto ERROR1; } // Debug.Assert(strOutputPath == info.NewRecPath); string strTargetPath = strOutputPath; lRet = channel.DoSaveTextRes(strTargetPath, strNewXml, false, // include preamble? "content", output_timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) { strError = "移动操作中," + this.ItemName + "记录 '" + info.OldRecPath + "' 已经被成功移动到 '" + strTargetPath + "' ,但在写入新内容时发生错误: " + strError; if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch) { // 不进行反复处理。 // 因为源已经移动,情况很复杂 } // 仅仅写入错误日志即可。没有Undo this.App.WriteErrorLog(strError); error = new EntityInfo(info); error.ErrorInfo = "移动操作发生错误:" + strError; error.ErrorCode = channel.OriginErrorCode; ErrorInfos.Add(error); return -1; } else // 成功 { info.NewRecPath = strOutputPath; // 兑现保存的位置,因为可能有追加形式的路径 DomUtil.SetElementText(domOperLog.DocumentElement, "action", "move"); // 新记录 XmlNode node = DomUtil.SetElementText(domOperLog.DocumentElement, "record", strNewXml); DomUtil.SetAttr(node, "recPath", info.NewRecPath); // 旧记录 node = DomUtil.SetElementText(domOperLog.DocumentElement, "oldRecord", strExistSourceXml); DomUtil.SetAttr(node, "recPath", info.OldRecPath); // 保存成功,需要返回信息元素。因为需要返回新的时间戳 error = new EntityInfo(info); error.NewTimestamp = output_timestamp; error.NewRecord = strNewXml; error.ErrorInfo = "移动操作成功。NewRecPath中返回了实际保存的路径, NewTimeStamp中返回了新的时间戳,NewRecord中返回了实际保存的新记录(可能和提交的源记录稍有差异)。"; if (string.IsNullOrEmpty(strWarning) == false) { error.ErrorInfo = "移动操作成功。但" + strWarning; error.ErrorCode = ErrorCodeValue.PartialDenied; } else error.ErrorCode = ErrorCodeValue.NoError; ErrorInfos.Add(error); } return 0; ERROR1: error = new EntityInfo(info); error.ErrorInfo = strError; error.ErrorCode = ErrorCodeValue.CommonError; ErrorInfos.Add(error); return -1; }
private void CfgFileEditDlg_Load(object sender, System.EventArgs e) { button_export.Enabled = false; MemoryStream stream = null; string strMetaData; string strError = ""; string strMime = ""; Hashtable values = null; if (Obj != null) { if (this.Obj.Content != null) { stream = new MemoryStream(this.Obj.Content); this.Stream = stream; this.Stream.Seek(0, SeekOrigin.Begin); button_export.Enabled = true; } this.TimeStamp = this.Obj.TimeStamp; strMetaData = this.Obj.Metadata; // 观察mime // 取metadata values = StringUtil.ParseMetaDataXml(strMetaData, out strError); if (values == null) { MessageBox.Show(this, strError); return; } strMime = (string)values["mimetype"]; if (strMime == null || strMime == "") strMime = "text"; this.Mime = strMime; this.LocalPath = (string)values["localpath"]; if (this.LocalPath == null) this.LocalPath = ""; this.textBox_content.Text = ""; // string strFirstPart = StringUtil.GetFirstPartPath(ref strMime); if (this.IsText == true) { if (this.Stream != null) { this.Stream.Seek(0, SeekOrigin.Begin); using (StreamReader sr = new StreamReader(this.Stream, Encoding.UTF8)) { this.textBox_content.Text = ConvertCrLf(sr.ReadToEnd()); } } } else { } ////// button_OK.Enabled = false; this.textBox_content.SelectionStart = 0; this.textBox_content.SelectionLength = 0; return; } this.channel = Channels.GetChannel(this.ServerUrl); Debug.Assert(channel != null, "Channels.GetChannel() 异常"); DigitalPlatform.Stop stop = null; if (stopManager != null) { stop = new DigitalPlatform.Stop(); stop.Register(this.stopManager, true); // 和容器关联 stop.OnStop += new StopEventHandler(this.DoStop); stop.Initial("正在下载配置文件: " + this.Path); stop.BeginLoop(); } // string strContent = ""; byte[] baTimeStamp = null; string strOutputPath; string strStyle = "content,data,metadata,timestamp,outputpath"; // string strStyle = "attachment,data,metadata,timestamp,outputpath"; stream = new MemoryStream(); long lRet = channel.GetRes( this.Path, stream, stop, // stop, strStyle, null, // byte [] input_timestamp, out strMetaData, out baTimeStamp, out strOutputPath, out strError); /* long lRet = channel.GetRes(( this.Path, out strContent, out strMetaData, out baTimeStamp, out strOutputPath, out strError); */ if (stopManager != null) { stop.EndLoop(); stop.OnStop -= new StopEventHandler(this.DoStop); stop.Initial(""); } if (lRet == -1) { MessageBox.Show(this, strError); goto FINISH; } this.Stream = stream; this.Stream.Seek(0, SeekOrigin.Begin); button_export.Enabled = true; this.TimeStamp = baTimeStamp; // 观察mime // 取metadata values = StringUtil.ParseMetaDataXml(strMetaData, out strError); if (values == null) { MessageBox.Show(this, strError); goto FINISH; } strMime = (string)values["mimetype"]; if (strMime == null || strMime == "") strMime = "text"; this.Mime = strMime; this.LocalPath = (string)values["localpath"]; if (this.LocalPath == null) this.LocalPath = ""; // string strFirstPart = StringUtil.GetFirstPartPath(ref strMime); if (this.IsText == true) { this.Stream.Seek(0, SeekOrigin.Begin); using (StreamReader sr = new StreamReader(this.Stream, Encoding.UTF8)) { this.textBox_content.Text = ConvertCrLf(sr.ReadToEnd()); } // 注意,此后 this.Stream 被关闭 } else { //this.textBox_content.Text = "<二进制内容无法直接编辑>"; //this.textBox_content.ReadOnly = true; //this.button_format.Enabled = false; } ////// button_OK.Enabled = false; FINISH: if (stopManager != null && stop != null) { stop.Unregister(); // 和容器关联 stop = null; } this.channel = null; this.textBox_content.SelectionStart = 0; this.textBox_content.SelectionLength = 0; }
// 把实体记录借阅信息详细化 // parameters: // strEntityRecPath 册记录路径。如果本参数值为空,则表示希望通过strItemBarcode参数来找到册记录 // return: // -1 error // 0 册条码号没有找到对应的册记录 // 1 成功 int ModifyEntityRecord( // RmsChannelCollection Channels, RmsChannel channel, string strEntityRecPath, string strItemBarcode, string strReaderBarcode, string strBorrowDate, string strBorrowPeriod, out string strError) { strError = ""; int nRet = 0; long lRet = 0; int nRedoCount = 0; if (String.IsNullOrEmpty(strItemBarcode) == true) { strError = "strItemBarcode参数不能为空"; return -1; } // RmsChannel channel = null; REDO_CHANGE: string strOutputItemRecPath = ""; byte[] item_timestamp = null; string strItemXml = ""; List<string> aPath = null; #if NO if (channel == null) { channel = Channels.GetChannel(this.WsUrl); if (channel == null) { strError = "get channel error"; return -1; } } #endif if (String.IsNullOrEmpty(strEntityRecPath) == false) { string strStyle = "content,data,metadata,timestamp,outputpath"; string strMetaData = ""; lRet = channel.GetRes(strEntityRecPath, strStyle, out strItemXml, out strMetaData, out item_timestamp, out strOutputItemRecPath, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) { return 0; } strError = "ModifyEntityRecord()通过册记录路径 '"+strEntityRecPath+"' 读入册记录时发生错误: " + strError; return -1; } } else { // 从册条码号获得册记录 // return: // -1 error // 0 not found // 1 命中1条 // >1 命中多于1条 nRet = this.GetItemRecXml( // Channels, channel, strItemBarcode, out strItemXml, 100, out aPath, out item_timestamp, out strError); if (nRet == 0) { // 册条码号不存在也是需要修复的情况之一。 return 0; } if (nRet == -1) { strError = "ModifyEntityRecord()读入册记录时发生错误: " + strError; return -1; } if (aPath.Count > 1) { // TODO: 需要将入围的记录全部提取出来,然后看borrower符合读者证条码号的那一条(或者多条?) // 可以参考UpgradeDt1000Loan中的SearchEntityRecord()函数 /* strError = "因册条码号 '" + strItemBarcode + "' 检索命中多条册记录: " + StringUtil.MakePathList(aPath) + ",修改册记录的操作ModifyEntityRecord()无法进行"; return -1; * */ int nSuccessCount = 0; string strTempError = ""; // 递归 for (int i = 0; i < aPath.Count; i++) { string strTempPath = aPath[i]; if (String.IsNullOrEmpty(strTempPath) == true) { Debug.Assert(false, ""); continue; } // return: // -1 error // 0 册条码号没有找到对应的册记录 // 1 成功 nRet = ModifyEntityRecord( // Channels, channel, strTempPath, strItemBarcode, strReaderBarcode, strBorrowDate, strBorrowPeriod, out strError); if (nRet == -1 && nSuccessCount == 0) { if (String.IsNullOrEmpty(strTempError) == false) strTempError += "; "; strTempError += "试探册记录 '" + strTempPath + "' 时发生错误: " + strError; } if (nRet == 1) { // 改为存储成功信息 if (nSuccessCount == 0) strTempError = ""; if (String.IsNullOrEmpty(strTempError) == false) strTempError += "; "; strTempError += strTempPath; nSuccessCount++; } } if (nSuccessCount > 0) { strError = "册条码号 '" + strItemBarcode + "' 检索命中" + aPath.Count.ToString() + "条册记录: " + StringUtil.MakePathList(aPath) + ",后面对它们进行了逐条试探,有 " + nSuccessCount.ToString() + " 条记录符合预期的要求,册中借阅信息得到增强。借阅信息得到增强的册记录路径如下: " + strTempError; return 1; } else { strError = "册条码号 '" + strItemBarcode + "' 检索命中" + aPath.Count.ToString() + "条册记录: " + StringUtil.MakePathList(aPath) + ",后面对它们进行了逐条试探,但是没有一条记录符合预期的要求。试探过程报错如下: " + strTempError; return -1; } /* result.Value = -1; result.ErrorInfo = "册条码号为 '" + strItemBarcode + "' 的册记录有 " + aPath.Count.ToString() + " 条,无法进行修复操作。请在附加册记录路径后重新提交修复操作。"; result.ErrorCode = ErrorCode.ItemBarcodeDup; aDupPath = new string[aPath.Count]; aPath.CopyTo(aDupPath); return result; * */ } else { Debug.Assert(nRet == 1, ""); Debug.Assert(aPath.Count == 1, ""); if (nRet == 1) { strOutputItemRecPath = aPath[0]; } } } XmlDocument itemdom = null; nRet = LibraryApplication.LoadToDom(strItemXml, out itemdom, out strError); if (nRet == -1) { strError = "装载册记录进入XML DOM时发生错误: " + strError; return -1; } // 校验册条码号参数是否和XML记录中完全一致 string strTempItemBarcode = DomUtil.GetElementText(itemdom.DocumentElement, "barcode"); if (strItemBarcode != strTempItemBarcode) { strError = "修改册记录ModifyEntityRecord()操作被拒绝。因册条码号参数 '" + strItemBarcode + "' 和册记录中<barcode>元素内的册条码号值 '" + strTempItemBarcode + "' 不一致。"; return -1; } // 看看册记录中是否有指回读者记录的链 string strBorrower = DomUtil.GetElementText(itemdom.DocumentElement, "borrower"); if (strBorrower != strReaderBarcode) { // strError = "ModifyEntityRecord()操作被拒绝。您所请求要修复的链,本是一条完整正确的链。可直接进行普通还书操作。"; strError = "修改册记录ModifyEntityRecord()操作被拒绝。因册记录 " + strOutputItemRecPath + " 中的[borrower]值 '" + strBorrower + "' 和发源(来找册条码号 '" + strItemBarcode + "')的读者证条码号 '" + strReaderBarcode + "' 不一致,不能构成一条完整正确的链。请及时排除此故障。"; return -1; } // 2007/1/1注:应当看看记录中<borrower>元素是否有内容才改写<borrowDate>和<borrowPeriod>元素。 DomUtil.SetElementText(itemdom.DocumentElement, "borrowDate", strBorrowDate); DomUtil.SetElementText(itemdom.DocumentElement, "borrowPeriod", strBorrowPeriod); #if NO if (channel == null) { channel = Channels.GetChannel(this.WsUrl); if (channel == null) { strError = "get channel error"; return -1; } } #endif byte[] output_timestamp = null; string strOutputPath = ""; // 写回册记录 lRet = channel.DoSaveTextRes(strOutputItemRecPath, itemdom.OuterXml, false, "content", // ,ignorechecktimestamp item_timestamp, out output_timestamp, out strOutputPath, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.TimestampMismatch) { nRedoCount++; if (nRedoCount > 10) { strError = "ModifyEntityRecord()写回册记录的时候,遇到时间戳冲突,并因此重试10次,仍失败..."; return -1; } goto REDO_CHANGE; } return -1; } // end of 写回册记录失败 return 1; }
// 获得一行信息 int GetLineInfo( RmsChannel channel, string strPath, out string strSender, out string strRecipient, out string strSubject, out string strDate, out string strSize, out bool bTouched, out string strError) { strSender = ""; strRecipient = ""; strSubject = ""; strDate = ""; strSize = ""; bTouched = false; strError = ""; // 将种记录数据从XML格式转换为HTML格式 string strMetaData = ""; byte[] timestamp = null; string strXml = ""; string strOutputPath = ""; long lRet = channel.GetRes(strPath, out strXml, out strMetaData, out timestamp, out strOutputPath, out strError); if (lRet == -1) { // text-level: 内部错误 strError = "获得消息记录 '" + strPath + "' 时出错: " + strError; return -1; } XmlDocument dom = new XmlDocument(); try { dom.LoadXml(strXml); } catch (Exception ex) { // text-level: 内部错误 strError = "装载XML记录进入DOM时出错: " + ex.Message; return -1; } strSender = DomUtil.GetElementText(dom.DocumentElement, "sender"); strRecipient = DomUtil.GetElementText(dom.DocumentElement, "recipient"); strSubject = DomUtil.GetElementText(dom.DocumentElement, "subject"); strDate = DomUtil.GetElementText(dom.DocumentElement, "date"); strDate = DateTimeUtil.LocalTime(strDate); strSize = DomUtil.GetElementText(dom.DocumentElement, "size"); string strTouched = DomUtil.GetElementText(dom.DocumentElement, "touched"); if (strTouched == "1") bTouched = true; else bTouched = false; return 0; }
// TODO: 是否检查流通信息,需要可以通过参数控制 // 检索书目记录下属的事项记录,返回少量必要的信息,可以提供后面实做删除时使用 // parameters: // strStyle return_record_xml 要在DeleteEntityInfo结构中返回OldRecord内容 // check_circulation_info 检查是否具有流通信息。如果具有则会报错 2012/12/19 把缺省行为变为此参数 // 当包含 limit: 时,定义最多取得记录的个数。例如希望最多取得 10 条,可以定义 limit:10 // return: // -1 error // 0 not exist item dbname // 1 exist item dbname public int SearchChildItems(RmsChannel channel, string strBiblioRecPath, string strStyle, DigitalPlatform.LibraryServer.LibraryApplication.Delegate_checkRecord procCheckRecord, object param, out long lHitCount, out List<DeleteEntityInfo> entityinfos, out string strError) { strError = ""; lHitCount = 0; entityinfos = new List<DeleteEntityInfo>(); int nRet = 0; bool bReturnRecordXml = StringUtil.IsInList("return_record_xml", strStyle); bool bCheckCirculationInfo = StringUtil.IsInList("check_circulation_info", strStyle); bool bOnlyGetCount = StringUtil.IsInList("only_getcount", strStyle); string strLimit = StringUtil.GetParameterByPrefix(strStyle, "limit", ":"); string strBiblioDbName = ResPath.GetDbName(strBiblioRecPath); string strBiblioRecId = ResPath.GetRecordId(strBiblioRecPath); // 获得书目库对应的事项库名 string strItemDbName = ""; nRet = this.GetItemDbName(strBiblioDbName, out strItemDbName, out strError); if (nRet == -1) goto ERROR1; if (String.IsNullOrEmpty(strItemDbName) == true) return 0; // 检索实体库中全部从属于特定id的记录 string strQueryXml = "<target list='" + StringUtil.GetXmlStringSimple(strItemDbName + ":" + "父记录") + "'><item><word>" + strBiblioRecId + "</word><match>exact</match><relation>=</relation><dataType>string</dataType><maxCount>-1</maxCount></item><lang>" + "zh" + "</lang></target>"; long lRet = channel.DoSearch(strQueryXml, "entities", "", // strOuputStyle out strError); if (lRet == -1) goto ERROR1; if (lRet == 0) { strError = "没有找到属于书目记录 '" + strBiblioRecPath + "' 的任何" + this.ItemName + "记录"; return 0; } lHitCount = lRet; // 仅返回命中条数 if (bOnlyGetCount == true) return 0; int nResultCount = (int)lRet; int nMaxCount = 10000; if (nResultCount > nMaxCount) { strError = "命中" + this.ItemName + "记录数 " + nResultCount.ToString() + " 超过 " + nMaxCount.ToString() + ", 暂时不支持针对它们的删除操作"; goto ERROR1; } string strColumnStyle = "id,xml,timestamp"; int nLimit = -1; if (string.IsNullOrEmpty(strLimit) == false) Int32.TryParse(strLimit, out nLimit); int nStart = 0; int nPerCount = 100; if (nLimit != -1 && nPerCount > nLimit) nPerCount = nLimit; for (; ; ) { #if NO List<string> aPath = null; lRet = channel.DoGetSearchResult( "entities", nStart, nPerCount, "zh", null, out aPath, out strError); if (lRet == -1) goto ERROR1; if (aPath.Count == 0) { strError = "aPath.Count == 0"; goto ERROR1; } #endif Record[] searchresults = null; lRet = channel.DoGetSearchResult( "entities", nStart, nPerCount, strColumnStyle, "zh", null, out searchresults, out strError); if (lRet == -1) goto ERROR1; if (searchresults == null) { strError = "searchresults == null"; goto ERROR1; } if (searchresults.Length == 0) { strError = "searchresults.Length == 0"; goto ERROR1; } // 获得每条记录 // for (int i = 0; i < aPath.Count; i++) int i = 0; foreach (Record record in searchresults) { string strMetaData = ""; string strXml = ""; byte[] timestamp = null; string strOutputPath = ""; DeleteEntityInfo entityinfo = new DeleteEntityInfo(); if (record.RecordBody == null || string.IsNullOrEmpty(record.RecordBody.Xml) == true) { // TODO: 这里需要改造为直接从结果集中获取 xml,timestamp lRet = channel.GetRes(record.Path, out strXml, out strMetaData, out timestamp, out strOutputPath, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) continue; strError = "获取" + this.ItemName + "记录 '" + record.Path + "' 时发生错误: " + strError; goto ERROR1; // goto CONTINUE; } } else { strXml = record.RecordBody.Xml; strOutputPath = record.Path; timestamp = record.RecordBody.Timestamp; } entityinfo.RecPath = strOutputPath; entityinfo.OldTimestamp = timestamp; if (bReturnRecordXml == true) entityinfo.OldRecord = strXml; if (bCheckCirculationInfo == true || procCheckRecord != null) { // 检查是否有借阅信息 // 把记录装入DOM XmlDocument domExist = new XmlDocument(); try { domExist.LoadXml(strXml); } catch (Exception ex) { strError = this.ItemName + "记录 '" + record.Path + "' 装载进入DOM时发生错误: " + ex.Message; goto ERROR1; } // 2016/11/15 if (procCheckRecord != null) { nRet = procCheckRecord( nStart + i, strOutputPath, domExist, timestamp, param, out strError); if (nRet != 0) return nRet; } /* entityinfo.ItemBarcode = DomUtil.GetElementText(domExist.DocumentElement, "barcode"); * */ // TODO: 在日志恢复阶段调用本函数时,是否还有必要检查是否具有流通信息?似乎这时应强制删除为好 // 观察已经存在的记录是否有流通信息 // return: // -1 出错 // 0 没有 // 1 有。报错信息在strError中 nRet = this.HasCirculationInfo(domExist, out strError); if (nRet == -1) goto ERROR1; if (nRet == 1) { strError = "拟删除的" + this.ItemName + "记录 '" + entityinfo.RecPath + "' 中" + strError + "(此种情况可能不限于这一条),不能删除。因此全部删除操作均被放弃。"; goto ERROR1; } } // CONTINUE: entityinfos.Add(entityinfo); i++; } nStart += searchresults.Length; if (nStart >= nResultCount) break; if (nLimit != -1 && nStart >= nLimit) break; } return 1; ERROR1: return -1; }