[Castore-commits] UnimarcException.java NONE 1.1 ExtractionUnimarc.java NONE 1.1

mathieu grimault grimault-m at adullact1.hosting.cri74.org
Mar 5 Déc 12:21:48 CET 2006


Update of /cvsroot/castore/castore-core/src/java/fr/emn/castor/documents/metier/unimarc
In directory adullact1:/tmp/cvs-serv24436/src/java/fr/emn/castor/documents/metier/unimarc

Added Files:
	UnimarcException.java ExtractionUnimarc.java 
Log Message:
Intégration de l'import UNIMARC

--- NEW FILE: ExtractionUnimarc.java ---
/*
 * $Id$
 *
 * Plateforme CASTORE
 * CeCILL Copyright (C) 2005-2006 by EMN
 * Made by 
 * Web site = http://www.emn.fr/castore
 * Contact = Cédric Dumas, e-mail = Cedric.Dumas at emn.fr
 *
 * Version
 *
 * Ce logiciel est un programme informatique servant à créer une plateforme
 * open-source de bibliothèque numérique XML pour Conserver, Valoriser et
 * Diffuser le patrimoine documentaire de votre institut.
 *
 * Ce logiciel est régi par la licence CeCILL soumise au droit français et
 * respectant les principes de diffusion des logiciels libres. Vous pouvez
 * utiliser, modifier et/ou redistribuer ce programme sous les conditions de la
 * licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site
 * "http://www.cecill.info". En contrepartie de l'accessibilité au code source
 * et des droits de copie, de modification et de redistribution accordés par
 * cette licence, il n'est offert aux utilisateurs qu'une garantie limitée. Pour
 * les mêmes raisons, seule une responsabilité restreinte pèse sur l'auteur du
 * programme, le titulaire des droits patrimoniaux et les concédants successifs.
 * A cet égard l'attention de l'utilisateur est attirée sur les risques associés
 * au chargement, à l'utilisation, à la modification et/ou au développement et à
 * la reproduction du logiciel par l'utilisateur étant donné sa spécificité de
 * logiciel libre, qui peut le rendre complexe à manipuler et qui le réserve
 * donc à des développeurs et des professionnels avertis possédant des
 * connaissances informatiques approfondies. Les utilisateurs sont donc invités
 * à charger et tester l'adéquation du logiciel à leurs besoins dans des
 * conditions permettant d'assurer la sécurité de leurs systèmes et ou de leurs
 * données et, plus généralement, à l'utiliser et l'exploiter dans les mêmes
 * conditions de sécurité. Le fait que vous puissiez accéder à cet en-tête
 * signifie que vous avez pris connaissance de la licence CeCILL, et que vous en
 * avez accepté les termes.
 *
 */

package fr.emn.castor.documents.metier.unimarc;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.marc4j.MarcReader;
import org.marc4j.MarcStreamReader;
import org.marc4j.converter.CharConverter;
import org.marc4j.converter.impl.Iso5426ToUnicode;
import org.marc4j.marc.ControlField;
import org.marc4j.marc.DataField;
import org.marc4j.marc.Record;
import org.marc4j.marc.Subfield;
import org.marc4j.marc.VariableField;

import fr.emn.castor.common.Constants;
import fr.emn.castor.documents.Fonds;
import fr.emn.castor.documents.metier.docGenerique.ParserNoticeException;

/**
 * Extraction de métadonnées d'une notice UNIMARC vers la notice d'un document
 * en cours de soumission. 
 * Le mapping est réalisé par l'adjonction d'informations dans le fichier 
 * contenant les informations de métadonnées pour un type de document 
 * (typeDoc/MD_XXX.xml). 
 *   
 * @author $Author$
 * @version $Revision$
 *
 */
public class ExtractionUnimarc {
	
