2011-11-02 14 views
19

Czy istnieje prosty sposób pracy z JSONem w ramach oracle? Mam standardową procedurę, którą często używam do wywoływania usług WWW, JSON jest formatem, który znam w kontekście programowania WWW, ale jaki jest najlepszy sposób pracy z jsonem w ramach procedury przechowywanej? Na przykład: pobierz odpowiedź CLOB z URI, przekonwertuj ją na obiekt JSON i uzyskaj wartość z tego?Praca z jsonem w wyroczni

Na litość odniesienia, tutaj jest procedura Kiedyś pobrać adresy

create or replace procedure macp_URL_GET(url_resp in out clob, v_url in varchar2) is 
    req  Utl_Http.req; 
    resp Utl_Http.resp; 
    NAME VARCHAR2 (255); 
    VALUE VARCHAR2 (1023); 
    v_msg VARCHAR2 (80); 
    v_ans clob; 
-- v_url VARCHAR2 (32767) := 'http://www.macalester.edu/'; 
BEGIN 
    /* request that exceptions are raised for error Status Codes */ 
    Utl_Http.set_response_error_check (ENABLE => TRUE); 
    /* allow testing for exceptions like Utl_Http.Http_Server_Error */ 
    Utl_Http.set_detailed_excp_support (ENABLE => TRUE); 
    /* 
    Utl_Http.set_proxy (
     proxy     => 'www-proxy.us.oracle.com', 
     no_proxy_domains  => 'us.oracle.com' 
    ); 
    */ 
    req := Utl_Http.begin_request (url => v_url, method => 'GET'); 
    /* 
    Alternatively use method => 'POST' and Utl_Http.Write_Text to 
    build an arbitrarily long message 
    */ 

    /* 
    Utl_Http.set_authentication (
     r    => req, 
     username  => 'SomeUser', 
     PASSWORD  => 'SomePassword', 
     scheme   => 'Basic', 
     for_proxy  => FALSE  --this info is for the target Web server 
    ); 
    */ 

    Utl_Http.set_header (r => req, NAME => 'User-Agent', VALUE => 'Mozilla/4.0'); 
    resp := Utl_Http.get_response (r => req); 
    /* 
    DBMS_OUTPUT.put_line ('Status code: ' || resp.status_code); 
    DBMS_OUTPUT.put_line ('Reason phrase: ' || resp.reason_phrase); 
    FOR i IN 1 .. Utl_Http.get_header_count (r => resp) 
    LOOP 
     Utl_Http.get_header (r => resp, n => i, NAME => NAME, VALUE => VALUE); 
     DBMS_OUTPUT.put_line (NAME || ': ' || VALUE); 
    END LOOP; 
    */ 
--test 
    BEGIN 
     LOOP 
     Utl_Http.read_text (r => resp, DATA => v_msg); 
     --DBMS_OUTPUT.put_line (v_msg); 
     v_ans := v_ans || v_msg; 
     url_resp := url_resp || v_msg; 
     END LOOP; 
    EXCEPTION 
     WHEN Utl_Http.end_of_body 
     THEN 
     NULL; 
    END; 
--test 
    Utl_Http.end_response (r => resp); 


    --url_resp := v_ans; 

EXCEPTION 
    /* 
    The exception handling illustrates the use of "pragma-ed" exceptions 
    like Utl_Http.Http_Client_Error. In a realistic example, the program 
    would use these when it coded explicit recovery actions. 

    Request_Failed is raised for all exceptions after calling 
    Utl_Http.Set_Detailed_Excp_Support (ENABLE=>FALSE) 
    And it is NEVER raised after calling with ENABLE=>TRUE 
    */ 
    WHEN Utl_Http.request_failed 
    THEN 
     DBMS_OUTPUT.put_line (
     'Request_Failed: ' || Utl_Http.get_detailed_sqlerrm 
    ); 
     url_resp :='Request_Failed: ' || Utl_Http.get_detailed_sqlerrm; 
    /* raised by URL http://xxx.oracle.com/ */ 
    WHEN Utl_Http.http_server_error 
    THEN 
     DBMS_OUTPUT.put_line (
     'Http_Server_Error: ' || Utl_Http.get_detailed_sqlerrm 
    ); 
     url_resp := 'Http_Server_Error: ' || Utl_Http.get_detailed_sqlerrm; 
    /* raised by URL http://otn.oracle.com/xxx */ 
    WHEN Utl_Http.http_client_error 
    THEN 
     DBMS_OUTPUT.put_line (
     'Http_Client_Error: ' || Utl_Http.get_detailed_sqlerrm 
    ); 
     url_resp := 'Http_Client_Error: ' || Utl_Http.get_detailed_sqlerrm; 
    /* code for all the other defined exceptions you can recover from */ 
    WHEN OTHERS 
    THEN 
     DBMS_OUTPUT.put_line (SQLERRM); 
     url_resp := SQLERRM; 
