天天看點

Marc資料解析和拼接(java版)

解析marc資料:

marc資料分為三部分:辨別區、目次區、資料記錄區。詳情請仔細查找資料,本文不多介紹,直接上代碼

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class JMarc {

		static Map<String, String> map=new HashMap<String, String>();//解析集合

		public Map<String, String> jxMarc(String marc){
			originalMap();
			String m=marc.split("\\u001D")[0];
			String s1=m.split("\\u001E")[0];
			String s2=(String) s1.subSequence(5, 6);
			if(s2.equals("d")){
				System.err.println("檢測到資料已廢除!錯誤發生在:辨別區狀态為‘d’");
				return map;
			}
			int  s3=Integer.parseInt(s1.substring(12,17));
			String s4=s1.substring(24,s3-1);
			if(s4.length()%12!=0) {
				System.err.println("檢測到資料格式錯誤!錯誤發生在:位址目次區");
				return map;
			}
			List<String> list1=new ArrayList<String>();//目次區集合
			for(int i=0;i<s4.length()/12;i++) {
				list1.add( s4.substring( 12*i, 12*(i+1) ) );
			}
			int k=m.split("\\u001E").length-1;//第一個數組是辨別+目次區
			String[] sz=m.split("\\u001E");
			List<String> list2=new ArrayList<String>();//記錄區集合
			for(int i =0;i<k;i++) {
				list2.add(sz[i+1]);
			}
			if(list1.size()!=list2.size()) {
				System.err.println("檢測到目次區與記錄區數量不比對!錯誤發生在:目次區或資料區,"
						+ "目次區:"+list1.size()+"組,記錄區:"+list2.size()+"條");
				return map;
			}
			//比對
			for(int i=0;i<list1.size();i++) {
				matchingMap(list1.get(i).substring(0,3),list2.get(i));
			}
			return map;
		}
		//初始化map
		public Map<String, String> originalMap() {
			map.put("isbn", null);//ISBN
			map.put("title", null);//标題
			map.put("divisionname", null);//分冊名
			map.put("divisionnumber", null);//分冊号
			map.put("author", null);//作者
			map.put("oneprice", null);//價格
			map.put("size", null);//尺寸
			map.put("page", null);//頁數、x冊
			map.put("published", null);//出版地
			map.put("clc", null);//中圖分類号
			map.put("press", null);//出版社
			map.put("pubdate", null);//出版時間
			map.put("language", null);//語言
			map.put("type", null);//主題
			map.put("Remarks", null);//内容、簡介
			return map;
		}
		//比對并指派map
		public void matchingMap(String key1,String key2) {
			switch (key1) {
			case "010":
				if( key2.split("\\u001Fa").length>1 ) {//isbn
					String f1=key2.split("\\u001Fa")[1];
					String f2=f1.split("\\u001F")[0];
					map.put("isbn", f2);
				}
				if(key2.split("\\u001Fd").length>1) {//價格
					String f1=key2.split("\\u001Fd")[1];
					String f2=f1.split("\\u001F")[0];
					map.put("oneprice", f2);
				}
				break;
			case "101":
				if(key2.split("\\u001Fa").length>1) {//語言
					String f1=key2.split("\\u001Fa")[1];
					String f2=f1.split("\\u001F")[0];
					map.put("language", f2);
				}
				break;
			case "200":
				if(key2.split("\\u001Ff").length>1) {//作者
					String f1=key2.split("\\u001Ff")[1];
					String f2=f1.split("\\u001F")[0];
					map.put("author", f2);
				}
				if(key2.split("\\u001Fa").length>1) {//題名
					String f1=key2.split("\\u001Fa")[1];
					String f2=f1.split("\\u001F")[0];
					map.put("title", f2);
				}
				if(key2.split("\\u001Fh").length>1) {//分冊号***可能不止一個'@h'
					String f1=key2.split("\\u001Fh")[1];
					String f2=f1.split("\\u001F")[0];
					map.put("divisionnumber", f2);
				}
				if(key2.split("\\u001Fi").length>1) {//分冊名***可能不止一個'@i'
					String f1=key2.split("\\u001Fi")[1];
					String f2=f1.split("\\u001F")[0];
					map.put("divisionname", f2);
				}
				break;
			case "210":
				if(key2.split("\\u001Fa").length>1) {//出版地
					String f1=key2.split("\\u001Fa")[1];
					String f2=f1.split("\\u001F")[0];
					map.put("published", f2);
				}
				if(key2.split("\\u001Fc").length>1) {//出版社
					String f1=key2.split("\\u001Fc")[1];
					String f2=f1.split("\\u001F")[0];
					map.put("press", f2);
				}
				if(key2.split("\\u001Fd").length>1) {//出版時間
					String f1=key2.split("\\u001Fd")[1];
					String f2=f1.split("\\u001F")[0];
					map.put("pubdate",f2);
				}
				break;
			case "215":
				if(key2.split("\\u001Fd").length>1) {//尺寸
					String f1=key2.split("\\u001Fd")[1];
					String f2=f1.split("\\u001F")[0];
					map.put("size", f2);
				}
				if(key2.split("\\u001Fa").length>1) {//頁數***可能是層數
					String f1=key2.split("\\u001Fa")[1];
					String f2=f1.split("\\u001F")[0];
					map.put("page", f2);
				}
				break;
			case "330":
				if(key2.split("\\u001Fa").length>1) {//内容
					String f1=key2.split("\\u001Fa")[1];
					String f2=f1.split("\\u001F")[0];
					map.put("Remarks", f2);
				}
				break;
			case "606":	
				if(key2.split("\\u001Fa").length>1) {//主題
					String f1=key2.split("\\u001Fa")[1];
					String f2=f1.split("\\u001F")[0];
					map.put("type", f2);
				}
				break;
			case "690":
				if(key2.split("\\u001Fa").length>1) {//分類号
					String f1=key2.split("\\u001Fa")[1];
					String f2=f1.split("\\u001F")[0];
					map.put("clc", f2);
				}
				break;
			default:
				break;
			}
			
			
		}

}

           

