dp2 icon indicating copy to clipboard operation
dp2 copied to clipboard

常用的MarcQuery脚本集锦

Open lunvo opened this issue 6 years ago • 46 comments

MarcQuery 脚本使用方法 https://github.com/DigitalPlatform/dp2/wiki/MarcQuery-脚本使用方法

MarcQuery 函数库的参考手册:http://dp2003.com/marcquery/

如何在 dp2catalog 中执行 MarcQuery 脚本? https://github.com/DigitalPlatform/dp2/issues/344

lunvo avatar Feb 19 '19 04:02 lunvo

清空 606$a 子字段内容(dp2circulation)

using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Forms;
using System.IO;
using System.Text;
using System.Xml;
using dp2Circulation;
using DigitalPlatform.Marc;
using DigitalPlatform.Xml;
using DigitalPlatform.Script;
public class MyMarcQueryHost : MarcQueryHost
{
    public override void OnRecord(object sender, StatisEventArgs e)
    {
        // 先检索出606$a子字段
        MarcNodeList subfields = this.MarcRecord.select("field[@name='606']/subfield[@name='a']");
        foreach (MarcNode node in subfields)
        {
            node.Content = ""; // 将606$a子字段内容设为空
            this.Changed = true;  //将这条记录标识修改状态,这样后面可以保存修改。
        }
    }
}

renyh avatar Apr 22 '19 07:04 renyh

删除 606$a 子字段

using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Forms;
using System.IO;
using System.Text;
using System.Xml;

using dp2Circulation;

using DigitalPlatform.Marc;
using DigitalPlatform.Xml;
using DigitalPlatform.Script;

public class MyMarcQueryHost : MarcQueryHost
{
    public override void OnRecord(object sender, StatisEventArgs e)
    {
        MarcNodeList subfields = this.MarcRecord.select("field[@name='606']/subfield[@name='a']");
        foreach (MarcNode node in subfields)
        {
            node.detach();   // 删除子字段
            this.Changed = true;
        }
    }
}

DigitalPlatform avatar Apr 22 '19 07:04 DigitalPlatform

新增一个 801 字段

下面代码可以给 MARC 记录无条件新增一个 801 字段:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Forms;
using System.IO;
using System.Text;
using System.Xml;

using dp2Circulation;

using DigitalPlatform.Marc;
using DigitalPlatform.Xml;
using DigitalPlatform.Script;

public class MyMarcQueryHost : MarcQueryHost
{
    public override void OnRecord(object sender, StatisEventArgs e)
    {
	this.MarcRecord.ChildNodes.insertSequence(new MarcField('$', "801  $aCN$bNLC"));
	this.Changed = true;
    }
}

而如果是当 801 字段存在的时候修改它,不存在的时候新增一个 801,可以这样写:

    public override void OnRecord(object sender, StatisEventArgs e)
    {
	MarcNodeList fields = this.MarcRecord.select("field[@name='801']");
	if (fields.count >0)
	{
		MarcNodeList subfields = fields[0].select("subfield[@name='a']");
		if (subfields.count > 0)
			subfields.Content = "CN";
		else
			fields[0].ChildNodes.insertSequence(new MarcSubfield("a", "CN"));

		subfields = fields[0].select("subfield[@name='b']");
		if (subfields.count > 0)
			subfields.Content = "NLC";
		else
			fields[0].ChildNodes.insertSequence(new MarcSubfield("b", "NLC"));
	}
	else
		this.MarcRecord.ChildNodes.insertSequence(new MarcField('$', "801  $aCN$bNLC"));

	this.Changed = true;
    }

这段代码比较复杂。

考虑到这种“有了一个字段(子字段)就修改它,没有就新增一个”的需求特别常见,MarcQuery 甚至提供了一个专门的 setFirstField() 或者 setFirstSubfield() 函数: 注:这一段脚本暴露了当前 MarcQuery 函数库一个 bug

    public override void OnRecord(object sender, StatisEventArgs e)
    {
	this.MarcRecord.setFirstSubfield("801", "a", "CN", "  ");
	this.MarcRecord.setFirstSubfield("801", "b", "NLC", "  ");

	this.Changed = true;
    }