	/** Clef de la map stockant les infos issues de typeDoc/MD_XXX.xml */
	private static String TAG_VALEUR		 = "valeur";
	private static String TAG_REPETABLE	 = "repetable";
	private static String TAG_SOUS_ZONE	 = "sous-zone";
	private static String TAG_INDICE		 = "indice";
	
	/** L'élément racine du fichier XML */
	private Element racine;
	
	/** L'enregistrement UNIMARC */
	private Record enregistrement;
	
	/** L'identifiant du document en cours de soumission */
	private String idDoc;
	
	/** le logger. */
    private static Log log = LogFactory.getLog(ExtractionUnimarc.class);
    
    /** 
	 * Interface de conversion du format UNIMARC vers unicode.
	 * Il existe : 
	 * 	AnselToUnicode, Iso5426ToUnicode, Iso6937ToUnicode
	 */
	private static CharConverter converter = new Iso5426ToUnicode();
	
	/**
	 * Constructeur
	 * @param idDoc L'identifiant du document en cours de soumission 
	 * @param unimarc Le fichier UNIMARC uploadé
	 * @throws UnimarcException En cas de pépin
	 */
	public ExtractionUnimarc(String idDoc, InputStream unimarc) throws UnimarcException {
		this.idDoc = idDoc;
		// Chargement du descriptif du type de document Castore
		String docType = 
			Fonds.getInstance().getNoticeValue(idDoc, "type");
        List fichiers = 
        	Fonds.getInstance().searchFilesForMapping(docType);
        
        if (log.isTraceEnabled()) {
        	log.trace(
	        	"Fichiers de description XML trouvés pour le type de document " + 
	        	docType + ": " + fichiers
	        );
        }
        
        if (fichiers == null || fichiers.size() == 0) {
        	throw new UnimarcException(
        		"Aucun fichier de description trouvé pour le type de doc " + docType
        	);
        }
		SAXBuilder sxb = new SAXBuilder();
		Document document = null;
		try {
			document = 
				sxb.build(
					new File(Constants.CASTOR_TYPEDOC_PATH + "/" + fichiers.get(0))
				);
		} catch (JDOMException e) {
			log.error(
				"Erreur à la lecture du fichier MD_XXX.xml : \n" + e, e
			);
			throw new UnimarcException(
				"Impossible de récupérer les métadonnées : erreur XML."
			);
		} catch (IOException e) {
			log.error(
				"Impossible de trouver le fichier MD_XXX.xml : \n" + e, e
			);
			throw new UnimarcException(
				"Impossible de récupérer les métadonnées : erreur XML."
			);
		}
		racine = document.getRootElement();
		
		// Chargement de la notice UNIMARC
		MarcReader reader = new MarcStreamReader(unimarc);
		// On ne traite que le 1er enregistrement du fichier !
		if (reader.hasNext()) {
			enregistrement = reader.next();
		} else {
			throw new UnimarcException(
				"Impossible de récupérer les métadonnées : \n " + 
				"Le fichier UNIMARC ne contient pas d'enregistrement."
			);
		}
	}
	