END; 

Następnie przetestować to

begin 
    macp_url_get(url_resp => :url_resp, 
       'http://maps.googleapis.com/maps/api/geocode/json?address=55105&sensor=false'); 
end; 

(wiem, że googleapi pozwoli odpowiedzi xml, ale istnieją inne webowe API, których używam regularnie, domyślnie JSON)

+1

Nie sądzę, że można to zrobić po wyjęciu z pudełka, ale jest kilka osób, które utworzyły dla niego api [ http://reseau.erasme.org/pl-sql-library-for-JSON?lang=en] (biblioteka pl/sql dla JSON - możesz zobaczyć przykładowy test, wygląda całkiem prosto) i [ sourceforge.net/projects/pljson/] (pljson - to wygląda na bardziej skomplikowane, ale powinno również działać) – Harrison

Odpowiedz

18

i zaczęła używać tej biblioteki, a wydaje się obiecujące: https://github.com/pljson/pljson

Łatwy w instalacji, a przykłady są dobre.

Aby korzystać z biblioteki w swojej przykład dodać tych zmiennych do procedury ..

mapData  json; 
results  json_list; 
status  json_value; 
firstResult json; 
geometry json; 

....

Następnie można manipulować odpowiedź jako obiekt JSON.

-- convert the result from the get to a json object, and show some results. 
mapData := json(v_ans); 

-- Show the status of the request 
status := mapData.get('status'); 
dbms_output.put_line('Status = ' || status.get_string()); 

IF (status.get_string() = 'OK') THEN 
    results := json_list(mapData.get('results')); 
    -- Grab the first item in the list 
    resultObject := json(results.head); 

    -- Show the human readable address 
    dbms_output.put_line('Address = ' || resultObject.get('formatted_address').to_char()); 
    -- Show the json location data 
    dbms_output.put_line('Location = ' || resultObject.get('geometry').to_char()); 
END IF; 

Uruchomienie tego kodu spowoduje to wyjście do wyjścia DBMS:

Status = OK 
Address = "St Paul, MN 55105, USA" 
Location = { 
    "bounds" : { 
    "northeast" : { 
     "lat" : 44.9483849, 
     "lng" : -93.1261959 
    }, 
    "southwest" : { 
     "lat" : 44.9223829, 
     "lng" : -93.200307 
    } 
    }, 
    "location" : { 
    "lat" : 44.9330076, 
    "lng" : -93.16290629999999 
    }, 
    "location_type" : "APPROXIMATE", 
    "viewport" : { 
    "northeast" : { 
     "lat" : 44.9483849, 
     "lng" : -93.1261959 
    }, 
    "southwest" : { 
     "lat" : 44.9223829, 
     "lng" : -93.200307 
    } 
    } 
} 
+1

Należy zauważyć, że biblioteka ta została przeniesiona do GitHub https://github.com/pljson/pljson – Damian

2

Napisałem tę bibliotekę: http://reseau.erasme.org/pl-sql-library-for-JSON?lang=en, i działa to świetnie, aby uzyskać odpowiedź jsona na tabelę plsql.

Jeśli chcesz tylko do danych Oracle i przekształcić go w JSON Biblioteka ta jest nieco „Heavy używać” ... mogę zaproponować inny kod robi to lepiej i szybciej:

create or replace package jsonfly as 

procedure open_object(k varchar2 default null); 
procedure close_object; 
procedure open_array (k varchar2 default null); 
procedure close_array; 
procedure separation; 
procedure member(k varchar2, v varchar2); 
procedure member(k varchar2, n number); 
procedure send; 
end; 
/

create or replace package body jsonfly as 
-------------------------------------------------------------------------------- 
-- package pour générer du JSON, envoyé à la volé 
-------------------------------------------------------------------------------- 
type tCache is table of varchar2(2000) index by binary_integer; 

g_openBrace   constant varchar2(2) := '{ '; 
g_closeBrace  constant varchar2(2) := ' }'; 
g_openBracket  constant varchar2(2) := '[ '; 
g_closeBracket  constant varchar2(2) := ' ]'; 
g_stringDelimiter constant varchar2(1) := '"'; 
g_Affectation  constant varchar2(3) := ' : '; 
g_separation  constant varchar2(3) := ', '; 
g_CR    constant varchar2(1) := Chr(10); -- used to indent the JSON object correctly 
g_spc    constant varchar2(2) := ' ';  -- used to indent the JSON object correctly 
g_js_comment_open constant varchar2(20) := '/*-secure-\n'; -- used to prevent from javascript hijacking 
g_js_comment_close constant varchar2(20) := '\n*/';   -- used to prevent from javascript hijacking 

--isObjectOpened boolean := false; 
--isArrayOpened boolean := false; 
t tCache; 
i number := 1; 

-------------------------------------------------------------------------------- 
-- 
-------------------------------------------------------------------------------- 
procedure p(s varchar2) is 
begin 
    t(i) := s; 
    i := i + 1; 
end; 
-------------------------------------------------------------------------------- 
-- 
-------------------------------------------------------------------------------- 
function encap (s varchar2) return varchar2 is 
begin 
    return g_stringdelimiter || s || g_stringdelimiter; 
end; 

-------------------------------------------------------------------------------- 
-- 
-------------------------------------------------------------------------------- 
function encode_string(p_string varchar2) return varchar2 is 
begin 
    return replace(replace(replace(replace(replace(replace(replace(replace(p_string, 
     '\', '\\'), 
     '"', '\"'), 
     '/', '\/'), 
     chr(8), '\b'), 
     chr(9), '\t'), 
     chr(10), '\n'), 
     chr(12), '\f'), 
     chr(13), '\r'); 
end; 

-------------------------------------------------------------------------------- 
-- 
-------------------------------------------------------------------------------- 
procedure open_object(k varchar2 default null) is 
begin  
    if (k is null) then 
     p(g_openbrace); 
    else 
     p(encap(k) || g_affectation || g_openbrace); 
    end if; 
end; 

-------------------------------------------------------------------------------- 
-- 
-------------------------------------------------------------------------------- 
procedure close_object is 
begin 
    if (t(i-1) = g_separation) then 
     i := i - 1; 
    end if; 
    p(g_closebrace); 
    separation(); 
end; 

-------------------------------------------------------------------------------- 
-- 
-------------------------------------------------------------------------------- 
procedure open_array (k varchar2 default null) is 
begin  
    if (k is null) then 
    p(g_openbracket); 
    else 
     p(encap(k) || g_affectation || g_openbracket); 
    end if; 
end; 

-------------------------------------------------------------------------------- 
-- 
-------------------------------------------------------------------------------- 
procedure close_array is 
begin 
    if (t(i-1) = g_separation) then 
     i := i - 1; 
    end if; 
    p(g_closebracket); 
    separation(); 
end; 

-------------------------------------------------------------------------------- 
-- 
-------------------------------------------------------------------------------- 
procedure separation is 
begin 
    p(g_separation); 
end; 

-------------------------------------------------------------------------------- 
-- 
-------------------------------------------------------------------------------- 
procedure key(k varchar2) is 
begin 
    p(encap(k) || g_affectation); 
end; 

-------------------------------------------------------------------------------- 
-- 
-------------------------------------------------------------------------------- 
procedure value(v varchar2) is 
begin 
    p(v); 
end; 

-------------------------------------------------------------------------------- 
-- 
-------------------------------------------------------------------------------- 
procedure member(k varchar2, v varchar2) is 
begin 
    p(encap(k) || g_affectation || encap(encode_string(v))); 
    p(g_separation); 
end; 

-------------------------------------------------------------------------------- 
-- 
-------------------------------------------------------------------------------- 
procedure member(k varchar2, n number) is 
begin 
    p(encap(k) || g_affectation || n); 
    p(g_separation); 
end; 

-------------------------------------------------------------------------------- 
-- 
-------------------------------------------------------------------------------- 
procedure send is 
begin 
    if (t(i-1) = g_separation) then 
     t.delete(i-1); 
    end if; 

    i := t.first; 
    while (i is not null) loop 
     htp.p(t(i)); 
     i := t.next(i); 
    end loop; 
end; 


end jsonfly; 
/
3

Należy zauważyć, że jak Oracle 12c jest jakaś natywna obsługa JSON. Jednak nie sądzę, że w obecnej formie jest tak samo użyteczny jak wersja PLJSON zawarta w innej odpowiedzi.

Aby użyć funkcji, należy utworzyć tabelę z polem BLOB, CLOB lub Varchar2 i dodać do niej ograniczenie "kolumna IS JSON". To wymusza sprawdzanie składni JSON w tej kolumnie.

Dopóki istnieje ograniczenie "IS JSON", można uzyskać dostęp do wartości JSON w ramach notacji kropkowej z SQL. Według mnie nie zapewnia tak potężnej manipulacji jak PLJSON. Możesz również utworzyć XMLType, a następnie przekonwertować do JSON.

Przydatne linki:
Oracle docs
Good tutorial and examples
Tutorial including XML to JSON

1

Oracle APEX 5.0 posiada wsparcie dla JSON za pomocą APEX_JSON pakietu. Nie używałem go, ale wygląda interesująco i poprosiłem mój zespół o jego zbadanie.Naszym przypadkiem użycia jest umożliwienie przekazywania danych JSON jako parametr wejściowy do procedury przechowywanej z aplikacji nodejs.

+0

To nie było proste Przekaż, aby zainstalować pakiet APEX_JSON do naszej wyjściowej bazy danych bez instalowania serwera APEX 5.0. Postanowiliśmy użyć biblioteki pljson (https://github.com/pljson/pljson). – Parvez

1

Oracle 12c mają teraz native JSON support:

Oracle Database obsługuje Object Notation JavaScript (JSON) dane natywnie z cech relacyjnych baz danych, w tym transakcji, indeksowanie deklaratywnej zapytań i widoków

danych JSON i dane XML mogą być używane w Oracle Database w podobny sposób. W przeciwieństwie do danych relacyjnych, oba mogą być przechowywane, indeksowane i sprawdzane bez potrzeby stosowania schematu definiującego dane. Baza danych Oracle obsługuje JSON natywnie dzięki relacyjnym funkcjom baz danych, w tym transakcjom, indeksom, deklaratywnym zapytaniom i widokom.

Dane JSON były często przechowywane w bazach danych NoSQL, takich jak Oracle NoSQL Database i Oracle Berkeley DB. Umożliwiają one przechowywanie i pobieranie danych, które nie są oparte na żadnym schemacie, ale nie oferują rygorystycznych modeli spójności relacyjnych baz danych.

Aby zrekompensować to niedociągnięcie, relacyjna baza danych jest czasami używana równolegle z bazą danych NoSQL. Aplikacje korzystające z danych JSON przechowywanych w bazie danych NoSQL muszą zapewnić integralność danych.

Natywne wsparcie dla JSON przez Oracle Database eliminuje tego rodzaju obejścia. Zapewnia wszystkie zalety funkcji relacyjnej bazy danych do użytku z JSON, w tym transakcje, indeksowanie, deklaratywne zapytania i widoki.

Kwerendy bazy danych Oracle są deklaratywne. Możesz dołączyć dane JSON do danych relacyjnych. Możesz także projektować dane JSON relacyjnie, udostępniając je dla procesów i narzędzi relacyjnych. Można również wyszukiwać, z poziomu bazy danych, dane JSON, które są przechowywane poza bazą danych w zewnętrznej tabeli.

Można uzyskać dostęp do danych JSON przechowywanych w bazie danych w taki sam sposób, jak dostęp do innych danych bazy danych, w tym przy użyciu OCI, .NET i JDBC.

W przeciwieństwie do danych XML, które są przechowywane przy użyciu typu danych SQL typu XMLType, dane JSON są przechowywane w bazie danych Oracle przy użyciu typów danych SQL VARCHAR2, CLOB i BLOB. Firma Oracle zaleca, aby zawsze używać ograniczenia sprawdzania is_json, aby upewnić się, że wartości kolumn są poprawne. Instancje JSON