(MarcRecord类)setFirstSubfield() 函数原型如下:

        /// <summary>
        /// 设置指定名字的第一个字段和第一个子字段的值。如果没有这个字段,则创建一个;如果没有这个子字段,则创建一个
        /// </summary>
        /// <param name="strFieldName">字段名。3字符</param>
        /// <param name="strSubfieldName">子字段名。1字符</param>
        /// <param name="strContent">要设置的子字段内容</param>
        /// <param name="strNewIndicator">如果指定的字段不存在,则需要创建,创建的时候将采用本参数作为字段指示符的值</param>
        public void setFirstSubfield(
            string strFieldName,
            string strSubfieldName,
            string strContent,
            string strNewIndicator = "  ")

DigitalPlatform avatar Apr 22 '19 07:04 DigitalPlatform

在MARC记录的998$s子字段作标识 (dp2circulation)

using System;
using System.Windows.Forms;

using dp2Circulation;
using DigitalPlatform.Marc;
using DigitalPlatform.Text;

public class add998s : MarcQueryHost
{
    public override void OnRecord(object sender, StatisEventArgs e)
    {
        string value = "***"; //这里输入标识值

        // 先检索出998字段
        MarcNodeList fields = this.MarcRecord.select("field[@name=998]");
        // 如果不存在998字段,直接增加998  $s
        if (fields.count == 0)
        {
            this.MarcRecord.append(String.Format("998  {0}s{1}", MarcQuery.SUBFLD, value));
            this.Changed = true;
            return;
        }

        // 取第一个998节点的$s子字段
        MarcNode node = fields[0];
        MarcNodeList subfields = node.select("subfield[@name='s']");
        // 如果没有$s子字段,增加998  $s
        if (subfields.count == 0)
        {
            node.append(String.Format("{0}s{1}", MarcQuery.SUBFLD, value));
            this.Changed = true;
            return;
        }
       // 取第一个998$s子字段
        MarcNode sNode = subfields[0];
        string sContent= sNode.Content;
        string old = sContent; //值
        StringUtil.SetInList(ref sContent, value, true); //新值

        //MessageBox.Show("old="+old +" new=" + sContent);
       // 如果新旧值不等,标记为修改状态
        if (old != sContent)
        {
            sNode.Content = sContent;
            this.Changed = true;
            return;
        }
    }
}

DigitalPlatform.Text.dll 的 SetInList()函数


        // 在列举值中增加或清除一个值
        // parameters:
        //      strSub  里面可以包含多个值
        public static void SetInList(ref string strList,
            string strSub,
            bool bOn)
        {
            if (bOn == false)
            {
                RemoveFromInList(strSub,
                    true,
                    ref strList);
            }
            else
            {
                // 单个值的情况
                if (strSub.IndexOf(',') == -1)
                {
                    if (IsInList(strSub, strList) == true)
                        return;	// 已经有了

                    // 在尾部新增加
                    if (string.IsNullOrEmpty(strList) == false)
                        strList += ",";

                    strList += strSub;
                    return;
                }

                // 2012/2/2
                // 多个值的情况
                string[] sub_parts = strSub.Split(new char[] { ',' });
                foreach (string sub in sub_parts)
                {
                    if (sub == null)
                        continue;

                    string strOne = sub.Trim();
                    if (string.IsNullOrEmpty(strOne) == true)
                        continue;

                    if (IsInList(strOne, strList) == true)
                        continue;	// 已经有了

                    // 在尾部新增加
                    if (string.IsNullOrEmpty(strList) == false)
                        strList += ",";

                    strList += strOne;
                }
            }
        }


