MainBlogContactRSS




Login    
Login
 
Recent Entries    
Next Projects
INITCAP this!
APEX 3.1 released ...
Exploiting the strange behavio ...
Where's my SQL?
Undocumented Packages for Back ...
Debugging an APEX application
Splitting strings
Where's the space gone?
The size of a (XE) database
1 2 3 4 5 6 
Search    
Search
 
Recent Articles    
Introduction to Regular Expres ...
Extracting SQL statements from ...
BBCode Parser
MODEL clause vs. old school SQ ...
IF NULL or how to match two va ...
Views    
Firefox1213
IExplorer1576
Linux106
Windows2823
Total Views42572
System    
BCHR 
CMS_TS (100MB) 
DB (XE) (5GB) 
PGA (256MB) 
Daily insights of a database application developer    
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;
 

1 
Entries rendered in: 0.04 s




nobody