	/**
	 * Lancement de l'extraction des données UNIMARC vers la notice Castore
	 * @throws UnimarcException En cas de soucis
	 */
	public void extraire() throws UnimarcException {
		try {
			Map metadatas = new HashMap();
			Map mappingsDCUnimarc = recupMappingsDCUnimarc();
			Iterator i = mappingsDCUnimarc.keySet().iterator();
			// Itération sur chaque champ DC ayant une correspondance UNIMARC
			while (i.hasNext()) {
				String nomDc = (String)i.next();
				List zones = (List)mappingsDCUnimarc.get(nomDc);		
				
				if (log.isTraceEnabled()) {
					log.trace("Traitement du champ DC " + nomDc);
				}
				
				// Itération sur chaque zone UNIMARC
				Iterator zonator = zones.iterator();
				while (zonator.hasNext()) {
					Map zone = (Map)zonator.next();
					
					List donnees = 
						recupMetadonnees(
							(String)zone.get(TAG_VALEUR),
							(String)zone.get(TAG_SOUS_ZONE),
							(String)zone.get(TAG_INDICE),
							Boolean.parseBoolean((String)zone.get(TAG_REPETABLE)), 
							!Fonds.getInstance().isMultipleMetadata(nomDc, idDoc)
						);
					
					if (donnees != null && donnees.size() > 0) {
						if (log.isTraceEnabled()) {
							log.trace(
								"Injection des données dans le champ " + 
								nomDc + " :\n" + 
								donnees
							);
						}
						if (Fonds.getInstance().isMultipleMetadata(nomDc, idDoc)) {
							// cas dc multiple, on doit fournir une liste de valeurs
							ajouterDonneesMetadatas(nomDc, metadatas, donnees, true);
						} else {
							// cas dc unique, on doit fournir une seule valeur
							ajouterDonneesMetadatas(nomDc, metadatas, donnees, false);
						}
					}
				}
			}

			// Injection des metadonnnées dans la notice du document 
			if (metadatas != null && metadatas.size() > 0) {
				if (log.isTraceEnabled()) {
					log.trace("Injection des données dans la notice...");
				}
				Fonds.getInstance().setMetaDatas(idDoc, metadatas, "unimarc");
			}
		} catch (ParserNoticeException e) {
			log.error(
				"Erreur à la lecture du fichier MD_XXX.xml : \n"+ e, e	
			);
			throw new UnimarcException(
				"Impossible de récupérer les métadonnées : erreur XML." 
			);
		}
	}
	
	/**
	 * Ajoute les métadonnées à la liste des métadonnées récupérées.
	 * @param nomDc Le nom du champ Dublin Core en cours de traitement
	 * @param metadatas La liste des métadonnées récupérées
	 * @param donnees Les données à ajouter
	 * @param multiple Si le champ Dublin Core est unique (false) ou multiple (true)
	 */
	private void ajouterDonneesMetadatas(String nomDc, Map metadatas, List donnees, boolean multiple) {
		if (metadatas.containsKey(nomDc)) {
			if (multiple) {
				List donneesPresentes = (List)metadatas.get(nomDc);
				donneesPresentes.addAll((List)donnees);
				metadatas.put(nomDc, donneesPresentes);
			} else {
				List donneesPresentes = (List)metadatas.get(nomDc);
				String donneePresente = (String)donneesPresentes.get(0);
				Iterator i = donnees.iterator();
				while (i.hasNext()) {
					donneePresente += " " + (String)i.next();
				}
				donneesPresentes.clear();
				donneesPresentes.add(donneePresente);
				metadatas.put(nomDc, donneesPresentes);
			}
		} else {
			metadatas.put(nomDc, donnees);
		}
	}
	
	/**
	 * Récupération des informations de mapping UNIMARC/Dublin Core
	 * mentionnées dans le fichier MD_XXX.xml
	 * @return Une Map conscienceusement remplie
	 */
	private Map recupMappingsDCUnimarc() {
		Map mappingsDCUnimarc = new HashMap();
		List metadatas = racine.getChildren("metadata");
		Iterator i = metadatas.iterator();
		// Boucle sur les metadata
		while (i.hasNext()) {
			Element metadata = (Element)i.next();
			if (metadata.getChild("unimarc") != null) {
				// un mapping est renseigné !
				Element unimarc = metadata.getChild("unimarc");
				List zones = unimarc.getChildren("zone");
				Iterator zonator = zones.iterator();
				// boucle sur les zones pour un champ DC
				while (zonator.hasNext()) {
					Element zone = (Element)zonator.next();
					// Représentation du mapping indiqué dans le MD_XXX.xml
					Map mappingZones = new HashMap();
					mappingZones.put(TAG_VALEUR, zone.getTextNormalize());
					mappingZones.put(TAG_REPETABLE, zone.getAttributeValue(TAG_REPETABLE));
					if (zone.getAttribute(TAG_SOUS_ZONE) != null) {
						mappingZones.put(TAG_SOUS_ZONE, zone.getAttributeValue(TAG_SOUS_ZONE));
					}
					if (zone.getAttribute(TAG_INDICE) != null) {
						mappingZones.put(TAG_INDICE, zone.getAttributeValue(TAG_INDICE));
					}
					
					ajouterMapping(
						mappingsDCUnimarc, 
						metadata.getChild("equivalent_dc").getTextNormalize(), 
						mappingZones
					);
				}
			}
		}
		return mappingsDCUnimarc;
	}
	