补充一下:上面的 MarcQuery 脚本可以作为一个很好的培训练习题材。示范在内务书目查询窗中,如何二次开发 MarcQuery 脚本。 但就“修改书目记录 998$s” 这个功能来说,内务的书目查询窗内是本来就有这个功能的。即浏览列表中上下文菜单中的“快速修改书目记录”功能。这个功能挺完备的,它可以为 998$s 添加或者去掉一个子串,而保留其他子串。 注:998$s 内容,也就是书目记录的“状态”字段,里面可以是这样的形态“子串1,子串2”。

原贴地址 https://github.com/DigitalPlatform/dp2/issues/229

renyh avatar Apr 22 '19 07:04 renyh

输出到 Excel 文件(用 ClosedXML 函数库实现)

创建一个名为 output_excel.cs 的文件:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Forms;
using System.IO;
using System.Text;
using System.Xml;

using dp2Circulation;

using DigitalPlatform;
using DigitalPlatform.Core;
using DigitalPlatform.Marc;
using DigitalPlatform.Xml;
using DigitalPlatform.Script;

using ClosedXML.Excel;

public class MyMarcQueryHost : MarcQueryHost
{
    SaveFileDialog dlg = new SaveFileDialog();
    XLWorkbook doc = null;
    IXLWorksheet sheet = null;
    int nRowIndex = 1;  // 行号

    public override void OnBegin(object sender, StatisEventArgs e)
    {
        // 询问文件名
        dlg.Title = "请指定要输出的 Excel 文件名";
        dlg.CreatePrompt = false;
        dlg.OverwritePrompt = true;
        dlg.Filter = "Excel 文件 (*.xlsx)|*.xlsx|All files (*.*)|*.*";

        dlg.RestoreDirectory = true;

        if (dlg.ShowDialog() != DialogResult.OK)
        {
            e.Continue = ContinueType.SkipAll;
            return;
        }

        try
        {
            doc = new XLWorkbook(XLEventTracking.Disabled);
            File.Delete(dlg.FileName);
        }
        catch (Exception ex)
        {
            e.ParamString = ExceptionUtil.GetAutoText(ex);
            e.Continue = ContinueType.Error;
            return;
        }

        sheet = doc.Worksheets.Add("表格");

        // 输出标题行
        {
            int nColIndex = 1;  // 列号

            sheet.Cell(nRowIndex, nColIndex++).SetValue("title");

            sheet.Cell(nRowIndex, nColIndex++).SetValue("author");

            sheet.Cell(nRowIndex, nColIndex++).SetValue("publisher");

            sheet.Cell(nRowIndex, nColIndex++).SetValue("publish time");

            nRowIndex++;
        }
    }

    public override void OnRecord(object sender, StatisEventArgs e)
    {
        int nColIndex = 1;  // 列号

        string title = this.MarcRecord.select("field[@name='200']/subfield[@name='a']").FirstContent;
        sheet.Cell(nRowIndex, nColIndex++).SetValue(title);

        string author = this.MarcRecord.select("field[@name='200']/subfield[@name='f']").FirstContent;
        sheet.Cell(nRowIndex, nColIndex++).SetValue(author);

        string publisher = this.MarcRecord.select("field[@name='210']/subfield[@name='c']").FirstContent;
        sheet.Cell(nRowIndex, nColIndex++).SetValue(publisher);

        string publish_time = this.MarcRecord.select("field[@name='210']/subfield[@name='d']").FirstContent;
        sheet.Cell(nRowIndex, nColIndex++).SetValue(publish_time);

        nRowIndex++;
    }

    public override void OnEnd(object sender, StatisEventArgs e)
    {
        doc.SaveAs(dlg.FileName);
        doc.Dispose();

        try
        {
            System.Diagnostics.Process.Start(dlg.FileName);
        }
        catch
        {

        }
    }
}

还要创建一个名为 output_excel.cs.ref 的文件: (和上面的文件一起,两个文件要处于同一个文件夹)

<?xml version="1.0" encoding="utf-8"?>
<root>
  <ref>system.data.dll</ref>
  <ref>%bindir%/ClosedXml.dll</ref>
</root>

