Está en la página 1de 34

Índice de contenido

Migración de bases ISIS a KOHA....................................................................................................2

Cuestiones preliminares...................................................................................................................2
Aproximaciones...............................................................................................................................2
ISIS -> XML -> TEXT -> MARC -> KOHA.............................................................................3
ISIS -> ISO -> ISO2709 -> KOHA............................................................................................4
ISIS -> XML -> KOHA..............................................................................................................4
Apéndice..............................................................................................................................................9

ISIS -> XML -> TEXT -> MARC -> KOHA.............................................................................9


Script Python (XML -> TEXT)..............................................................................................9
Script Perl (TEXT -> MARC)..............................................................................................11
ISIS -> XML -> KOHA............................................................................................................23
Script Perl (XML -> KOHA)...............................................................................................23
Lenguaje de Formateo (PFT)...............................................................................................31
xml2koha.map......................................................................................................................32
Migración de bases ISIS a KOHA

Cuestiones preliminares
Para que cualquiera de los métodos descritos a continuación funcione, es imprescindible completar
algunos pasos previos. Estos pasos se refieren a la configuración del sistema e incluyen, en orden de
importancia, los siguientes parámetros:

item types (tipos de item): Son las categorías a las que pertenecen los ejemplares que maneja de
biblioteca. Por ejemplo, los videocassettes pertenecen a una categoría distinta a la de los libros y a
la de las grabaciones sonoras.
Este paso es fundamental, ya que mucha de la funcionalidad de Koha se pierde si no se
especifican correctamente los tipos de ítem.

MARC tag structure (Estructura de campos MARC): Koha permite definir qué campos MARC
serán usados y cuáles serán ignorados.
La importancia de este paso radica en la posibilidad de establecer una correlación entre los
subcampos MARC y los campos de las tablas presentes en Koha.

Como ejemplo, la posible estructura para los subcampos del campo de título, 245:

SELECT tagsubfield,kohafield FROM marc_subfield_structure WHERE tagfield=245;


+-------------+-------------------------+
| tagsubfield | kohafield |
+-------------+-------------------------+
| 6 | |
| 8 | |
| a | biblio.title |
| b | bibliosubtitle.subtitle |
| c | |
| f | |
| g | |
| h | biblio.abstract |
| k | |
| n | |
| p | |
| s | |
+-------------+-------------------------+

Aproximaciones

Hay más de una aproximación al problema de la migración de datos de una base existente a
las bases del sistema Koha, si bien no todas se enfocan a la migración de datos contenidos en bases
ISIS. Las siguientes secciones muestran los distintos caminos analizados y tratan de anticipar los
problemas que pueden presentar cada uno de ellos.
ISIS -> XML -> TEXT -> MARC -> KOHA
Este método consiste, tal como describe su autor en su página web, en exportar una base de
datos ISIS a un archivo XML a través de la utilidad incluida a tal efecto en WinISIS.
Nota: La utilidad mencionada se encuentra en el menú 'Utils' de WinIsis, pero sólo es accesible si
el idioma seleccionado es el inglés. Por alguna razón desconocida, si se configura el idioma de
WinIsis a español, la opción no es visible en el menú.
A partir de este archivo XML, se utiliza un script escrito en Python, el cual genera un
archivo de texto delimitado por tabulaciones ('tab delimited text file').
A continuación, se transforma la información contenida en el archivo de texto en registros
MARC mediante otro script, este escrito en lenguaje Perl.
Finalmente, el archivo conteniendo los registros en fomrato MARC se importaría a las bases
de Koha. El autor no especifica la manera en que esta importación se realiza, pero se infiere la
utilización del script bulkmarcimport.pl provisto en la ditribución de Koha (ubicado en Linux en:
DirectorioDeKoha/scripts/misc/).
Este método no ha sido probado hasta el momento, debido a que es el más complejo de los
tres analizados, en cuanto a la cantidad de pasos necesarios
ISIS -> ISO -> ISO2709 -> KOHA
Este método no está presente en una página web, ni ha sido propuesto en la lista de correo de
Koha, sino que se deriva de la posibilidad, ofrecida por el propio Koha, de realizar una importación
masiva de datos a las bases que componen el sistema a través del script bulkmarcimport.pl (ubicado
en Linux en: DirectorioDeKoha/scripts/misc/).
Este script recibe como parámetro, entre otras cosas, la ubicación y el nombre de un archivo
ISO2709 que contenga los datos MARC que se quieran importar.
La dificultad que se presenta a la hora de migrar bases ISIS a Koha, es que el archivo ISO
generado por las distintas herramientas disponibles no es interpretado correctamente, ya que no se
atendría lo suficiente al estándar ISO2709.
Poco antes de la elaboración de este informe, se realizaron pruebas con la utilidad ImpExp
disponible en http://www.unesco.org/isis/files/winisis/windows/utilities/. Mediante esta utilidad
sería posible transformar un archivo ISO generado a partir de una base ISIS en un archivo ISO
conforme al estándar ISO2709.
Las pruebas realizadas hasta el momento no han sido satisfactorias, pero es necesario
continuar con las mismas para obtener una conclusión determinante.

ISIS -> XML -> KOHA


Este método, en pocas palabras, implica la exportación de una base ISIS a un archivo XML
y la utilización de una script Perl para la inclusión de los datos contenidos en el archivo XML
directamente a las bases de datos de Koha.
Para la concreción exitosa de este método es necesaria la generación de un archivo XML
bien formado con todos los datos de la base de datos ISIS que se quiera importar a Koha. El autor
del mismo recomienda la utilización de la herramienta ISIS2XML disponible en
ftp://ftp.unesco.org/pub/winisis/windows/utilities/Isis2XML/
Sin embargo, este soft sólo se encuentra disponible en francés. Por lo tanto, si bien el autor
(del método y los scripts, no del soft) también ha puesto a disposición de cualquier interesado una
serie de imágenes que describen el proceso de creación del archivo XML (que se descargan junto
con el script). Las pruebas se realizaron haciendo moficaciones al lenguaje de formateo de ISIS
utilizado por WinIsis para generar archivos XML a partir de una base de datos.
Es imprescindible que el XML resultante no contenga 'saltos de linea' (carriage returns) ya
que, de lo contrario, el script de importación generará un error y abortará .
El archivo XML utilizado en las pruebas se generó por medio de la utilidad de impresión de
WINISIS, configurando la salida a un archivo de texto y utilizando el formato presentado en el
Apéndice. Se debe recordar que la estructura de un archivoXML debe contar con un elemento raíz.
Este elemento raíz se generó colocando <BASE> como Header y </BASE> como Footer, en la
ventana de configuración de la impresión de WINISIS.

