LP#1053397 initial unapi.mmr() support
authorBill Erickson <berick@esilibrary.com>
Fri, 17 Jan 2014 19:36:36 +0000 (14:36 -0500)
committerBill Erickson <berick@esilibrary.com>
Fri, 17 Jan 2014 19:36:36 +0000 (14:36 -0500)
Signed-off-by: Bill Erickson <berick@esilibrary.com>
Open-ILS/src/sql/Pg/upgrade/XXXX.schema.unapi-mmr.sql [new file with mode: 0644]

diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.unapi-mmr.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.unapi-mmr.sql
new file mode 100644 (file)
index 0000000..cdcef16
--- /dev/null
@@ -0,0 +1,171 @@
+BEGIN;
+
+/*
+using unapi.bre_output_layout for now.  
+Do we need separate output config for mmr?
+*/
+
+CREATE OR REPLACE FUNCTION unapi.mmr (
+    mmr_id BIGINT,
+    format TEXT,
+    ename TEXT,
+    includes TEXT[],
+    org TEXT,
+    depth INT DEFAULT NULL,
+    slimit HSTORE DEFAULT NULL,
+    soffset HSTORE DEFAULT NULL,
+    include_xmlns BOOL DEFAULT TRUE,
+    pref_lib INT DEFAULT NULL
+)
+RETURNS XML AS $F$
+DECLARE
+    mmrec   metabib.metarecord%ROWTYPE;
+    leadrec biblio.record_entry%ROWTYPE;
+    subrec biblio.record_entry%ROWTYPE;
+    layout  unapi.bre_output_layout%ROWTYPE;
+    xfrm    config.xml_transform%ROWTYPE;
+    ouid    INT;
+    xml_buf TEXT; -- growing XML document
+    tmp_xml TEXT; -- single-use XML string
+    xml_frag TEXT; -- single-use XML fragment
+    top_el  TEXT;
+    output  XML;
+    hxml    XML;
+    axml    XML;
+    subxml  XML; -- subordinate records elements
+    sub_xpath TEXT; 
+BEGIN
+
+    -- xpath for extracting bre.marc values from subordinate records 
+    -- so they may be appended to the MARC of the master record prior
+    -- to XSLT processing.
+    -- subjects, isbn, issn, upc -- anything else?
+    sub_xpath := 
+      '//*[starts-with(@tag, "6") or @tag="020" or @tag="022" or @tag="024"]';
+
+    IF org = '-' OR org IS NULL THEN
+        SELECT shortname INTO org FROM evergreen.org_top();
+    END IF;
+
+    SELECT id INTO ouid FROM actor.org_unit WHERE shortname = org;
+
+    IF ouid IS NULL THEN
+        RETURN NULL::XML;
+    END IF;
+
+    SELECT INTO mmrec * FROM metabib.metarecord WHERE id = mmr_id;
+    IF NOT FOUND THEN
+        RETURN NULL::XML;
+    END IF;
+
+    /*
+    -- TODO: aggregate holdings from constituent records
+    IF format = 'holdings_xml' THEN -- the special case
+        output := unapi.holdings_xml(
+            mmr_id, ouid, org, depth, includes, slimit, soffset, include_xmlns);
+        RETURN output;
+    END IF;
+    */
+
+    SELECT * INTO layout FROM unapi.bre_output_layout WHERE name = format;
+
+    IF layout.name IS NULL THEN
+        RETURN NULL::XML;
+    END IF;
+
+    SELECT * INTO xfrm FROM config.xml_transform WHERE name = layout.transform;
+
+    SELECT INTO leadrec * FROM biblio.record_entry WHERE id = mmrec.master_record;
+
+    -- Grab bulk SVF for the lead record if requested
+    -- TODO: additional SVF values from constituent records for formats, etc.
+    IF ('mra' = ANY (includes)) THEN 
+        axml := unapi.mra(leadrec.id,NULL,NULL,NULL,NULL);
+    ELSE
+        axml := NULL::XML;
+    END IF;
+
+    xml_buf = leadrec.marc;
+
+    hxml := NULL::XML;
+    subxml := NULL::XML;
+    FOR subrec IN SELECT * FROM biblio.record_entry bre
+        JOIN metabib.metarecord_source_map mmsm ON (mmsm.metarecord = mmr_id) 
+        WHERE mmsm.source = bre.id LOOP
+
+        -- collect holdings for all records
+        -- XXX: holdings limits and offsets are applied individually to each
+        -- subordinate record.  This could lead to large XML blobs for 
+        -- large metarecords.  Does this need to change?
+        IF ('holdings_xml' = ANY (includes)) THEN
+            hxml := XMLCONCAT(hxml, unapi.holdings_xml(
+                subrec.id, ouid, org, depth, 
+                evergreen.array_remove_item_by_value(includes,'holdings_xml'),
+                slimit, soffset, include_xmlns, pref_lib));
+        END IF;
+
+        IF subrec.id = leadrec.id THEN CONTINUE; END IF;
+        -- Append choice data from the XML of the non-lead records to the 
+        -- XML of the lead record
+
+        FOREACH xml_frag IN ARRAY 
+            (SELECT * FROM xpath(sub_xpath, subrec.marc::XML)) LOOP
+            subxml := XMLCONCAT(subxml, xml_frag::XML);
+        END LOOP;
+    END LOOP;
+
+    -- append data from the subordinate records to the 
+    -- record document before applying the main XSLT
+
+    top_el := REGEXP_REPLACE(xml_buf, E'^.*?<((?:\\S+:)?' || 
+        layout.holdings_element || ').*$', E'\\1');
+
+    IF subxml IS NOT NULL THEN 
+        xml_buf := REGEXP_REPLACE(xml_buf, 
+            '</' || top_el || '>(.*?)$', subxml || '</' || top_el || E'>\\1');
+    END IF;
+
+    IF format = 'marcxml' THEN
+         -- If we're not using the prefixed namespace in 
+         -- this record, then remove all declarations of it
+        IF xml_buf !~ E'<marc:' THEN
+           xml_buf := REGEXP_REPLACE(xml_buf, 
+            ' xmlns:marc="http://www.loc.gov/MARC21/slim"', '', 'g');
+        END IF; 
+    ELSE
+        xml_buf := oils_xslt_process(xml_buf, xfrm.xslt)::XML;
+    END IF;
+
+    IF axml IS NOT NULL THEN 
+        xml_buf := REGEXP_REPLACE(xml_buf, 
+            '</' || top_el || '>(.*?)$', axml || '</' || top_el || E'>\\1');
+    END IF;
+
+    IF hxml IS NOT NULL THEN -- XXX how do we configure the holdings position?
+        xml_buf := REGEXP_REPLACE(xml_buf, 
+            '</' || top_el || '>(.*?)$', hxml || '</' || top_el || E'>\\1');
+    END IF;
+
+    IF ('mmr.unapi' = ANY (includes)) THEN 
+        output := REGEXP_REPLACE(
+            xml_buf,
+            '</' || top_el || '>(.*?)',
+            XMLELEMENT(
+                name abbr,
+                XMLATTRIBUTES(
+                    'http://www.w3.org/1999/xhtml' AS xmlns,
+                    'unapi-id' AS class,
+                    'tag:open-ils.org:U2@mmr/' || mmr_id || '/' || org AS title
+                )
+            )::TEXT || '</' || top_el || E'>\\1'
+        );
+    ELSE
+        output := xml_buf;
+    END IF;
+
+    output := REGEXP_REPLACE(output::TEXT,E'>\\s+<','><','gs')::XML;
+    RETURN output;
+END;
+$F$ LANGUAGE PLPGSQL STABLE;
+
+COMMIT;