ClosedXML 是一个开源的 Excel 处理函数库,在这里: https://github.com/ClosedXML/ClosedXML

它的 wiki: https://github.com/ClosedXML/ClosedXML/wiki

DigitalPlatform avatar Apr 22 '19 15:04 DigitalPlatform

主题词字段一些疑问:606内容$a心理学$x论文$x写作$x心理$j指南 甚至有更多个$x,我想修改某个$x的内容如何实现?

distinct2010 avatar May 15 '19 03:05 distinct2010

00666nam0 2200229 450_ 001008859384 00520180217001401.0 010 ǂa978-7-5596-0929-8ǂb精装ǂdCNY68.00 100 ǂa20180217d2017 em y0chiy0110 ea 1010 ǂachi 102 ǂaCNǂb110000 105 ǂaa z 000yb 106 ǂar 2001 ǂa颠覆者ǂ9dian fu zheǂdǂe周鸿祎自传ǂf周鸿祎,范海涛著ǂgǂhǂi 210 ǂa北京ǂc北京联合出版公司ǂd2017 215 ǂa377页ǂdǂe 6060 ǂa互联网络ǂx企业家ǂx生平事迹ǂx互联网商业ǂx个人创业经历ǂy中国ǂz现代 690 ǂaK825.38=76ǂv5 701 0ǂa周鸿祎ǂ9zhou hong yiǂ4著 701 0ǂa范海涛ǂ9fan hai taoǂ4著 801 0ǂaCNǂb91MARCǂc20180217 998 ǂu2018-08-09 13:17:39Zǂzsupervisor


比如这条数据,我想要修改606的第三个$x内容 如果能够实现对606这个字段下面的所有子字段逐个进行修改时最好的,因为主题词字段多种多样,除了$a,$x还有$j$y$z等这样的

distinct2010 avatar May 15 '19 04:05 distinct2010

@distinct2010

using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Forms;
using System.IO;
using System.Text;
using System.Xml;

using dp2Circulation;

using DigitalPlatform.Marc;
using DigitalPlatform.Xml;
using DigitalPlatform.Script;

public class MyMarcQueryHost : MarcQueryHost
{
	public override void OnRecord(object sender, StatisEventArgs e)
	{
		var fields = this.MarcRecord.select("field[@name='606']");
		foreach(MarcField field in fields)
		{
			var subfields =field.select("subfield[@name='x']");
			// 修改第三个 $x 子字段内容(注意代码里面下标是从 0 开始的)
			if (subfields.count > 2)
			{
				subfields[2].Content += "---";
				this.Changed = true;
			}
		}
	}
}

DigitalPlatform avatar May 15 '19 04:05 DigitalPlatform

前面的描述不太清楚,给定一个606字段,606字段的所有自字段内容是fields[0].ChildNodes.Contents[i] 现在有个数组,通过循环修改每个子字段内容

distinct2010 avatar May 15 '19 09:05 distinct2010

@distinct2010

using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Forms;
using System.IO;
using System.Text;
using System.Xml;

using dp2Circulation;

using DigitalPlatform.Marc;
using DigitalPlatform.Xml;
using DigitalPlatform.Script;

public class MyMarcQueryHost : MarcQueryHost
{
	public override void OnRecord(object sender, StatisEventArgs e)
	{
		var fields = this.MarcRecord.select("field[@name='606']");
		foreach(MarcField field in fields)
		{
			int i = 0;
			foreach(MarcSubfield subfield in field.ChildNodes)
			{
				subfield.Content = (i++).ToString();
				this.Changed = true;
			} 
		}
	}
}

DigitalPlatform avatar May 15 '19 09:05 DigitalPlatform