Instalación:

El script de migración requiere la instalación previa de una serie de módulos de PERL:


Term::Activity
DBD::mysql
XML::Twig
MARC::Record

Posteriormente, el script necesitará saber dónde se encuentran los módulos de Koha. Por
ejemplo, si la instalación de Koha se encuentra en /usr/local/koha/ el comando a ejecutar sería:
$ export PERL5LIB=/usr/local/koha/intranet/modules

Con los pasos anteriores sería suficiente para que el script pueda funcionar correctamente.
Se puede probar lo anterior ubicándose en el directorio en el que se encuentra el script y ejecutando
el comando:
$./xml2koha.pl -pf data/10-records.xml
El resultado de este comando es un 'dump' en pantalla del contenido de 10 registros de
prueba (contenidos en el archivo 10-records.xml) en formato MARC.

Configuración:

Para lograr que el script se comporte correctamente, se debe configurar su


funcionamiento. Esto se logra editando dos archivos de texto, que acompañan al script
ejecutable, de nombres xml2koha.conf y xml2koha.map

xml2koha.conf
Se trata de un archivo de configuración bastante simple en el cual se debe setear las
siguientes variables:

$MAPFILE : El nombre del archivo de texto conteniendo el mapeado entre etiquetas


XML y campos/subcampos MARC.

$RECORD_ELEMENT : El nombre de la etiqueta XML que contiene la información de


cada registro de la base ISIS a importar en Koha.
Como ejemplo, si la estructura XML es:
<REGISTRO>
<TAG_1>aaaaaa</TAG_1>
<TAG_2>bbbbbb</TAG_2>
<TAG_3>cccccc</TAG_3>
</REGISTRO>

En xml2koha.conf debería figurar:


$RECORD_ELEMENT = “REGISTRO”;
$DEFAULT_TAGS : Definición de campos que se agregarán a cada registro procesado, con
un contenido fijo.
xml2koha.map

El archivo xml2koha.map es creado por el script xml2koha.pl automáticamente (si se


cambia el valor de $MAPFILE en xml2koha.conf el nombre del archivo .map también
cambiará). Para lograr esto, el archivo XML creado a partir de la base ISIS (supongamos
datos-cdsisis.xml) debe ser colocado en el mismo directorio del script xml2koha.pl. El
comando para realizar este proceso es:

$ ./xml2koha.pl -mf datos-cdsisis.xml

Completado este comando, quedará, en el mismo directorio, un nuevo archivo .map


que SERÁ NECESARIO EDITAR MANUALMENTE (no hay otra forma) para hacer
coincidir las etiquetas encontradas en el archivo XML con campos/subcampos MARC.

Al abrir el archivo .map con un editor de texto, se observarán dos secciones. La primera la
compone una serie de comnetarios referidos a la cantidad de ocurrencias de las distintas
etiquetas encontradas en el archivo XML. Esto puede servir como un primer punto de
control.

La segunda sección está compuesta de líneas del tipo...


000 ## %TAG

...que es donde se especifica el mapeado deseado.

Los tres números iniciales deben ser reemplazados con el campo MARC de destino, al cual
irá a parar la información contenida en cada etiqueta <TAG>
Los dos ## encontrados a continuación, deberán ser reemplazados, si es necesario, por los
valores de los indicadores que deberán incluirse en el campo/subcampo MARC de destino.
A continuación se podrá especificar el subcampo MARC al cual irá a parar el la información
contenida en cada etiqueta <TAG>, lo cual se logra colocando un signo $ seguido de la
etiqueta de subcampo.
Finalmente, se coloca el nombre del elemento/etiqueta XML del que se extraerá la
información, para el campo/subcampo MARC especificado. Este elemento puede ser
precedido por:
% : Sirve para mezclar, en un mismo campo MARC, la información proveniente de varios
campos. En la base de destino, se mezclaran los contenidos de los campos de la base ISIS
que apunten al mismo campo/subcampo MARC.
@ : Un elemento/etiqueta que comience con este símbolo será repetible. Cada elemento
enviado desde la base ISIS al mismo campo/subcampo MARC, será colocado en una nueva
ocurrencia en la base MARC de destino.
Un archivo xml2koha.map de ejemplo se ha incluido en este documento. La estructura de
este archivo debería quedar más o menos como sigue:
# Some counts of Elements found in data/vidunc.xml
# Count Element/Tag Name
# 3 Tag_110_a
# 5 Tag_245_a
# 5 Tag_245_n
# 9 Tag_653_a

110 ## $a %Tag_110_a
245 ## $a %Tag_245_a
245 ## $n %Tag_245_n
653 ## $a @Tag_653_a

Una vez que se está conforme con la configuración, se puede probar el resultado con el
comando:
$ ./xml2koha.pl -pf datos-cdsisis.xml

La opción -p presenta los resultados solamente en pantalla.

Para insertar los datos en la instalación de Koha, se deberá ejecutar el siguiente comando:
$ ./xml2koha.pl -cf datos-cdsisis.xml

En el caso de que se haya producido un error o se haya cometido una equivocación, se podrá
eliminar todos los datos bibliográficos de las base de Koha, antes de arreglar el problema y realizar
una nueva importación, con el siguiente comando:
$ ./xml2koha.pl -dcf datos-cdsisis.xml

Los ajustes y reconfiguraciones sucesivas se harán inevitables y el proceso de conversión se vuelve


bastante lento cuando se realiza la migración de una gran cantidad de registros, por lo que se
aconseja realizar las pruebas con conjuntos reducidos de registros, entre 30 y 50, hasta que el
resultado sea el esperado.
Apéndice

ISIS -> XML -> TEXT -> MARC -> KOHA

Script Python (XML -> TEXT)


ciddtf.py : Convert ISIS Document Database to Text File
Before Parsing :
Change RECORDX\xc3\x91_5\xc3\xaf\x03\x12 to RECORD
Change & to and
fix problems of <Tag_97> manualy.

