| BBCode Parser [2007.12.23] Bookmark (1.0.100.0) This is the first release of a BBCode "parser" that translates BBCode tags like [url] or [b]. It's part of a package for my CMS lite application.
CREATE OR REPLACE PACKAGE cm_parse
IS
/* parse blog entries */
FUNCTION bbcode_to_html(
p_text IN CLOB
, p_en_Id IN cm_entry.en_Id%TYPE DEFAULT NULL
) RETURN CLOB
;
END cm_parse;
/
CREATE OR REPLACE PACKAGE BODY cm_parse
IS
/* private constants */
ST_CODE CONSTANT PLS_INTEGER := 1;
ST_NOPARSE CONSTANT PLS_INTEGER := 2;
/* private types */
TYPE t_ref_links IS TABLE OF c_ref_links%ROWTYPE;
TYPE t_arg IS RECORD (key VARCHAR2(255)
,key_val VARCHAR2(255)
);
TYPE t_args IS TABLE OF t_arg INDEX BY BINARY_INTEGER;
TYPE t_status IS VARRAY(2) OF BOOLEAN;
/* private procedures */
/* get arguments */
PROCEDURE get_args(
p_tag IN VARCHAR2
, p_args OUT t_args
)
IS
v_argc PLS_INTEGER := 0;
v_arg VARCHAR2(255);
v_key VARCHAR2(255);
v_key_val VARCHAR2(255);
v_args t_args;
BEGIN
LOOP
v_argc := v_argc + 1;
v_arg := REGEXP_SUBSTR(p_tag, '([^] ]+)', 2, v_argc);
EXIT WHEN v_arg IS NULL;
v_key := LOWER(REGEXP_SUBSTR(v_arg, '([^=]+)'));
v_key_val := SUBSTR(v_arg, LEAST(LENGTH(v_key) + 2, 250));
v_args(v_argc).key := v_key;
v_args(v_argc).key_val := v_key_val;
END LOOP;
p_args := v_args;
END get_args;
/* public procedures */
/* parse blog entries */
FUNCTION bbcode_to_html(
p_text IN CLOB
, p_en_Id IN cm_entry.en_Id%TYPE DEFAULT NULL
) RETURN CLOB
IS
v_slash CONSTANT VARCHAR2(1) := '';
v_bracket CONSTANT VARCHAR2(1) := '[';
v_LF CONSTANT VARCHAR2(1) := CHR(13);
v_pos PLS_INTEGER;
v_pos_end PLS_INTEGER;
v_start PLS_INTEGER;
v_len PLS_INTEGER := NVL(LENGTH(p_text), 0);
v_searched VARCHAR2(255);
v_replace VARCHAR2(255);
v_args t_args;
v_source VARCHAR2(32000) := DBMS_LOB.SUBSTR(p_text, 32000);
v_text VARCHAR2(32000);
v_status t_status := t_status(FALSE, FALSE);
BEGIN
v_pos := 0;
LOOP
v_start := v_pos + 1;
Debug('v_start: ' || v_start);
/* don't parse text enclosed by the noparse tags */
IF v_status(ST_NOPARSE) THEN
v_pos := LEAST(NVL(NULLIF(INSTR(v_source, v_slash, v_start), 0), v_len + 1)
,NVL(NULLIF(INSTR(v_source, '[/noparse]', v_start), 0), v_len + 1)
);
ELSE
v_pos := LEAST(NVL(NULLIF(INSTR(v_source, v_slash, v_start), 0), v_len + 1)
,NVL(NULLIF(INSTR(v_source, v_LF, v_start), 0), v_len + 1)
,NVL(NULLIF(INSTR(v_source, v_bracket, v_start), 0), v_len + 1)
);
END IF;
v_text := v_text || SUBSTR(v_source, v_start, v_pos - v_start);
EXIT WHEN NVL(v_pos, 1) > v_len;
v_searched := SUBSTR(v_source, v_pos, 1);
CASE v_searched
WHEN v_slash THEN
v_pos := v_pos + 1;
v_searched := SUBSTR(v_source, v_pos, 1);
v_replace := CASE v_searched
WHEN '<' THEN '<'
WHEN '>' THEN '>'
WHEN '&' THEN '&'
ELSE v_searched
END;
WHEN v_LF THEN
v_pos := v_pos + 1;
IF v_status(ST_CODE) THEN
v_replace := v_searched;
ELSE
v_replace := '<br>';
END IF;
WHEN v_bracket THEN
v_pos_end := INSTR(v_source, ']', v_pos + 1) - v_pos + 1;
IF v_pos_end > 0 THEN
v_searched := SUBSTR(v_source, v_pos, v_pos_end);
v_replace := CASE v_searched
WHEN '[b]' THEN '<b>'
WHEN '[i]' THEN '<i>'
WHEN '[u]' THEN '<u>'
WHEN '[p]' THEN '<p>'
WHEN '[/b]' THEN '</b>'
WHEN '[/i]' THEN '</i>'
WHEN '[/u]' THEN '</u>'
WHEN '[/p]' THEN '</p>'
WHEN '[/url]' THEN '</a>'
WHEN '[/img]' THEN '>'
WHEN '[/doc]' THEN '>'
ELSE NULL
END;
CASE v_searched
WHEN '[code]' THEN
v_replace := '<pre>';
v_status(ST_CODE) := TRUE;
WHEN '[/code]' THEN
v_replace := '</pre>';
v_status(ST_CODE) := FALSE;
WHEN '[noparse]' THEN
v_replace := ' ';
v_status(ST_NOPARSE) := TRUE;
WHEN '[/noparse]' THEN
v_replace := ' ';
v_status(ST_NOPARSE) := FALSE;
ELSE
NULL;
END CASE;
IF v_replace IS NULL THEN
get_args(p_tag => v_searched, p_args => v_args);
IF v_args.COUNT > 0 THEN
CASE WHEN v_args(1).key = 'img' THEN
v_replace := '<img srg="' || v_args(1).key_val || '>';
WHEN v_args(1).key = 'doc' THEN
v_replace := '<img src="f?p=999:7:0::::P7_DOC_ID:' || v_args(1).key_val || '"';
WHEN v_args(1).key = 'url' THEN
IF v_args(1).key_val IS NULL THEN
v_args(1).key_val := REGEXP_REPLACE(REGEXP_SUBSTR(v_source
,'(http://)?([^[]+)'
,v_pos - v_pos_end
)
,'(http://)?(.+)'
,'http://2'
);
END IF;
v_replace := '<a href="' || v_args(1).key_val || '">';
ELSE
v_replace := v_searched;
END CASE;
END IF;
END IF;
v_pos := v_pos + v_pos_end - 1;
ELSE
v_replace := '';
END IF;
ELSE
RAISE_APPLICATION_ERROR(-20999, 'v_pos: ' || v_pos || ' v_searched: ' || v_searched);
END CASE;
v_text := v_text || v_replace;
END LOOP;
RETURN v_text || '<p>';
END bbcode_to_html;
END cm_parse;
|