//开始删除设置字段 MarcRecord records = new MarcRecord(this.strMarc); string[] DelFields = Settings.Default.DeleteField.Split(','); foreach (string DelField in DelFields) { if (DelField.Length == 3) { MarcNodeList fields = records.select("field[@name='" + DelField + "']"); foreach (MarcNode node in fields) { node.detach(); } } else if (DelField.Length == 4) { string zd = DelField.Substring(0, 3); string zzd = DelField.Substring(3, 1); MarcNodeList subfields = records.select("field[@name='" + zd + "']/subfield[@name='" + zzd + "']"); foreach (MarcNode node in subfields) { node.detach(); } } else { MessageBox.Show("删除字段配置项:" + DelField + " 有误!"); } }

报错:此时FocusedField不可能为null

distinct2010 avatar May 19 '19 04:05 distinct2010

@distinct2010

上面您给出的代码不完整,没法验证运行。请提供完整的、能在 dp2circulation 或 dp2catalog 中运行的脚本文件内容。

DigitalPlatform avatar May 20 '19 01:05 DigitalPlatform

插入若干个同名字段

插入到同名字段的后方:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Forms;
using System.IO;
using System.Text;
using System.Xml;

using dp2Circulation;

using DigitalPlatform.Marc;
using DigitalPlatform.Xml;
using DigitalPlatform.Script;

public class MyMarcQueryHost : MarcQueryHost
{
	public override void OnRecord(object sender, StatisEventArgs e)
	{
		for(int i =0;i<10;i++)
		{
			this.MarcRecord.ChildNodes.insertSequence(new MarcField('$', "801  $aCN"+i.ToString()+"$bNLC"), InsertSequenceStyle.PreferTail);
			this.Changed = true;
		}
	}
}

注意 insertSequence() 函数的第二参数是指定同名字段插入时候的相对位置关系。InsertSequenceStyle.PreferTail 表示插入在同名字段的后面。这个参数可以缺省,默认为 InsertSequenceStyle.PreferHead,也就是插入到同名字段的前面。

其实只要看看 MarcQuery 代码关于这个函数的原型就能发现这个参数。这个函数还有其他参数的版本。

DigitalPlatform avatar Jun 18 '19 17:06 DigitalPlatform

按照字段名(数字)大小对字段进行排序

using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Forms;
using System.IO;
using System.Text;
using System.Xml;

using dp2Circulation;

using DigitalPlatform.Marc;
using DigitalPlatform.Xml;
using DigitalPlatform.Script;

public class MyMarcQueryHost : MarcQueryHost
{
	public override void OnRecord(object sender, StatisEventArgs e)
	{
		this.MarcRecord.ChildNodes.sort((a, b)=>{
			return string.Compare(a.Name, b.Name);
		});
		this.Changed = true;
	}
}

sort() 函数接受一个回调函数。回调函数只需要比较 a 和 b 两个 MarcNode 对象的大小即可,返回一个整数。整数如何返回呢?可以简单理解为 a - b 的值。如果 a 小于 b,那么应该返回负数;相等应该返回 0,a 大于 b 则应该返回一个正数。

DigitalPlatform avatar Jun 18 '19 17:06 DigitalPlatform

按照字段指示符大小对字段进行排序

using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Forms;
using System.IO;
using System.Text;
using System.Xml;

using dp2Circulation;

using DigitalPlatform.Marc;
using DigitalPlatform.Xml;
using DigitalPlatform.Script;

public class MyMarcQueryHost : MarcQueryHost
{
	public override void OnRecord(object sender, StatisEventArgs e)
	{
		this.MarcRecord.ChildNodes.sort((a, b)=>{
			return string.Compare(a.Indicator, b.Indicator);
		});
		this.Changed = true;
	}
}

当然,这个例子没有啥实际意义,只是示范一下如何自由决定排序因素。

DigitalPlatform avatar Jun 18 '19 17:06 DigitalPlatform

把 909 字段里面的 $b 子字段复制到一个 905 字段中

using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Forms;
using System.IO;
using System.Text;
using System.Xml;

using dp2Circulation;

using DigitalPlatform.Marc;
using DigitalPlatform.Xml;
using DigitalPlatform.Script;