	/**
	 * Ajoute le mapping fourni en paramètre à la liste des mappings déjà trouvés
	 * @param mappingsDCUnimarc les mappings déjà trouvés
	 * @param nomDC Le nom du champ Dublin Core en cours de traitement
	 * @param mappingZones Le mapping nouvellement trouvé
	 */
	private void ajouterMapping(Map mappingsDCUnimarc, String nomDC, Map mappingZones) {
		List mappings = null;
		if (mappingsDCUnimarc.get(nomDC) == null) {
			// champ dc pas encore traité
			mappings = new ArrayList();			
		} else {
			// deja des infos de recupérées
			mappings = (List)mappingsDCUnimarc.get(nomDC);
		}
		mappings.add(mappingZones);
		mappingsDCUnimarc.put(nomDC, mappings);
	}
	
	/**
	 * Récupération des informations contenues dans le fichier UNIMARC
	 * @param etiquette L'étiquette de la zone à traiter
	 * @param sousZone Optionnel, la/les sous-zone(s) à traiter
	 * @param indice optionnel, l'indice de la zone si la zone est répétable et que ne veut que l'élément précisé [0,X]
	 * @param repetable Si la zone est répétable ou non
	 * @param concatener Si le champ Dublin Core est multiple (false) ou unique (true)
	 * @return une List de valeur avec plusieurs éléments (concatener=false) ou un seul (concatener=true)
	 */
	private List recupMetadonnees(String etiquette, String sousZone, String indice, boolean repetable, boolean concatener) {
		List liste = new ArrayList();
		if (repetable) {
			// on doit traiter une liste de champs
			List dfs = enregistrement.getVariableFields(etiquette);
			if (dfs != null && dfs.size() > 0) {
				if (concatener) {
					String resultat = "";
					Iterator i = dfs.iterator();
					while (i.hasNext()) {
						VariableField vf = (VariableField)i.next();
						String zu = lireZoneUnimarc(vf, sousZone);
						if (zu != null && zu.length() > 0) {
							resultat += zu + " ";
						}
					}
					resultat = resultat.trim();
					if (!"".equals(resultat)) {
						liste.add(resultat);
					}
				} else {
					Iterator i = dfs.iterator();
					while (i.hasNext()) {
						VariableField vf = (VariableField)i.next();
						String zu = lireZoneUnimarc(vf, sousZone);
						if (zu != null && zu.length() > 0) {
							liste.add(zu);
						}
					}
				}
			}
		} else {
			if (indice == null) {
				// on veut une unique zone
				VariableField vf = enregistrement.getVariableField(etiquette);
				String zu = lireZoneUnimarc(vf, sousZone);
				if (zu != null && zu.length() > 0) {
					liste.add(zu);
				}
			} else {
				// on veut une zone particuliere d'une zone repetable
				List dfs = enregistrement.getVariableFields(etiquette);
				if (dfs != null && dfs.size() >= (Integer.parseInt(indice)+1)) {
					VariableField vf = (VariableField)dfs.get(Integer.parseInt(indice));
					String zu = lireZoneUnimarc(vf, sousZone);
					if (zu != null && zu.length() > 0) {
						liste.add(zu);
					}
				}
			}
		}
		return liste;
	}
	