import libxml2

record = []

def Record(i, node):

sub_node = node.children

while sub_node is not None:

if sub_node.type == "element":

record[i][sub_node.name] = sub_node.get_content()

sub_node = sub_node.next

else:

sub_node = sub_node.next

Memory debug specific


libxml2.debugMemory(1)

isis_data = libxml2.parseFile ('../xmls/docs.xml')

root = isis_data.getRootElement()

node = root.children

i = 0

while node is not None:


if node.type != "element":

node = node.next

continue

if node is None:

break

if node.name == "RECORD":

##print node.get_content()

record.append({})

Record(i, node)

i = i + 1

node = node.next

else:

print "unhandled node in <isis_xml>: " + node.name

isis_data.freeDoc()

Memory debug specific


libxml2.cleanupParser()

if libxml2.debugMemory(1) == 0:

print "OK"

else:

print "Memory leak %d bytes" % (libxml2.debugMemory(1))

libxml2.dumpMemory()

record_file = open('../outs/docs.txt', 'w')

tag = ['Tag_4', 'Tag_7', 'Tag_11', 'Tag_12', 'Tag_13', 'Tag_18', 'Tag_19',


'Tag_20', 'Tag_21', 'Tag_24', 'Tag_38', 'Tag_10', 'Tag_114', 'Tag_115',
'Tag_110', 'Tag_5', 'Tag_122', 'Tag_97', 'Tag_151', 'Tag_153', 'Tag_123']

for j in record:

if j.has_key('Tag_691'):

record_file.write(j['Tag_691'])

Check docs without 114 tag


if j.has_key('Tag_114'):
pass
else:
print j['Tag_691']
else:

record_file.write('_B_L_A_N_K_')

for h in tag:

if j.has_key(h):

record_file.write('\t'+j[h])

else:

record_file.write('\t_B_L_A_N_K_')

record_file.write('\n')

Script Perl (TEXT -> MARC)


package cmftf;

Create MARC From Text File


Copyright 2004 Baiju M <baijum81@lycos.com>
This program is licensed under GNU GPL.

use strict;

use MARC::Record;

my $input_file = "../outs/docs.txt";

my $output_file = "../outs/docs.out";

my $repeated_items = " ";

open(INFILE, $input_file) or die "Can't open $input_file: $!";


open(OUTFILE, ">>", $output_file) or die "Can't open $output_file: $!";

my $c = 0;