public class MyMarcQueryHost : MarcQueryHost
{
	public override void OnRecord(object sender, StatisEventArgs e)
	{
                // 制造出若干 909 字段
		for(int i =0;i<10;i++)
		{
			this.MarcRecord.ChildNodes.insertSequence(new MarcField('$', "909  $aCN"+i.ToString()+"$bB" + i.ToString()), InsertSequenceStyle.PreferTail);
			this.Changed = true;
		}

                // 新添加一个 905 字段
		MarcField field = new MarcField('$', "905  $atest");
		this.MarcRecord.ChildNodes.insertSequence(field, InsertSequenceStyle.PreferTail);

                // 选择和复制 909$b 子字段,复制到刚才的 905 字段中
		MarcNodeList subfields = this.MarcRecord.select("field[@name='909']/subfield[@name='b']");
		foreach(MarcSubfield subfield in subfields)
		{
			field.ChildNodes.insertSequence(subfield.clone(), InsertSequenceStyle.PreferTail);
		}
	}
}

DigitalPlatform avatar Jun 18 '19 18:06 DigitalPlatform

删除所有9**字段如何实现?

distinct2010 avatar Jun 23 '19 02:06 distinct2010

删除所有 9XX 字段

using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Forms;
using System.IO;
using System.Text;
using System.Xml;

using dp2Circulation;

using DigitalPlatform.Marc;
using DigitalPlatform.Xml;
using DigitalPlatform.Script;

public class MyMarcQueryHost : MarcQueryHost
{
	public override void OnRecord(object sender, StatisEventArgs e)
	{
		this.MarcRecord.select("field[substring(@name,1,1)='9']").detach();
		this.Changed = true;
	}
}

注意 XPath 的 substring() 函数第二参数 offset 是从 1 开始计数的,比较坑人。

DigitalPlatform avatar Jun 23 '19 03:06 DigitalPlatform

原来 BBS 里面 http://dp2003.com/dp2bbs/article.aspx?board=@__3&id=71 其中的代码修订以后放在这里:

第一个

using System.Collections;
using System.Collections.Generic;
using System.Windows.Forms;
using System.IO;
using System.Text;
using System.Xml;

using dp2Catalog;

using DigitalPlatform.Marc;
using DigitalPlatform.Xml;
using DigitalPlatform.Script;

public class MyMarcQueryHost : MarcQueryHost
{
	public override void OnRecord(object sender, StatisEventArgs e)
	{
        		this.MarcRecord.ChildNodes.add(new MarcField("200", "  ",SUBFLD + "aAAAA"));
        		this.MarcRecord.ChildNodes.add(new MarcField("300", "  ", SUBFLD + "bBBBB"));
        
        		MarcNodeList nodes = this.MarcRecord.select("field[@name='200']");

        		MessageBox.Show(this.MainForm, nodes.count.ToString());

        		this.Changed = true;
	}
}

第二个:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Forms;
using System.IO;
using System.Text;
using System.Xml;

using dp2Catalog;

using DigitalPlatform.Marc;
using DigitalPlatform.Xml;
using DigitalPlatform.Script;

public class MyMarcQueryHost : MarcQueryHost
{
	public override void OnRecord(object sender, StatisEventArgs e)
	{
        		this.MarcRecord.ChildNodes.add(new MarcField("200", "  ",SUBFLD + "aAAAA"));
        		this.MarcRecord.ChildNodes.add(new MarcField("300", "  ", SUBFLD + "bBBBB"));
        
        		MarcNodeList nodes = this.MarcRecord.select("field[@name='200']");
       		        nodes.first().Name = "999";    // 修改了第一个200字段的字段名
        		this.Changed = true;
	}
}

DigitalPlatform avatar Dec 10 '19 08:12 DigitalPlatform

如何修改头标区和指示符呢?

distinct2010 avatar May 04 '20 04:05 distinct2010

如何修改头标区

using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Forms;
using System.IO;
using System.Text;
using System.Xml;

using dp2Circulation;

using DigitalPlatform.Marc;
using DigitalPlatform.Xml;
using DigitalPlatform.Script;

