Custom-Import

Motivation

VL kann bibliographische Standards wie z.B. mabxml oder marc direkt importieren. Es gibt jedoch auch Formate, die nur explizit in einer Domain gemapped werden können. Für diese Aufgabe müssen XSL-Transformationen implementiert werden.

Konfiguration

Die Konfiguration wird an der gewünschten Domain abgelegt:

[imports]
    [[custom]]
        # activate feature
        on = boolean(default=False)
        # trigger on these file extensions in import directory
        extensions = string_list(default=list('.xml'))
        # generate data records from input file
        # splitmode = dumb: use children of root element as data records
        splitmode = option(dumb, trafo, mets, default=dumb)
        # splitmode = trafo: split input file into data records that are stored
        # in OM_XML/rawCatalogData and fed into mapper trafo
        splitter = string(default='splitter.xsl')
        # map data records to MODS
        # also used for splitting in splitmode = mets
        mapper = string(default='xml2mods.xsl')

Beispiele

Die folgenden Beispiele operieren auf einer modsList mit zwei Datenpaketen in einer Datei mit dem Namen example_list.mods. Um auf *.mods Dateien zu triggern, wird imports.custom.extensions = .mods gesetzt.

<modsList xmlns="http://www.loc.gov/mods/v3" version="3.5">
    <mods>
        <recordInfo>
            <recordIdentifier>ABCDEF_0</recordIdentifier>
        </recordInfo>
    </mods>
    <mods>
        <recordInfo>
            <recordIdentifier>ABCDEF_1</recordIdentifier>
        </recordInfo>
    </mods>
</modsList>

splitmode = dumb

Der dumb Default-Mode ist in VL immer verfügbar. In diesem Modus werden einfach alle /* Elemente unter dem root-Tag modsList als Datenpakete verstanden. Der Dokumenttyp kann nicht beeinflusst werden. Ein passender imports.custom.mapper ohne weitere Logik hätte die Form:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:mods="http://www.loc.gov/mods/v3">
    <xsl:template match="/">
        <mods:mods>
            <mods:titleInfo>
                <mods:title>
                    <xsl:value-of select="//mods:recordIdentifier"/>
                </mods:title>
            </mods:titleInfo>
            <mods:recordInfo>
                <mods:recordIdentifier>
                    <xsl:value-of select="//mods:recordIdentifier"/>
                </mods:recordIdentifier>
            </mods:recordInfo>
        </mods:mods>
    </xsl:template>
</xsl:stylesheet>

Der mapper kopiert also einfach die mods:recordIdentifier aus dem Quell-MODS nach mods:title und mods:recordIdentifier im Ziel-MODS.

splitmode = trafo

Im trafo Mode muss eine XSL-Transformation mit konfigurierbaren Namen aus imports.custom.splitter implementiert werden. Eine solche splitter.xsl für das modsList Beispiel könnte folgende Form haben:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:mods="http://www.loc.gov/mods/v3">
    <xsl:template match="/">
        <records>
            <xsl:apply-templates/>
        </records>
    </xsl:template>
    <xsl:template match="mods:mods">
        <record type="book">
            <xsl:copy-of select="."/>
            <more data="from outer scope can be collected here"/>
        </record>
    </xsl:template>
</xsl:stylesheet>

Der Namen des root Elements (hier <records>) und der Kinder (hier <record>) sind beliebig. Am <record> Element kann der mit @type der VL-Dokumenttyp festgelegt werden. Im Gegensatz zum dumb Splitter können die Datenpakete frei aus dem gesamten Eingabedokument zusammengestellt werden.

Ein passender Mapper hat folgende Form:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:mods="http://www.loc.gov/mods/v3">
    <!-- match nested output of splitter.xsl -->
    <xsl:template match="/record/mods:mods">
        <!-- like dumb mode mapper above -->
    </xsl:template>
</xsl:stylesheet>

splitmode = mets

Im mets Mode muss ein METS im VL-Import-Profile via Mapper generiert werden. Gleichzeitig muss der Mapper Einzelpakete nach MODS mappen können. Die Einzelpakete für die Rohdaten müssen im METS neben den MODS-Paketen dmdSec/mdWrap[@MDTYPE=MODS] in mdWrap[@MDTYPE=rawCatalogData] abgelegt werden. Ein solcher Mapper hätte die Form:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:mods="http://www.loc.gov/mods/v3" xmlns:mets="http://www.loc.gov/METS/">
    <!-- generate METS if root element is modsList (initial import mode) -->
    <xsl:template match="/mods:modsList">
        <mets:mets>
            <xsl:for-each select="//mods:mods">
                <xsl:variable name="idn" select="mods:recordInfo/mods:recordIdentifier"/>
                <mets:dmdSec ID="DMD_{$idn}">
                    <mets:mdWrap MIMETYPE="text/xml" MDTYPE="MODS">
                        <mets:xmlData>
                            <mods:mods>
                                <mods:titleInfo>
                                    <mods:title><xsl:value-of select="$idn"/></mods:title>
                                </mods:titleInfo>
                                <mods:recordInfo>
                                    <mods:recordIdentifier>
                                        <xsl:value-of select="$idn"/>
                                    </mods:recordIdentifier>
                                </mods:recordInfo>
                            </mods:mods>
                        </mets:xmlData>
                    </mets:mdWrap>
                    <!-- stored in DB and used for MD-Update if mapper changed -->
                    <mets:mdWrap MIMETYPE="text/xml" MDTYPE="rawCatalogData">
                        <mets:xmlData>
                            <!-- only one element allowed here, we will only store first child -->
                            <xsl:copy-of select="."/>
                        </mets:xmlData>
                    </mets:mdWrap>
                </mets:dmdSec>
            </xsl:for-each>
            <mets:structMap TYPE="logical">
                <xsl:for-each select="//mods:recordIdentifier">
                    <mets:div TYPE="book" DMDID="DMD_{.}"/>
                </xsl:for-each>
            </mets:structMap>
        </mets:mets>
    </xsl:template>
    <!-- map raw mods from mdWrap/rawCatalogData during metadata update mode -->
    <xsl:template match="/mods:mods">
        <!-- share mapping with mets-generator -->
    </xsl:template>
</xsl:stylesheet>