while (<INFILE>) {

$c++;

my $biblionumber_ftf_691_090_c, my $title_ftf_4_245_a, my $edition_ftf_7_250_a,


my $publisher_ftf_11_260_b, my $publishcountry_ftf_12_260_a, my
$publishyear_ftf_13_260_c, my $author1ee_ftf_18_100_a, my
$author1se_ftf_19_100_a, my $author2ee_ftf_20_700_a, my $author2se_ftf_21_700_a,
my $adiauthors_ftf_24_700_a, my $role_ftf_38_590_a, my $phydescr_ftf_10_300_a,
my $classno_ftf_114_852_k, my $classno_ftf_115_852_h, my $keyword_ftf_5_520_a,
my $voldetails_ftf_110_440_v, my $dateofentry_ftf_122_952_v, my
$notes_ftf_97_500_a, my $pubprice_151_952_r, my $currency_153_590_b, my
$reccreated_123_508_a, my $remainder;

($biblionumber_ftf_691_090_c, $title_ftf_4_245_a, $edition_ftf_7_250_a,


$publisher_ftf_11_260_b, $publishcountry_ftf_12_260_a,
$publishyear_ftf_13_260_c, $author1ee_ftf_18_100_a, $author1se_ftf_19_100_a,
$author2ee_ftf_20_700_a, $author2se_ftf_21_700_a, $adiauthors_ftf_24_700_a,
$role_ftf_38_590_a, $phydescr_ftf_10_300_a, $classno_ftf_114_852_k,
$classno_ftf_115_852_h, $keyword_ftf_5_520_a, $voldetails_ftf_110_440_v,
$dateofentry_ftf_122_952_v, $notes_ftf_97_500_a, $pubprice_151_952_r,
$currency_153_590_b, $reccreated_123_508_a, $remainder) = split(/\t/, $_, 23);

if (($biblionumber_ftf_691_090_c !~ /[^\d]/) and ($title_ftf_4_245_a !~


/_B_L_A_N_K_/) and ($repeated_items !~ /$biblionumber_ftf_691_090_c/) ) {

$repeated_items .= " $biblionumber_ftf_691_090_c";

my @biblionumber_array;

open(INF, $input_file) or die "Can't open $input_file: $!";

my $i = 1;

while (<INF>) {

$i++;

if ($i >= $c) {

my $biblionumber_ftf_691_090_c2, my $title_ftf_4_245_a2, my
$edition_ftf_7_250_a2, my $publisher_ftf_11_260_b2, my
$publishcountry_ftf_12_260_a2, my $publishyear_ftf_13_260_c2, my
$author1ee_ftf_18_100_a2, my $author1se_ftf_19_100_a2, my
$author2ee_ftf_20_700_a2, my $author2se_ftf_21_700_a2, my
$adiauthors_ftf_24_700_a2, my $role_ftf_38_590_a2, my $phydescr_ftf_10_300_a2,
my $classno_ftf_114_852_k2, my $classno_ftf_115_852_h2, my
$keyword_ftf_5_520_a2, my $voldetails_ftf_110_440_v2, my
$dateofentry_ftf_122_952_v2, my $notes_ftf_97_500_a2, my $pubprice_151_952_r2,
my $currency_153_590_b2, my $reccreated_123_508_a2, my $remainder2;

($biblionumber_ftf_691_090_c2, $title_ftf_4_245_a2, $edition_ftf_7_250_a2,


$publisher_ftf_11_260_b2, $publishcountry_ftf_12_260_a2,
$publishyear_ftf_13_260_c2, $author1ee_ftf_18_100_a2, $author1se_ftf_19_100_a2,
$author2ee_ftf_20_700_a2, $author2se_ftf_21_700_a2, $adiauthors_ftf_24_700_a2,
$role_ftf_38_590_a2, $phydescr_ftf_10_300_a2, $classno_ftf_114_852_k2,
$classno_ftf_115_852_h2, $keyword_ftf_5_520_a2, $voldetails_ftf_110_440_v2,
$dateofentry_ftf_122_952_v2, $notes_ftf_97_500_a2, $pubprice_151_952_r2,
$currency_153_590_b2, $reccreated_123_508_a2, $remainder2) = split(/\t/, $_,
23);

if (($biblionumber_ftf_691_090_c2 !~ /[^\d]/) and ($title_ftf_4_245_a2 !~


/_B_L_A_N_K_/) and ($title_ftf_4_245_a2 eq $title_ftf_4_245_a) and
($author1ee_ftf_18_100_a2 eq $author1ee_ftf_18_100_a)){

print "$biblionumber_ftf_691_090_c:$biblionumber_ftf_691_090_c2\t";

$repeated_items .= " $biblionumber_ftf_691_090_c2";

push @biblionumber_array, $biblionumber_ftf_691_090_c2;

print "\n";

close(INF);

my $record = MARC::Record->new();

if ($author1ee_ftf_18_100_a =~ /_B_L_A_N_K_/) {

$author1ee_ftf_18_100_a = "";

if ($author1se_ftf_19_100_a =~ /_B_L_A_N_K_/) {

$author1se_ftf_19_100_a = "";
}

my $author1_ftf = join(" ", $author1se_ftf_19_100_a, $author1ee_ftf_18_100_a);

if ($author1_ftf ne "") {

my $author1 = MARC::Field->new(

'100','1','',

a => $author1_ftf

);

$record->add_fields($author1);

if ($title_ftf_4_245_a !~ /_B_L_A_N_K_/) {

my $title = MARC::Field->new(

'245','1','2',

a => $title_ftf_4_245_a

);

$record->add_fields($title);

if ($edition_ftf_7_250_a !~ /_B_L_A_N_K_/) {

my $edition = MARC::Field->new(

'250',,,

a => $edition_ftf_7_250_a

);
$record->add_fields($edition);

if ($publishcountry_ftf_12_260_a !~ /_B_L_A_N_K_/) {

my $publishcountry = MARC::Field->new(

'260',,,

a => $publishcountry_ftf_12_260_a

);

$record->add_fields($publishcountry);

if ($publisher_ftf_11_260_b =~ /_B_L_A_N_K_/) {

$publisher_ftf_11_260_b = "";

if ($publishyear_ftf_13_260_c =~ /_B_L_A_N_K_/) {

$publishyear_ftf_13_260_c = "";

my $publisher = MARC::Field->new(

'260',,,

b => $publisher_ftf_11_260_b,

c => $publishyear_ftf_13_260_c

);

$record->add_fields($publisher);
if ($phydescr_ftf_10_300_a =~ /_B_L_A_N_K_/) {

$phydescr_ftf_10_300_a = "";

my $phydescr = MARC::Field->new(

'300',,,

a => $phydescr_ftf_10_300_a,

f => 'BOOK'

);

$record->append_fields($phydescr);

if ($voldetails_ftf_110_440_v !~ /_B_L_A_N_K_/) {

my $voldetails = MARC::Field->new(

'440','','3',

v => $voldetails_ftf_110_440_v

);

$record->add_fields($voldetails);

if ($notes_ftf_97_500_a !~ /_B_L_A_N_K_/) {

my $notes = MARC::Field->new(

'500',,,

a => $notes_ftf_97_500_a

);

$record->add_fields($notes);
}

if ($reccreated_123_508_a !~ /_B_L_A_N_K_/) {

my $reccreated = MARC::Field->new(

'508',,,

a => $reccreated_123_508_a

);

$record->add_fields($reccreated);

if ($keyword_ftf_5_520_a !~ /_B_L_A_N_K_/) {

my $keyword = MARC::Field->new(

'520',,,

a => $keyword_ftf_5_520_a

);

$record->add_fields($keyword);

if ($role_ftf_38_590_a =~ /_B_L_A_N_K_/) {

$role_ftf_38_590_a = '';

if ($currency_153_590_b =~ /_B_L_A_N_K_/) {

$currency_153_590_b = '';

}
my $role = MARC::Field->new(

'590',,,

a => $role_ftf_38_590_a,

b => $currency_153_590_b

);

$record->add_fields($role);

if ($author2ee_ftf_20_700_a =~ /_B_L_A_N_K_/) {

$author2ee_ftf_20_700_a = "";

if ($author2se_ftf_21_700_a =~ /_B_L_A_N_K_/) {

$author2se_ftf_21_700_a = "";

if ($adiauthors_ftf_24_700_a =~ /_B_L_A_N_K_/) {

$adiauthors_ftf_24_700_a = "";

my $adiauthors_ftf = join(" ", $author2se_ftf_21_700_a,


$author2ee_ftf_20_700_a, $adiauthors_ftf_24_700_a);

if ($adiauthors_ftf ne "") {

my $adiauthors = MARC::Field->new(

'700','1','',

a => $adiauthors_ftf

);
$record->add_fields($adiauthors);

if ($classno_ftf_114_852_k =~ /_B_L_A_N_K_/) {

if ($classno_ftf_115_852_h =~ /_B_L_A_N_K_/) {

my $classno = MARC::Field->new(

'852',,,

k => '999.9999'

);

$record->add_fields($classno);

else {

if ($classno_ftf_115_852_h =~ /^\d\d\d/) {

my $classno = MARC::Field->new(

'852',,,

k => $classno_ftf_115_852_h

);

$record->add_fields($classno);

else {

my $classno = MARC::Field->new(

'852',,,
k => '999.9998',

h => $classno_ftf_115_852_h

);

$record->add_fields($classno);

else {

if ($classno_ftf_114_852_k =~ /^\d\d\d/) {

if ($classno_ftf_115_852_h =~ /_B_L_A_N_K_/) {

$classno_ftf_115_852_h = "";

my $classno = MARC::Field->new(

'852',,,

k => $classno_ftf_114_852_k,

h => $classno_ftf_115_852_h

);

$record->add_fields($classno);

else {

if ($classno_ftf_115_852_h =~ /^\d\d\d/) {

my $classno = MARC::Field->new(
'852',,,

k => $classno_ftf_115_852_h,

h => $classno_ftf_114_852_k

);

$record->add_fields($classno);

else {

if ($classno_ftf_115_852_h =~ /_B_L_A_N_K_/) {

$classno_ftf_115_852_h = "";

my $classno = MARC::Field->new(

'852',,,

k => '999.9997',

h => $classno_ftf_115_852_h

);

$record->add_fields($classno);

if ($pubprice_151_952_r =~ /_B_L_A_N_K_/) {

$pubprice_151_952_r = '';
}

if ($dateofentry_ftf_122_952_v =~ /_B_L_A_N_K_/) {

$dateofentry_ftf_122_952_v = '';

my @biblionumber_array_tmp = sort @biblionumber_array;

foreach (@biblionumber_array_tmp) {

my $biblionumber = $_;

my $barcode = MARC::Field->new(

'952',,,

b => "MAIN",

d => "MAIN",

p => $biblionumber,

r => $pubprice_151_952_r,

u => $biblionumber,

v => $dateofentry_ftf_122_952_v

);

$record->add_fields($barcode);

#print "\n";

print OUTFILE $record->as_usmarc();

}
else {

#print $_;

ISIS -> XML -> KOHA

Script Perl (XML -> KOHA)


#!/usr/bin/perl

use strict;
package xml2koha;

use vars qw( $opt_m $opt_v $opt_c $opt_f $opt_p $opt_d $opt_q);
use Getopt::Std;

use XML::Twig;
# use XML::Checker::Parser;
use MARC::Record;

use C4::Context;
use C4::Biblio;

use Term::Activity;

&usage() unless getopts('mvpdcqf:');


&usage() unless $opt_f;

# get configuration settings


do "xml2koha.conf";

my $xml_file = $opt_f;

our $ldr = &make_leader();


our $tag_008 = &make_008();

our %tags;
our %map;

our $marc_rec = MARC::Record->new();


our $dbh = C4::Context->dbh;

our $ta; # $ta->tick;

die "Can't find '$xml_file': $!\n" unless -f $xml_file;

# always go into quiet mode when printing MARC to STDOUT


$opt_q = 1 if $opt_p;

if( $opt_v ) {
# validate the XML
# print "Validating XML file..." unless $opt_q;
# validate($xml_file);
# print "done\n" unless $opt_q;
}
if( $opt_m ) {
# make XML to MARC map file
print "Making XML to MARC map..." unless $opt_q;
make_map($xml_file);
print "done\n" unless $opt_q;
}

if ($opt_d) {
# remove any trace of previous records in koha db
print "Deleting biblios..." unless $opt_q;
$dbh->do("delete from biblio");
$dbh->do("delete from biblioitems");
$dbh->do("delete from items");
$dbh->do("delete from bibliosubject");
$dbh->do("delete from additionalauthors");
$dbh->do("delete from bibliosubtitle");
$dbh->do("delete from marc_biblio");
$dbh->do("delete from marc_subfield_table");
$dbh->do("delete from marc_word");
$dbh->do("delete from marc_blob_subfield");
print "done\n" unless $opt_q;
}

if( $opt_p ) {
# always go into quiet mode when printing MARC to STDOUT
$opt_q = 1;

# print to STDOUT in a human readable format


convert($xml_file);

# don't run convert when printing as well


$opt_c = 0;

if( $opt_c ) {
#convert to MARC
$xml2koha::ta = new Term::Activity({label => 'records imported'})
unless $opt_q;
convert($xml_file);
}

################### validate ###########################


# Check that this XML file survives parsing
########################################################
#sub validate {
# my($xml_file) = @_;
# my %expat_options = (KeepCDATA => 1,
# SkipExternalDTD => 1
# );
#
# my $xp = new XML::Checker::Parser(%expat_options);
# eval {
# local $XML::Checker::FAIL = \&my_fail;
# $xp->parsefile($xml_file);
# };
# if ($@) {
# print "$xml_file failed validation!\n";
# die "$@";
# }
#}
################ my_fail ##############################
# I can't get ISIS2XML to produce a DTD so in all cases
# please ignore undefined element (101) and
# attribute (103) errors.
#######################################################
sub my_fail {
my $code = shift;
if($code > 109) {
die XML::Checker::error_string ($code, @_) if $code < 200;
XML::Checker::print_error ($code, @_);
}
}

####################### make_map #######################


# make a map file for the user. The map file will
# translate xml elements into marc tags
########################################################
sub make_map {
my($xml_file,) = @_;
my $twig = new XML::Twig(
keep_spaces => 1,
TwigHandlers => { $xml2koha::RECORD_ELEMENT =>
\&map_record }
);
$twig->parsefile($xml_file);

if(-f $xml2koha::MAPFILE) {
return(0) unless &y_or_n(
"The map file ($xml2koha::MAPFILE) already exists.
Are you sure you wish to overwrite it?");
}

open(MAPFILE,"> $xml2koha::MAPFILE") ||
die "Can't open output '$xml2koha::MAPFILE':$!\n";

print MAPFILE "#\n# XML to MARC mapping derived from $xml_file\n#\n\n";

print MAPFILE "# Some counts of Elements found in $xml_file\n";


print MAPFILE "# Count\t\tElement/Tag Name\n";
foreach my $tag (sort keys(%xml2koha::tags)) {
my $count = $xml2koha::tags{$tag};
print MAPFILE "# $count\t\t$tag\n";
}

print MAPFILE "\n\n";


foreach my $tag (sort keys(%xml2koha::tags)) {
my $count = $xml2koha::tags{$tag};
print MAPFILE "000 ## \%$tag\n";
}
}

##################### map_record #######################


# Collect all the elements in each record. While I'm
# collecting them I might as well count how many of
# each element is in the XML file. All the tags or
# elements will be stored in the tags array.
########################################################
sub map_record {
my($twig, $record) = @_;
my $el = $record->first_child();
if($el) {
do {
my $name = $el->gi;
$xml2koha::tags{$name}++;
} while( $el = $el->next_sibling());
}
$twig->purge;
}

################### make_leader ########################


# make a leader tag (LDR or 000)
########################################################
sub make_leader {

# an example leader
# 1 2
# 012345678901234567890123
# *****nam##22*****#a#4500

# 012345678901234567890123
my @ldr = split(//,'************************');
$ldr[5] = 'n'; # new item
$ldr[6] = 'a'; # language material. ie book
$ldr[7] = 'm'; # it's a monograph
$ldr[8] = '#'; # No specific type
$ldr[9] = '#'; # MARC-8
$ldr[10] = '2'; # indicators are 2 chars
$ldr[11] = '2'; # subfields are 2 chars
$ldr[17] = '5'; # Partial (preliminary) level
# Look, the previous db is a mess
$ldr[18] = '#'; # Non-ISBD
$ldr[19] = '#'; # Related record not required
$ldr[20] = '4'; # spec just says put these numbers in
$ldr[21] = '5';
$ldr[22] = '0';
$ldr[23] = '0';
return join('',@ldr);
}

##################### make_008 #########################


# make a 008 field for my books
########################################################
sub make_008 {

# an example 008 tag


# 1 2 3
# 0123456789012345678901234567890123456789
# 820305s1991####nyu###########001#0#eng##

# 0123456789012345678901234567890123456789
my @tag_008 = split(//,'########################################');

my ($day, $month, $year) = (localtime)[3,4,5];

# date marc record was created


my @date_str = split(//,(sprintf("%02d%02d%02d",
($year+1900) % 100,$month+1,$day)));
for(my $i = 0; $i <= 5; $i++) { $tag_008[$i] = $date_str[$i]; }

# 008/07-10 (Date 1) and 008/11-14 (Date 2)


# no date specified
$tag_008[6] = 'b';

# Place of publication, production, or execution


# No attempt to code this
# 15..17
for(my $i = 15; $i <= 17; $i++) { $tag_008[$i] = '|'; }
# book related info
# 18..34
for(my $i = 18; $i <= 34; $i++) { $tag_008[$i] = '|'; }

# language of material
# once again, no attempt made
# 35..37
for(my $i = 35; $i <= 37; $i++) { $tag_008[$i] = '|'; }

# Modified record
# No attempt
$tag_008[38] = '|';

# Cataloging source
# No attempt
$tag_008[39] = '|';

return join('',@tag_008);
}

################# convert ##############################


# Convert the CML to Koha DB records
########################################################
sub convert {
my($xml_file) = @_;
%xml2koha::map = &get_map($xml2koha::MAPFILE);

my $twig = new XML::Twig(


TwigHandlers => {
$xml2koha::RECORD_ELEMENT => \&convert_record }
);
$twig->parsefile($xml_file);
}

############### convert_record #########################


# twig handler. Called every time a new record is
# processed
########################################################
sub convert_record {
my($twig, $record) = @_;
my %items;

my $mfn = $record->att("MFN");

$xml2koha::ta->tick unless $opt_q;

$xml2koha::marc_rec = MARC::Record->new();

# set the leader for the record


$xml2koha::marc_rec->leader($xml2koha::ldr);

# set the 008 tag since we're dealing with books


my $field = MARC::Field->new('008',$xml2koha::tag_008);
$xml2koha::marc_rec->append_fields($field);

# add default tags from config file


$xml2koha::marc_rec->add_fields(@{$xml2koha::DEFAULT_TAGS});

my $el = $record->first_child();
if($el) {
do {
my $key = $el->gi();
my $value = $el->text();
# these symbols cause havoc in web-based systems so dump
# them.
$value =~ s/<//;
$value =~ s/>//;
$items{$key} = $value;
&add_field($key,$value);
} while( $el = $el->next_sibling());
}

# add the MFN


if($mfn) {
# check whether a 952 tag already exists
if(my $field = $xml2koha::marc_rec->field('952')) {
# if so then add a p subfield
$field->update('p' => $mfn);
} else {
# if not then make a new 952 tag
my $field = MARC::Field->new('952','','','p' => $mfn);
}
}

# only print to STDOUT if that is what you asked


print $xml2koha::marc_rec->as_formatted(), "\n" if $opt_p;

# When in print mode don't save to koha


&koha_save unless $opt_p;

# try and be tidy by deleting this twig when done


$twig->purge;
}

################# add_field ############################


# gather XML elements and make them fields in a
# MARC::Record
########################################################
sub add_field {
my($xml_element,$element_value) = @_;
my $tag;
my $indicator_1;
my $indicator_2;
my $subfield;
my %fields;
my $merge;

# first get all the required values for this xml element out of
# map defined by the user

$tag = $xml2koha::map{$xml_element}->{'tag'};
$indicator_1 = $xml2koha::map{$xml_element}->{'indicator_1'};
$indicator_2 = $xml2koha::map{$xml_element}->{'indicator_2'};
$subfield = $xml2koha::map{$xml_element}->{'subfield'};
$merge = $xml2koha::map{$xml_element}->{'merge'};

# check whether this tag has already been inserted. If not then
# it won't be a merge.
if(!$xml2koha::marc_rec->field($tag)) {
$merge = 0;
# no matter what, we have a new tag so make the subfields hash
# straight away
%fields = ($subfield => $element_value);
}

if($merge) {
# The tag already exists so get the subfields hash and
# add or append new subfields.
if(my $text = $xml2koha::marc_rec->field($tag)->subfield($subfield)) {
# update the subfield
$text .= ' ' . $element_value;
$xml2koha::marc_rec->field($tag)->update($subfield => $text);
}
else {
# add a new subfield
$xml2koha::marc_rec->field($tag)->add_subfields($subfield,
$element_value);
}
# The tag already exists so check whether indicators should
# be updated or added or left alone
if(my $ind1 = $xml2koha::marc_rec->field($tag)->indicator(1)) {
# update an indicator
if($indicator_1 =~ m/\d/) {
if($ind1 !~ m/\d/) {
$xml2koha::marc_rec->field($tag)->
update(ind1 => $indicator_1);
};
}
}
else {
# add a new indicator
$xml2koha::marc_rec->field($tag)->
update(ind1 => $indicator_1);
}

# The tag already exists so check whether indicators should


# be updated or added or left alone
if(my $ind2 = $xml2koha::marc_rec->field($tag)->indicator(2)) {
# update an indicator
if($indicator_2 =~ m/\d/) {
if($ind2 =~ m/\#/) {
$xml2koha::marc_rec->field($tag)->
update(ind2 => $indicator_2);
};
}
}
else {
# add a new indicator
$xml2koha::marc_rec->field($tag)->
update(ind2 => $indicator_2);
}

}
else {
# always add fields that are not merged together.
# tag 650 for example.
my $field = MARC::Field->new($tag,
$indicator_1,
$indicator_2,
$subfield => $element_value);
$xml2koha::marc_rec->append_fields($field);
}
}

################# koha_save ############################


# Write the MARC::Record into koha db
########################################################
sub koha_save {
# $record = MARC::File::USMARC::decode(char_decode($record->as_usmarc(),
$char_encoding));
# warn "$i ==>".$record->as_formatted() if $verbose eq 2;
my ($tagfield,$tagsubfield) =
&MARCfind_marc_from_kohafield($dbh,"items.itemnumber");
my @fields = $xml2koha::marc_rec->field($tagfield);
my @items;
my $nbitems=0;

foreach my $field (@fields) {


my $item = MARC::Record->new();
$item->append_fields($field);
push @items,$item;
$xml2koha::marc_rec->delete_field($field);
$nbitems++;
}

# now, create biblio and items with NEWnewXX call.


my ($bibid,$oldbibnum,$oldbibitemnum) = NEWnewbiblio($dbh,
$xml2koha::marc_rec);
for (my $i=0;$i<=$#items;$i++) {
NEWnewitem($dbh,$items[$i],$bibid);
}

################ get_map ###############################


# returns an associative array of the tags, indicators
# and subfields defined by the user
########################################################
sub get_map {
my($infile) = @_;
my %tags;
my $sub_field;
my $data;

open(INFILE,$infile) || die "Can't open input '$infile':$!\n";


while(<INFILE>) {
chomp; # ditch the end of line marker
s/^\s*//; # ditch the leading spaces
s/\s*$//; # ditch the trailing spaces

# might just be a blank line as well


next if length == 0;

# is the line a comment. if so then skip it


next if /^\s*#/;

# always start with a blank row


my %row = ();

# split the line using a space as the delimiter


my ($tag,$indicators,$the_rest) = split(/ /,$_,3);
$row{'tag'} = $tag;
($row{'indicator_1'},$row{'indicator_2'}) = split(//,$indicators);

# check for sub fields


if($the_rest =~ /^\s*\$/) {
($sub_field,$data) = split(/ /,$the_rest,2);
$row{'subfield'} = substr($sub_field,1);
$row{'data'} = substr($data,1);

# if the field starts with a % then this will be merged with


# the same tag / subfield
if($data =~ /\%./) {$row{'merge'} = 1;}
else { $row{'merge'} = 0; }
}
else {
$row{'data'} = substr($the_rest,1);

# if the field starts with a % then this will be merged with


# the same tag / subfield
if($data =~ /\%./) { $row{'merge'} = 1; }
else { $row{'merge'} = 0; }
}

# gather all my rows together


$tags{substr($data,1)} = \%row;

}
# share my rows with evriwun else
return %tags;
}

################ y_or_n ###############################


# Simple prompter
#######################################################
sub y_or_n {
my($prompt) = @_;
print STDOUT $prompt;
my $answer = scalar(<STDIN>);
$answer =~ /^y/i;
}

################ usage ################################


# Tell the user how to run me
#######################################################
sub usage {
print "
USAGE:
xml2koha.pl -mvcdpqf filename

-m map
Makes a map file in the current directory called
xml2koha.map

-v validates the XML file used for input

-c converts the XML file to MARC

-d Deletes all bibliographic records in the Koha DB

-p Print to STDOUT only. Do not write records into koha.


Use this option to test the process and revised map file

-q Quiet mode. Don't advise me of what is going on

-f Sets the XML file used for input. You'll to set


this everytime the program is run.
";
exit();
}

Lenguaje de Formateo (PFT)


El siguiente es el lenguaje de formateo ISIS utilizado para generar un archivo XML con los datos de
la base que se importarán a KOHA.

mhu "<REGISTRO>""<Tag_1>"d1,if v1*0.1<>'^' then v1^* fi


"</Tag_1>"d1,"<Tag_3_a>"v3^a"</Tag_3_a>""<Tag_3_b>"v3^b"</Tag_3_b>""<Tag_3_c>"v3
^c"</Tag_3_c>"d3"<Tag_5>"d5 if v5*0.1<>'^' then v5^* fi
"</Tag_5>"d5,"<Tag_6>"d6,if v6*0.1<>'^' then v6^* fi "</Tag_6>"d6,"<Tag_8>"d8 if
v8*0.1<>'^' then v8^* fi "</Tag_8>"d8,"<Tag_10>"d10 if v10*0.1<>'^' then v10^*
fi "</Tag_10>"d10,"<Tag_11>"d11 if v11*0.1<>'^' then v11^* fi
"</Tag_11>"d11,"<Tag_14_a>"v14^a"</Tag_14_a>""<Tag_14_b>"v14^b"</Tag_14_b>"d14,"
<Tag_15>"d15 if v15*0.1<>'^' then v15^* fi
"</Tag_15>"d15,"<Tag_20_t>"v20^t"</Tag_20_t>""<Tag_20_s>"v20^s"</Tag_20_s>""<Tag
_22_a>"v22^a"</Tag_22_a>"d22,"<Tag_23_s>"v23^s"</Tag_23_s>""<Tag_23_p>"v23^p"</T
ag_23_p>""<Tag_23_c>"v23^c"</Tag_23_c>""<Tag_23_i>"v23^i"</Tag_23_i>"d23,"<Tag_2
4_t>"v24^t"</Tag_24_t>""<Tag_24_s>"v24^s"</Tag_24_s>"d24,"<Tag_27>"d27, if
v27*0.1<>'^' then v27^* fi
"</Tag_27>"d27,"<Tag_28_a>"v28^a"</Tag_28_a>""<Tag_28_c>"v28^c"</Tag_28_c>""<Tag
_28_f>"v28^f"</Tag_28_f>"d28,"<Tag_29_p>"v29^p"</Tag_29_p>""<Tag_29_s>"v29^s"</T
ag_29_s>""<Tag_29_t>"v29^t"</Tag_29_t>""<Tag_29_o>"v29^o"</Tag_29_o>""<Tag_29_f>
"v29^f"</Tag_29_f>"d29,"<Tag_30_t>"v30^t"</Tag_30_t>""<Tag_30_s>"v30^s"</Tag_30_
s>"d30,"<Tag_33_a>"v33^a"</Tag_33_a>"d33,"<Tag_34_s>"v34^s"</Tag_34_s>""<Tag_34_
p>"v34^p"</Tag_34_p>""<Tag_34_c>"v34^c"</Tag_34_c>""<Tag_34_i>"v34^i"</Tag_34_i>
"d34,"<Tag_36_a>"v36^a"</Tag_36_a>""<Tag_36_b>"v36^b"</Tag_36_b>"d36,"<Tag_40_n>
"v40^n"</Tag_40_n>""<Tag_40_x>"v40^x"</Tag_40_x>""<Tag_40_o>"v40^o"</Tag_40_o>"d
40,"<Tag_41_l>"v41^l"</Tag_41_l>""<Tag_41_p>"v41^p"</Tag_41_p>"d41,"<Tag_42>"d42
, if v42*0.1<>'^' then v42^* fi "</Tag_42>"d42,"<Tag_44>"d44, if v44*0.1<>'^'
then v44^* fi "</Tag_44>"d44,"<Tag_45>"d45,if v45*0.1<>'^' then v45^* fi
"</Tag_45>"d45,"<Tag_47_l>"v47^l"</Tag_47_l>""<Tag_47_e>"v47^e"</Tag_47_e>"d47,"
<Tag_48>"d48,if v48*0.1<>'^' then v48^* fi "</Tag_48>"d48,"<Tag_50>"d50,if
v50*0.1<>'^' then v50^* fi "</Tag_50>"d50,"<Tag_52>"d52,if v52*0.1<>'^' then
v52^* fi "</Tag_52>"d52,"<Tag_53>"d53,if v53*0.1<>'^' then v53^* fi
"</Tag_53>"d53,"<Tag_54_a>"v54^a"</Tag_54_a>""<Tag_54_b>"v54^b"</Tag_54_b>""<Tag
_54_c>"v54^c"</Tag_54_c>"d54,"<Tag_55_n>"v55^n"</Tag_55_n>""<Tag_55_e>"v55^e"</T
ag_55_e>""<Tag_55_g>"v55^g"</Tag_55_g>""<Tag_55_c>"v55^c"</Tag_55_c>""<Tag_55_d>
"v55^d"</Tag_55_d>"d55,"<Tag_59>"d59,if v59*0.1<>'^' then v59^* fi
"</Tag_59>"d59,"<Tag_62>"d62,if v62*0.1<>'^' then v62^* fi
"</Tag_62>"d62,"<Tag_65>"d65,if v65*0.1<>'^' then v65^* fi
"</Tag_65>"d65,"<Tag_75>"d75,if v75*0.1<>'^' then v75^* fi
"</Tag_75>"d75,"<Tag_76>"d76 if v76*0.1<>'^' then v76^* fi
"</Tag_76>"d76,"<Tag_77>"d77,if v77*0.1<>'^' then v77^* fi
"</Tag_77>"d77,"<Tag_78>"d78, if v78*0.1<>'^' then v78^* fi
"</Tag_78>"d78,"<Tag_79>"d79, if v79*0.1<>'^' then v79^* fi
"</Tag_79>"d79,"<Tag_84>"d84, if v84*0.1<>'^' then v84^* fi
"</Tag_84>"d84,"<Tag_85>"d85,if v85*0.1<>'^' then v85^* fi
"</Tag_85>"d85,"<Tag_90_a>"v90^a"</Tag_90_a>""<Tag_90_b>"v90^b"</Tag_90_b>""<Tag
_90_c>"v90^c"</Tag_90_c>"d90,"<Tag_92>"d92,if v92*0.1<>'^' then v92^* fi
"</Tag_92>"d92,"<Tag_94>"d94,if v94*0.1<>'^' then v94^* fi
"</Tag_94>"d94,"<Tag_96>"d96, if v96*0.1<>'^' then v96^* fi
"</Tag_96>"d96,"<Tag_99>"d99, if v99*0.1<>'^' then v99^* fi
"</Tag_99>"d99,"<Tag_100>"d100,if v100*0.1<>'^' then v100^* fi
"</Tag_100>"d100,'</REGISTRO>'

xml2koha.map
#
# XML to MARC mapping derived from data/CAMZA.xml
#

# Some counts of Elements found in data/CAMZA.xml


# Count Element/Tag Name
# 4 Tag_24_s
# 18 Tag_24_t
# 17 Tag_28_a
# 18 Tag_47_e
# 18 Tag_47_l
# 18 Tag_77

245 ## $b %Tag_24_s
245 ## $a %Tag_24_t
100 ## $a @Tag_28_a
260 ## $b %Tag_47_e
260 ## $a %Tag_47_l
952 ## $p %Tag_77

020 ## $a @Tag_10
020 ## $a @Tag_11
040 ## $a %Tag_76
041 ## $a @Tag_50
044 ## $a @Tag_48
080 ## $a %Tag_75_c
080 ## $b %Tag_75_l
100 ## $a @Tag_28_a
100 ## $a @Tag_28_b
100 ## $d @Tag_28_d
100 ## $c @Tag_28_o
245 ## $c @Tag_28_f
245 ## $a @Tag_24_t
245 ## $b @Tag_24_s
245 ## $c @Tag_24_r
110 ## $a @Tag_29_e
110 ## $b @Tag_29_j
110 ## $c @Tag_29_l
110 ## $g @Tag_29_p
111 ## $a @Tag_40_n
111 ## $c @Tag_41_l
111 ## $d @Tag_42
111 ## $n @Tag_40_x
240 ## $a %Tag_27
250 ## $a %Tag_44
260 ## $b @Tag_47_e
260 ## $a @Tag_47_l
260 ## $c %Tag_45
300 ## $a %Tag_52_e
300 ## $b %Tag_52_i
440 ## $a @Tag_36_t
440 ## $n @Tag_36_s
440 ## $p @Tag_36_d
440 ## $v @Tag_12
440 ## $x %Tag_15
500 ## $a @Tag_59
653 ## $a @Tag_62
650 ## $a @Tag_65
900 ## $ %Tag_999
920 ## $ %Tag_77

También podría gustarte