public class MyMarcQueryHost : MarcQueryHost
{
	public override void OnRecord(object sender, StatisEventArgs e)
	{
		this.MarcRecord.Header[0, 5] = "77888";
		this.MarcRecord.Header[5, 1] = "!";
		this.Changed = true;
	}
}

DigitalPlatform avatar May 04 '20 11:05 DigitalPlatform

请高手写一个这样的脚本,把215▼a罗马数字转阿拉伯数字,例如,215▼axii,变成215▼a12,这是罗马小写的,另一种是罗马大写,例如215▼aVIII,也是转为215▼a8,非常感谢!

GUI9527 avatar Jul 01 '20 15:07 GUI9527

把 215$a 中的罗马数字替换为阿拉伯数字

下面脚本要在 dp2catalog 中执行。罗马数字替换为阿拉伯数字的函数未实现全部功能,只示范性替换了 xiii 这个罗马数字。

using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Forms;
using System.IO;
using System.Text;
using System.Xml;

using dp2Catalog;

using DigitalPlatform.Marc;
using DigitalPlatform.Xml;
using DigitalPlatform.Script;

public class MyMarcQueryHost : MarcQueryHost
{
	public override void OnRecord(object sender, StatisEventArgs e)
	{
		var subfields = this.MarcRecord.select("field[@name='215']/subfield[@name='a']");
		foreach(MarcSubfield subfield in subfields)
		{
			string content = subfield.Content;
			string new_content = ReplaceText(content);
			if (content != new_content)
			{
				subfield.Content = new_content;
				this.Changed = true;
			}
		}
	}

	// 把文本中的罗马数字部分替换为阿拉伯数字。未完成
	static string ReplaceText(string text)
	{
		if (string.IsNullOrEmpty(text))
			return text;
		// TODO: 这里需要实现变换功能
		return text.Replace("xiii", "13");
	}
}

DigitalPlatform avatar Jul 02 '20 00:07 DigitalPlatform

制作MARC21数据,常常需要转换一些字段内容,如020:$cCNY307.28(GBP29.99) [注:从v3编目marc记录窗复制▼到记事本变成了$,在复制$到记录窗没有变回▼],如何通过脚本把已经制作好的txt文件批加入,如文本文件制作好,9783944874593 :▼cCNY461.07(GBP45.00) [注:前面冒号必加] ,把▼c准确无误的加入对应数据020字段▼a9783944874593的后面

GUI9527 avatar Jul 02 '20 12:07 GUI9527

符号转化对应上了 9780190904913 :|cCNY266.29(GBP25.99) 9780190906801 :|cCNY491.71(GBP47.99) 9780190908904 :|cCNY655.74(GBP64.00) 9780190909376 :|cCNY563.53(GBP55.00) 9780190913151 :|cCNY491.71(GBP47.99)脚本如何写还是个问题?????????????????????????? 01331cam a2200325 i 4500 00120415204 00520190523125802.0 008180321s2018 nyu b 001 0 eng__ 010 ǂa 2018013235 020 ǂa9780190904913 (hardcover)【注:把文本文件内容或excel的:|cCNY266.29(GBP25.99)加到这里来】 020 ǂz9780190904920 (updf) 020 ǂz9780190904937 (ebook) 040 ǂaDLCǂbengǂcDLCǂerdaǂdDLC 042 ǂapcc 05000ǂaBJ71ǂb.P46 2018 08200ǂa170.9ǂ223 093 ǂa 1001 ǂaPettit, Philip,ǂd1945-ǂeauthor. 24514ǂaThe birth of ethics :ǂbreconstructing the role and nature of morality /ǂcPhilip Pettit ; with commentary by Michael Tomasello ; edited by Kinch Hoekstra. 260 1ǂa[New York, NY] :ǂbOxford University Press,ǂc[2018] 300 ǂavi, 387 pages ;ǂc22 cm 336 ǂatextǂbtxtǂ2rdacontent 337 ǂaunmediatedǂbnǂ2rdamedia 338 ǂavolumeǂbncǂ2rdacarrier 504 ǂaIncludes bibliographical references (pages 359-369) and index. 650 0ǂaEthicsǂxHistory. 7001 ǂaHoekstra, Kinch,ǂeeditor. 906 ǂa7ǂbcbcǂcorignewǂd1ǂeecipǂf20ǂgy-gencatlg 9250 ǂaacquireǂb1 shelf copyǂxpolicy default 955 ǂbrk14 2018-03-21ǂcrk14 2018-03-21 telework to subjǂdrk02 2018-05-11 to Dewey (telework)ǂwxm07 2018-05-11ǂaxn16 2018-12-17 1 copy rec'd., to CIP ver.ǂark20 2018-12-22ǂfrf10 2019-01-17 CIP ver. to CALM 997 ǂa9780190904913|reconstructing the role and nature of morality,The birth of ethics|Hoekstra, Kinch,Pettit, Philip|Oxford University Press,2018ǂhe92a372245c74f5067db151eddd22204ǂv0.03