	/**
	 * Retourne la valeur de la zone UNIMARC
	 * @param vf La zone Unimarc à lire
	 * @param sousZone optionnel, la/les sous-zone(s)
	 * @return La valeur débarassée des caractères spéciaux UNIMARC 
	 */
	private String lireZoneUnimarc(VariableField vf, String sousZone) {
		if (sousZone == null) {
			// la zone est un champ de controle
			ControlField cf = (ControlField)vf;
			if (cf != null) {
				return converter.convert(cf.getData());
			}
			return null;
		} else {
			// la zone est un champ de données
			DataField df = (DataField)vf;
			if (df != null) {
				if (sousZone.length() > 1) {
					// Il y a plusieurs sous-zones, 
					// on les concatène avec un espace séparateur
					String s = "";
					for (int i=0;i<sousZone.length();i++) {
						Subfield sf = df.getSubfield(sousZone.charAt(i));
						if (sf != null) {
							s += converter.convert(sf.getData()) + " ";
						}
					}
					s = s.trim();
					if (!"".equals(s)) {
						return s;
					}
				} else {
					// il n'y a qu'une sous-zone à traiter
					Subfield sf = df.getSubfield(sousZone.charAt(0));
					if (sf != null) {
						return converter.convert(sf.getData());
					}
				}
			}
			return null;
		}
	}
}

--- NEW FILE: UnimarcException.java ---
/*
 * $Id$
 *
 * Plateforme CASTORE
 * CeCILL Copyright (C) 2005-2006 by EMN
 * Made by 
 * Web site = http://www.emn.fr/castore
 * Contact = Cédric Dumas, e-mail = Cedric.Dumas at emn.fr
 *
 * Version
 *
 * Ce logiciel est un programme informatique servant à créer une plateforme
 * open-source de bibliothèque numérique XML pour Conserver, Valoriser et
 * Diffuser le patrimoine documentaire de votre institut.
 *
 * Ce logiciel est régi par la licence CeCILL soumise au droit français et
 * respectant les principes de diffusion des logiciels libres. Vous pouvez
 * utiliser, modifier et/ou redistribuer ce programme sous les conditions de la
 * licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA sur le site
 * "http://www.cecill.info". En contrepartie de l'accessibilité au code source
 * et des droits de copie, de modification et de redistribution accordés par
 * cette licence, il n'est offert aux utilisateurs qu'une garantie limitée. Pour
 * les mêmes raisons, seule une responsabilité restreinte pèse sur l'auteur du
 * programme, le titulaire des droits patrimoniaux et les concédants successifs.
 * A cet égard l'attention de l'utilisateur est attirée sur les risques associés
 * au chargement, à l'utilisation, à la modification et/ou au développement et à
 * la reproduction du logiciel par l'utilisateur étant donné sa spécificité de
 * logiciel libre, qui peut le rendre complexe à manipuler et qui le réserve
 * donc à des développeurs et des professionnels avertis possédant des
 * connaissances informatiques approfondies. Les utilisateurs sont donc invités
 * à charger et tester l'adéquation du logiciel à leurs besoins dans des
 * conditions permettant d'assurer la sécurité de leurs systèmes et ou de leurs
 * données et, plus généralement, à l'utiliser et l'exploiter dans les mêmes
 * conditions de sécurité. Le fait que vous puissiez accéder à cet en-tête
 * signifie que vous avez pris connaissance de la licence CeCILL, et que vous en
 * avez accepté les termes.
 *
 */

package fr.emn.castor.documents.metier.unimarc;

/**
 * Exception lancée lors de la manipulation UNIMARC
 *
 * @author $Author$
 * @version $Revision$
 *
 */
public class UnimarcException extends Exception {

	/**
	 * Pour interface Serializable
	 */
	private static final long serialVersionUID = 1L;

	/**
	 * Constructeur
	 * @param erreur Le message d'erreur
	 */
	public UnimarcException(String erreur) {
		super(erreur);
	}
}




Plus d'informations sur la liste de diffusion Castore-commits