将結果放到了map數組裡。解析的資料都是規定好的,因為這是本人項目的一小部分,需要其他部分解析的可以參考資料添加解析。比對類是單獨的

拼接marc資料

會解析自然會拼接拉。直接上代碼了。自己看吧:

public class PMarc {
	
	String marc1 = null;//第一段辨別
	String marc2 = null;//第二段目次
	String marc3 = null;//第三段記錄
	String marc =null;//marc資料
	char _RecordSplitChar = '\u001D';  // 區間分隔符
    char _FieldSplitChar = '\u001E';  // 字段分割符
    char _SubFieldSplitChar = '\u001F';  // 子字段分隔符

    public String pjMarc(
			String isbn,String oneprice,String title,String author,String press,String clc) {
		//記錄區
		 String s1="  "+_SubFieldSplitChar+"a"+isbn+_SubFieldSplitChar+"d"+oneprice;    //010  isbn+價格
		 String s2=_FieldSplitChar+"1 "+_SubFieldSplitChar+"a"+title+_SubFieldSplitChar+"f"+author;   //200 題名+作者
		 String s3=_FieldSplitChar+"  "+_SubFieldSplitChar+"c"+press;     //210 出版社
		 String s4=_FieldSplitChar+"  "+_SubFieldSplitChar+"a"+clc ;    //690 中圖分類号
		marc3=s1+s2+s3+s4;
		
		marc2="010"+String.format("%04d", s1.length())+String.format("%05d", 0)
		+"200"+String.format("%04d", s2.length())+String.format("%05d", 0+s1.length())
		+"210"+String.format("%04d", s3.length())+String.format("%05d", 0+s1.length()+s2.length())
		+"690"+String.format("%04d", s4.length())+String.format("%05d", 0+s1.length()+s2.length()+s3.length())
				;
		
		marc1=String.format("%05d", marc3.length()+marc2.length()+1)
		+"pam0"+" 22"+String.format("%05d",marc2.length()+1+24)+"   "+"450 "
				;
		
		marc=marc1+marc2+_FieldSplitChar+marc3+_RecordSplitChar;
		
		return marc;
	}
}

           

拼接類拼接的比較簡單,可以自行添加複雜,注意的是分隔符,很容易出錯。

測試類

import java.util.HashMap;
import java.util.Map;

public class test {

	public static void main(String[] args) {
		Map<String, String> map=new HashMap<String, String>();
		JMarc j=new JMarc();
		PMarc p=new PMarc();
		//拼接
		String s=p.pjMarc("978-7-5463-4025-4", "CNY79.50", "誅仙", "蕭鼎著", "起點小說網", "D67.475");
		map=j.jxMarc(s);//解析測試
		System.err.println(s);
		System.out.println(map);
		//解析
		String s2="01141nam0 2200289   450 00100100000000500170001001000390002703500260006603500240009204900490011610000410016510100080020610200150021410500180022910600060024720001570025321000350041021500190044533001600046460700250062469000140064970100490066370200310071271200630074380100220080680100230082800011310320020928000000.0  a7-101-00183-1dCNY332.00(全二十冊)  a(A100000NLC)000113139  a(011001)c2001044106  aA100000NLCbUCS01000113103c000113139dNLC01  a20010709e19951956em y0chiy0110    ea0 achi  aCNb110000  ay   z   000yy  ar1 a資治通鑒9zi zhi tong jianh第一冊i卷一至一十二 周威烈王二十三年戊寅起 漢惠帝七年癸醜止b專著f(宋)司馬光編著g(元)胡三省音注g“标點資治通鑒小組”校點  a北京c中華書局d1956h1995重印  a75,418頁d20cm  a《資治通鑒》為北宋司馬光所編撰的編年體通史,共294卷。全書記載了上起周威王二十三年(公元前403年),下至五代周世宗顯德六年(公元959年)的一千三百六十二年的曆史。  a中國x古代史j編年體  aK204.3v4 0c(宋)a司馬光f(1019-1086)9si ma guang4編著 0a胡三省9hu san sheng4音注02a标點資治通鑒小組9biao dian zi zhi tong jian xiao zu4校點 0aCNbNLCc20010717 2aCNbOLCCc20100923";
		map=j.jxMarc(s2);
		System.out.println(map);
	}
}

           

s2字元串中的marc資料亂碼了。編碼格式不同,建議自己去找一條marc資料去測試,可以去:中國國家圖書館找。

還有關于用z39.50協定套取mar資料的java方法可以去看我的另一篇yaz4j擷取marc資料

套取marc方法類下載下傳

-------------------------------------------------2019-11-01記載日志