GUI9527 avatar Jul 05 '20 01:07 GUI9527

删除所有的空字段和所有的空子字段如何实现?

distinct2010 avatar Aug 09 '20 14:08 distinct2010

dp2内务的种册窗,在MARC编辑器,右键 “整理“-”删除全部空字段”/“删除全部子字段”等一组命令

Hopeshine avatar Aug 10 '20 02:08 Hopeshine

如何从record中得到指定字段名的MarcField对象? record.select("field[@name='字段名']").firstcontent;强制转换为MarcField好像不行; foreach (MarcField Field in record.Fields) { Field.Name=字段名; } 只能用这种方式吗?

distinct2010 avatar Aug 17 '20 09:08 distinct2010

dp2内务的种册窗,在MARC编辑器中,单击“整理”-“删除全部空缺” /“删除全部子替换”等一组命令

MARC编辑器中,此命令是用MarcEdit中的命令完成的。 MarcQuery如何实现呢?

MarcNodeList Fields = record.ChildNodes;
            foreach (MarcNode Field in Fields)
            {
                MarcNodeList SubFields = Field.ChildNodes;
                foreach (MarcNode SubField in SubFields)
                {
                    if (string.IsNullOrEmpty(SubField.Content))
                    {
                        SubField.detach();
                    }
                }
                if (string.IsNullOrEmpty(Field.Content))
                {
                    Field.detach();
                }
            }
            return record;

这样是会报错的,因为foreach中集合已经被更新了

distinct2010 avatar Aug 18 '20 14:08 distinct2010

@distinct2010

这样是会报错的,因为foreach中集合已经被更新了

可以这样写:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Forms;
using System.IO;
using System.Text;
using System.Xml;

using dp2Circulation;

using DigitalPlatform.Marc;
using DigitalPlatform.Xml;
using DigitalPlatform.Script;

public class MyMarcQueryHost : MarcQueryHost
{
	public override void OnRecord(object sender, StatisEventArgs e)
	{

		var fields = new List<MarcNode>(this.MarcRecord.ChildNodes.List);   // 复制到一个新的集合
		foreach (var field in fields)
		{
			var subfields = new List<MarcNode>(field.ChildNodes.List);    // 复制到一个新的集合
			foreach (MarcNode subfield in subfields)
			{
				if (string.IsNullOrEmpty(subfield.Content))
				{
					subfield.detach();
					this.Changed = true;
				}
			}
			if (string.IsNullOrEmpty(field.Content))
			{
				field.detach();
				this.Changed = true;
			}
		}
	}
}

上面这个写法,是把 ChildNodes 复制到一个新的集合中(代码中的 fields 或者 subfields),对新的集合进行枚举遍历,就不怕原先的 ChildNodes 在中途被修改了,因为遍历的不是 ChildNodes。

DigitalPlatform avatar Nov 13 '20 09:11 DigitalPlatform