JSON MARC decoding + tests
[yaz-moved-to-github.git] / src / marc_read_json.c
diff --git a/src/marc_read_json.c b/src/marc_read_json.c
new file mode 100644 (file)
index 0000000..19c570a
--- /dev/null
@@ -0,0 +1,167 @@
+/* This file is part of the YAZ toolkit.
+ * Copyright (C) 1995-2013 Index Data
+ * See the file LICENSE for details.
+ */
+
+/**
+ * \file marc_read_json.c
+ * \brief Implements reading of MARC in JSON format
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <yaz/marcdisp.h>
+#include <yaz/json.h>
+#include <yaz/yaz-util.h>
+
+static void parse_subfields(yaz_marc_t mt, struct json_node *sf, WRBUF wtmp)
+{
+    assert(sf->type == json_node_list);
+    for (; sf; sf = sf->u.link[1])
+    {
+        if (sf->u.link[0]->type == json_node_object &&
+            sf->u.link[0]->u.link[0]->type == json_node_list)
+        {
+            struct json_node *se = sf->u.link[0]->u.link[0];
+            for (; se; se = se->u.link[1])
+            {
+                if (se->u.link[0]->type == json_node_pair
+                    && se->u.link[0]->u.link[0]->type == json_node_string
+                    && se->u.link[0]->u.link[1]->type == json_node_string)
+                {
+                    wrbuf_rewind(wtmp);
+                    wrbuf_puts(wtmp, se->u.link[0]->u.link[0]->u.string);
+                    wrbuf_puts(wtmp, se->u.link[0]->u.link[1]->u.string);
+                    yaz_marc_add_subfield(mt, wrbuf_buf(wtmp), wrbuf_len(wtmp));
+                }
+            }
+        }
+    }
+}
+
+static void parse_field(yaz_marc_t mt, struct json_node *p,
+                        int indicator_length, WRBUF wtmp)
+{
+    if (p->type == json_node_pair && p->u.link[0]->type == json_node_string)
+    {
+        struct json_node *l = p->u.link[1];
+        if (l->type == json_node_string)
+        {
+            yaz_marc_add_controlfield(mt, p->u.link[0]->u.string,
+                                      l->u.string, strlen(l->u.string));
+        }
+        else if (l->type == json_node_object &&
+                 l->u.link[0]->type == json_node_list)
+        {
+            struct json_node *m;
+            char indicator[10];
+
+            memset(indicator, ' ', sizeof(indicator));
+            for (m = l->u.link[0]; m; m = m->u.link[1])
+            {
+                struct json_node *s = m->u.link[0];
+                if (s->type == json_node_pair)
+                {
+                    if (s->u.link[0]->type == json_node_string
+                        && !strncmp(s->u.link[0]->u.string, "ind", 3)
+                        && s->u.link[1]->type == json_node_string)
+                    {
+                        int ch = s->u.link[0]->u.string[3];
+                        if (ch >= '1' && ch < '9')
+                            indicator[ch - '1'] = s->u.link[1]->u.string[0];
+                    }
+                }
+            }
+            yaz_marc_add_datafield(mt, p->u.link[0]->u.string,
+                                   indicator, indicator_length);
+            for (m = l->u.link[0]; m; m = m->u.link[1])
+            {
+                struct json_node *s = m->u.link[0];
+                if (s->type == json_node_pair)
+                {
+                    if (s->u.link[0]->type == json_node_string
+                        && !strcmp(s->u.link[0]->u.string, "subfields")
+                        && s->u.link[1]->type == json_node_array)
+                    {
+                        parse_subfields(mt, s->u.link[1]->u.link[0], wtmp);
+                    }
+                }
+            }
+        }
+    }
+}
+
+int yaz_marc_read_json_node(yaz_marc_t mt, struct json_node *n)
+{
+    if (n && n->type == json_node_object)
+    {
+        int indicator_length;
+        int identifier_length;
+        int base_address;
+        int length_data_entry;
+        int length_starting;
+        int length_implementation;
+        struct json_node *l;
+        WRBUF wtmp = wrbuf_alloc();
+        for (l = n->u.link[0]; l; l = l->u.link[1])
+        {
+            if (l->u.link[0]->type == json_node_pair &&
+                l->u.link[0]->u.link[0]->type == json_node_string)
+            {
+                struct json_node *p = l->u.link[0];
+                if (!strcmp(p->u.link[0]->u.string, "leader") &&
+                    p->u.link[1]->type == json_node_string &&
+                    strlen(p->u.link[1]->u.string) == 24)
+                {
+                    yaz_marc_set_leader(mt, p->u.link[1]->u.string,
+                                        &indicator_length,
+                                        &identifier_length,
+                                        &base_address,
+                                        &length_data_entry,
+                                        &length_starting,
+                                        &length_implementation);
+                }
+                if (!strcmp(p->u.link[0]->u.string, "fields") &&
+                    p->u.link[1]->type == json_node_array &&
+                    p->u.link[1]->u.link[0] &&
+                    p->u.link[1]->u.link[0]->type == json_node_list)
+                {
+                    struct json_node *l;
+                    for (l = p->u.link[1]->u.link[0]; l; l = l->u.link[1])
+                    {
+                        if (l->u.link[0]->type == json_node_object)
+                        {
+                            if (l->u.link[0]->u.link[0] &&
+                                l->u.link[0]->u.link[0]->type == json_node_list)
+                            {
+                                struct json_node *m = l->u.link[0]->u.link[0];
+                                for (; m; m = m->u.link[1])
+                                    parse_field(mt, m->u.link[0],
+                                                indicator_length, wtmp);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        wrbuf_destroy(wtmp);
+        return 0;
+    }
+    return -1;
+}
+
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * c-file-style: "Stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+