First stab at a marc map as a fast alternat to XSLT
[pazpar2-moved-to-github.git] / src / marcmap.c
diff --git a/src/marcmap.c b/src/marcmap.c
new file mode 100644 (file)
index 0000000..a468d3e
--- /dev/null
@@ -0,0 +1,191 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+
+#include <yaz/nmem.h>
+
+#include <marcmap.h>
+#include <marchash.h>
+
+struct marcmap *marcmap_load(char *filename, NMEM nmem) {
+    struct marcmap *mm;
+    struct marcmap *mmhead;
+    FILE *fp;
+    char c;
+    char buf[256];
+    int len;
+    int field;
+    int newrec;
+
+    len = 0;
+    field = 0;
+    newrec = 1;
+    mm = NULL;
+    mmhead = NULL;
+    fp = fopen(filename, "r");
+
+    while ((c = getc(fp) ) != EOF) 
+    {
+        // allocate some space
+        if (newrec)
+        {
+            if (mm != NULL) 
+            {
+                mm->next = nmem_malloc(nmem, sizeof(struct marcmap));
+                mm = mm->next;
+            }
+            // first one!
+            else 
+            { mm = nmem_malloc(nmem, sizeof(struct marcmap));
+                mmhead = mm;
+            }
+            newrec = 0;
+        }
+       // whitespace saves and moves on
+       if (c == ' ' || c == '\n' || c == '\t')
+        {
+            buf[len] = '\0';
+            len++;
+            // first field, marc
+            if (field == 0)
+            {
+                // allow blank lines
+               if (!(len <3))
+                {
+                    mm->field = nmem_malloc(nmem, len * sizeof(char));
+                    strncpy(mm->field, buf, len);
+                }
+            }
+            // second, marc subfield, just a char
+            else if (field == 1)
+            {
+                mm->subfield = buf[len-2];
+            }
+            // third, pz fieldname
+            else if (field == 2) 
+            { 
+                mm->pz = nmem_malloc(nmem, len * sizeof(char));
+                strncpy(mm->pz, buf, len);
+            }
+
+            // new line, new record
+            if (c == '\n')
+            {
+                field = 0;
+                newrec = 1;
+            }
+            else
+            {
+                field++;
+            }
+            len = 0;
+        }
+        else
+        {
+            buf[len] = c;
+            len++;
+        }
+    }
+    mm->next = NULL;
+    return mmhead;
+}
+
+xmlDoc *marcmap_apply(struct marcmap *marcmap, xmlDoc *xml_in)
+{
+    char mergekey[1024];
+    char medium[32];
+    char *s;
+    NMEM nmem;
+    xmlNsPtr ns_pz;
+    xmlDocPtr xml_out;
+    xmlNodePtr xml_out_root;
+    xmlNodePtr rec_node;
+    xmlNodePtr meta_node; 
+    struct marchash *marchash;
+    struct marcfield *field;
+    struct marcsubfield *subfield;
+    struct marcmap *mmcur;
+     
+    xml_out = xmlNewDoc(BAD_CAST "1.0");
+    xml_out_root = xmlNewNode(NULL, BAD_CAST "record");
+    xmlDocSetRootElement(xml_out, xml_out_root);
+    ns_pz = xmlNewNs(xml_out_root, BAD_CAST "http://www.indexdata.com/pazpar2/1.0", BAD_CAST "pz"); 
+    nmem = nmem_create();
+    rec_node = xmlDocGetRootElement(xml_in);
+    marchash = marchash_create(nmem);
+    marchash_ingest_marcxml(marchash, rec_node);
+
+    mmcur = marcmap;
+    while (mmcur != NULL)
+    {
+        if (field = marchash_get_field(marchash, mmcur->field, NULL))
+            do
+            {
+                // field value
+                if ((mmcur->subfield == '$') && (s = field->val))
+                {
+                    meta_node = xmlNewChild(xml_out_root, ns_pz, BAD_CAST "metadata", s);
+                    xmlSetProp(meta_node, BAD_CAST "type", mmcur->pz); 
+                }
+                // catenate all subfields
+                else if ((mmcur->subfield == '*') && (s = marchash_catenate_subfields(field, " ", nmem)))
+                {
+                    meta_node = xmlNewChild(xml_out_root, ns_pz, BAD_CAST "metadata", s);
+                    xmlSetProp(meta_node, BAD_CAST "type", mmcur->pz);
+                }
+                // subfield value
+                else if (mmcur->subfield) 
+                {
+                    if (subfield = marchash_get_subfield(mmcur->subfield, field, NULL)) 
+                        do
+                            if (s = subfield->val)
+                            {
+                                meta_node = xmlNewChild(xml_out_root, ns_pz, BAD_CAST "metadata", s);
+                                xmlSetProp(meta_node, BAD_CAST "type", mmcur->pz);
+                            }
+                        while (subfield = marchash_get_subfield(mmcur->subfield, field, subfield));
+                }
+                
+            }
+            while (field = marchash_get_field(marchash, mmcur->field, field));
+        mmcur = mmcur->next;
+    }
+
+    // hard coded mappings
+
+    // medium
+    if ((field = marchash_get_field(marchash, "245", NULL)) && (subfield = marchash_get_subfield('h', field, NULL)))
+    {
+       strncpy(medium, subfield->val, 32);
+    }
+    else if ((field = marchash_get_field(marchash, "900", NULL)) && (subfield = marchash_get_subfield('a', field, NULL)))
+       strcpy(medium, "electronic resource");
+    else if ((field = marchash_get_field(marchash, "900", NULL)) && (subfield = marchash_get_subfield('b', field, NULL)))
+       strcpy(medium, "electronic resource");
+    else if ((field = marchash_get_field(marchash, "773", NULL)) && (subfield = marchash_get_subfield('t', field, NULL)))
+       strcpy(medium, "article");
+    else
+       strcpy(medium, "book");
+
+    meta_node = xmlNewChild(xml_out_root, ns_pz, BAD_CAST "metadata", BAD_CAST medium);
+    xmlSetProp(meta_node, BAD_CAST "type", BAD_CAST "medium");
+
+    // merge key
+    memset(mergekey, 0, 1024);
+    strcpy(mergekey, "title ");
+    if ((field = marchash_get_field(marchash, "245", NULL)) && (subfield = marchash_get_subfield('a', field, NULL)))
+        strncat(mergekey, subfield->val, 1023 - strlen(mergekey));
+    strncat(mergekey, " author ", 1023 - strlen(mergekey));
+    if ((field = marchash_get_field(marchash, "245", NULL)) && (subfield = marchash_get_subfield('a', field, NULL)))
+        strncat(mergekey, subfield->val, 1023 - strlen(mergekey));
+    strncat(mergekey, " medium ", 1023 - strlen(mergekey));
+    strncat(mergekey, medium, 1023 - strlen(mergekey));
+
+    xmlSetProp(xml_out_root, BAD_CAST "mergekey", BAD_CAST mergekey);
+
+    nmem_destroy(nmem);
+    return xml_out;
+}