read, store and create xml and json

76
Read, Store and Create XML and JSON OUGN Spring Seminar 10-12 March 2016 Kim Berg Hansen Senior Consultant

Upload: kim-berg-hansen

Post on 16-Apr-2017

343 views

Category:

Data & Analytics


9 download

TRANSCRIPT

Page 1: Read, store and create xml and json

Read, Store and Create XML and JSONOUGN Spring Seminar 10-12 March 2016

Kim Berg HansenSenior Consultant

Page 2: Read, store and create xml and json

Read, Store and Create XML and JSON2 05/03/2023

About me

• Danish geek• SQL & PL/SQL developer since 2000• Developer at Trivadis AG since 2016

http://www.trivadis.dk• Oracle Certified Expert in SQL• Oracle ACE• Blogger at http://www.kibeha.dk• SQL quizmaster at

http://plsqlchallenge.oracle.com• Likes to cook• Reads sci-fi• Chairman of local chapter of

Danish Beer Enthusiasts

Page 3: Read, store and create xml and json

Read, Store and Create XML and JSON3 05/03/2023

About Trivadis

Trivadis is a market leader in IT consulting, system integration, solution engineeringand the provision of IT services focusing on and technologies in Switzerland, Germany, Austria and Denmark.We offer our services in the following strategic business fields:

Trivadis Services takes over the interacting operation of your IT systems.

O P E R A T I O N

Page 4: Read, store and create xml and json

Read, Store and Create XML and JSON4 05/03/2023

COPENHAGEN

MUNICH

LAUSANNEBERN

ZURICHBRUGG

GENEVA

HAMBURG

DÜSSELDORF

FRANKFURT

STUTTGART

FREIBURG

BASEL

VIENNA

With over 600 specialists and IT experts in your region

14 Trivadis branches and more than600 employees

260 Service Level Agreements

Over 4,000 training participants

Research and development budget:EUR 5.0 million

Financially self-supporting and sustainably profitable

Experience from more than 1,900 projects per year at over 800customers

Page 5: Read, store and create xml and json

Agenda for XML and JSON

Read, Store and Create XML and JSON5 05/03/2023

1. Retrieval

SOAP, REST, APEX_WEB_SERVICE, HttpUriType2. Storage

XMLType, CLOB, Object relational3. Query

XMLTABLE, XMLQUERY, JSON_TABLE, JSON_QUERY, JSON dot notation4. Creation

XML* functions, XMLTYPE constructor, DbUriType, APEX_JSON

Page 6: Read, store and create xml and json

Read, Store and Create XML and JSON6 05/03/2023

Requisites

begin dbms_network_acl_admin.create_acl ( acl => 'google_apis_acl.xml' , description => 'Demo ACL for Google apis' , principal => 'SCOTT' , is_grant => true , privilege => 'connect' ); dbms_network_acl_admin.add_privilege( acl => 'google_apis_acl.xml' , principal => 'APEX_050000' , is_grant => true , privilege => 'connect' ); dbms_network_acl_admin.assign_acl ( acl => 'google_apis_acl.xml' , host => '*.googleapis.com' ); dbms_network_acl_admin.assign_acl ( acl => 'google_apis_acl.xml' , host => '*.cdyne.com' ); commit;end;/

As privileged user (i.e. SYSTEM) create ACL and give network privileges

Page 7: Read, store and create xml and json

Read, Store and Create XML and JSON7 05/03/2023

Retrieval

Page 8: Read, store and create xml and json

Read, Store and Create XML and JSON8 05/03/2023

HTTP GET with HttpUriType

select httpuritype( 'maps.googleapis.com/maps/api/directions/xml' || '?'||'origin=' || utl_url.escape(convert( 'Endelavevej 55, DK-5500 Middelfart' , 'UTF8' )) || '&'||'destination=' || utl_url.escape(convert( 'Paul-Dessau-Strasse 6, D-22761 Hamburg' , 'UTF8' )) || '&'||'mode=driving'||'&'||'alternatives=true'||'&'||'units=metric' || '&'||'region=eu'||'&'||'language=en'||'&'||'sensor=false' ).getxml() directions from dual;

Retrieve XML directions from Google Maps API – No SSL (https) supported

Page 9: Read, store and create xml and json

Read, Store and Create XML and JSON9 05/03/2023

HTTP GET with HttpUriType

<?xml version="1.0" encoding="UTF-8"?><DirectionsResponse> <status>OK</status> <route> <summary>E45 and A7</summary> <leg> <step> <travel_mode>DRIVING</travel_mode> <start_location> <lat>55.4892447</lat> <lng>9.7517085</lng> </start_location> <end_location> <lat>55.4878639</lat> <lng>9.7539612</lng> </end_location> <polyline><points>wvtqIesoz@k@j@k@iCh@i@tBsBVY`B_BpAkA</points> </polyline>

<duration> <value>65</value> <text>1 min</text> </duration>... <geocoded_waypoint> <geocoder_status>OK</geocoder_status> <type>street_address</type> <place_id>ChIJRUp9K2iWTEYRmzjwsDRYoto</place_id> </geocoded_waypoint> <geocoded_waypoint> <geocoder_status>OK</geocoder_status> <type>street_address</type> <partial_match>true</partial_match> <place_id>ChIJZ1x_bZWFsUcRx7t3-L0HwsI</place_id> </geocoded_waypoint></DirectionsResponse>

Retrieve XML directions from Google Maps API – XMLTYPE object output

Page 10: Read, store and create xml and json

Read, Store and Create XML and JSON10 05/03/2023

HTTP GET with HttpUriType

select httpuritype( 'maps.googleapis.com/maps/api/directions/json' || '?'||'origin=' || utl_url.escape(convert( 'Endelavevej 55, DK-5500 Middelfart' , 'UTF8' )) || '&'||'destination=' || utl_url.escape(convert( 'Paul-Dessau-Strasse 6, D-22761 Hamburg' , 'UTF8' )) || '&'||'mode=driving'||'&'||'alternatives=true'||'&'||'units=metric' || '&'||'region=eu'||'&'||'language=en'||'&'||'sensor=false' ).getclob() directions from dual;

Retrieve JSON directions from Google Maps API – No SSL (https) supported

Page 11: Read, store and create xml and json

Read, Store and Create XML and JSON11 05/03/2023

HTTP GET with HttpUriType

{ "geocoded_waypoints" : [ { "geocoder_status" : "OK", "place_id" : "ChIJRUp9K2iWTEYRmzjwsDRYoto", "types" : [ "street_address" ] }, { "geocoder_status" : "OK", "partial_match" : true, "place_id" : "ChIJZ1x_bZWFsUcRx7t3-L0HwsI", "types" : [ "street_address" ] } ], "routes" : [ { "bounds" : { "northeast" : { "lat" : 55.5465325,

"lng" : 9.964266 }, "southwest" : { "lat" : 53.5627269, "lng" : 9.3241038 } },... }, "summary" : "E45", "warnings" : [], "waypoint_order" : [] } ], "status" : "OK"}

Retrieve JSON directions from Google Maps API – CLOB output containing JSON

Page 12: Read, store and create xml and json

Read, Store and Create XML and JSON12 05/03/2023

HTTP GET with APEX_WEB_SERVICE

declare directions clob; directions_xml xmltype;begin directions := apex_web_service.make_rest_request( p_url => 'http://maps.googleapis.com/maps/api/directions/xml' , p_http_method => 'GET' , p_parm_name => apex_util.string_to_table('origin:destination:mode:alternatives:units:region:language:sensor' ) , p_parm_value => apex_util.string_to_table('Endelavevej 55, DK-5500 Middelfart:Paul-Dessau-Strasse 6, D-22761 Hamburg:driving:true:metric:eu:en:false' ) ); dbms_output.put_line(substr(directions,1,4000)); directions_xml := xmltype(directions);end;/

Retrieve XML (or JSON) directions from Google Maps API – SSL (https) supported via WalletData always as CLOB whether XML or JSON – If XMLTYPE needed, use constructor

Page 13: Read, store and create xml and json

Read, Store and Create XML and JSON13 05/03/2023

HTTP GET with APEX_WEB_SERVICE

declare parm_name wwv_flow_global.vc_arr2; parm_value wwv_flow_global.vc_arr2; directions clob;begin parm_name(1) := 'origin'; parm_value(1) := 'Endelavevej 55, DK-5500 Middelfart'; parm_name(2) := 'destination'; parm_value(2) := 'Paul-Dessau-Strasse 6, D-22761 Hamburg'; parm_name(3) := 'mode'; parm_value(3) := 'driving'; parm_name(4) := 'alternatives'; parm_value(4) := 'true'; parm_name(5) := 'units'; parm_value(5) := 'metric'; parm_name(6) := 'region'; parm_value(6) := 'eu'; parm_name(7) := 'language'; parm_value(7) := 'en'; parm_name(8) := 'sensor'; parm_value(8) := 'false'; directions := apex_web_service.make_rest_request( p_url => 'http://maps.googleapis.com/maps/api/directions/json' , p_http_method => 'GET' , p_parm_name => parm_name , p_parm_value => parm_value ); dbms_output.put_line(substr(directions,1,4000));end;/

Retrieve JSON (or XML) directions from Google Maps APIAlternative call syntax building parameter name/value pairs manually

Page 14: Read, store and create xml and json

Read, Store and Create XML and JSON14 05/03/2023

HTTP SOAP Webservice with APEX_WEB_SERVICE

declare envelope clob; weather xmltype;begin select xmlroot( xmlelement( "soap:Envelope" , xmlattributes( 'http://www.w3.org/2001/XMLSchema-instance' as "xmlns:xsi" , 'http://www.w3.org/2001/XMLSchema' as "xmlns:xsd" , 'http://schemas.xmlsoap.org/soap/envelope/' as "xmlns:soap" ) , xmlelement( "soap:Body" , xmlelement( "GetCityWeatherByZIP" , xmlattributes('http://ws.cdyne.com/WeatherWS/' as "xmlns") , xmlelement("ZIP", '60611') ) ) ), version '1.0').getclobval() into envelope from dual; weather := apex_web_service.make_request( p_url => 'http://wsf.cdyne.com/WeatherWS/Weather.asmx' , p_action => 'http://ws.cdyne.com/WeatherWS/GetCityWeatherByZIP' , p_version => '1.1' , p_envelope => envelope ); dbms_output.put_line(weather.getclobval());end;/

Retrieve weather in Chicago, USA – Data always as CLOB even though contains XML

Page 15: Read, store and create xml and json

Read, Store and Create XML and JSON15 05/03/2023

Further information on callouts

My presentation from ODTUG KScope14:

– External Data via HTTP, FTP and Web Services

– http://bit.ly/kibeha_http_ws_slides

Page 16: Read, store and create xml and json

Read, Store and Create XML and JSON16 05/03/2023

Storage

Page 17: Read, store and create xml and json

Read, Store and Create XML and JSON17 05/03/2023

XMLTYPE column

create table addresses ( addr_id integer primary key , address varchar2(4000) , geocoded xmltype) xmltype geocoded store as securefile binary xml;

insert into addresses values ( 1 , 'Endelavevej 55, DK-5500 Middelfart' , httpuritype( 'http://maps.googleapis.com/maps/api/geocode/xml?address='|| utl_url.escape('Endelavevej 55, DK-5500 Middelfart') ).getxml());

Column object type XMLTYPE

Page 18: Read, store and create xml and json

Read, Store and Create XML and JSON18 05/03/2023

XMLTYPE column

select geocoded from addresses;

Column object type XMLTYPE

<?xml version="1.0" encoding="UTF-8"?><GeocodeResponse> <status>OK</status> <result> <type>street_address</type> <formatted_address>Endelavevej 55, 5500 Middelfart, Denmark</formatted_address> <address_component> <long_name>55</long_name> <short_name>55</short_name> <type>street_number</type> </address_component>... <place_id>ChIJRUp9K2iWTEYRmzjwsDRYoto</place_id> </result></GeocodeResponse>

Page 19: Read, store and create xml and json

Read, Store and Create XML and JSON19 05/03/2023

CLOB column with JSON

create table addresses2 ( addr_id integer primary key , address varchar2(4000) , geocoded clob check(geocoded is json));

insert into addresses2 (addr_id, address) values (2, 'Endelavevej 55, DK-5500 Middelfart');

update addresses2 set geocoded = httpuritype( 'http://maps.googleapis.com/maps/api/geocode/json?address='|| utl_url.escape(address) ).getclob();

Any CLOB can contain JSON - Use IS JSON check constraint to be certain

Page 20: Read, store and create xml and json

Read, Store and Create XML and JSON20 05/03/2023

CLOB column with JSON

select geocoded from addresses2;

Content like any other CLOB

{ "results" : [ { "address_components" : [ { "long_name" : "55", "short_name" : "55", "types" : [ "street_number" ] },.. "formatted_address" : "Endelavevej 55, 5500 Middelfart, Denmark", "geometry" : { "location" : { "lat" : 55.4892307, "lng" : 9.7519265..

Page 21: Read, store and create xml and json

Read, Store and Create XML and JSON21 05/03/2023

XMLTYPE table

create table geocoded_addresses of xmltype xmltype store as securefile binary xml;

insert into geocoded_addresses values ( httpuritype( 'http://maps.googleapis.com/maps/api/geocode/xml?address='|| utl_url.escape('Endelavevej 55, DK-5500 Middelfart') ).getxml());

Object table of type XMLTYPE

Page 22: Read, store and create xml and json

Read, Store and Create XML and JSON22 05/03/2023

XMLTYPE table

select sys_nc_rowinfo$ from geocoded_addresses;

Table now contains objects, not scalar columns

<?xml version="1.0" encoding="UTF-8"?><GeocodeResponse> <status>OK</status> <result> <type>street_address</type> <formatted_address>Endelavevej 55, 5500 Middelfart, Denmark</formatted_address> <address_component> <long_name>55</long_name> <short_name>55</short_name> <type>street_number</type> </address_component>... <place_id>ChIJRUp9K2iWTEYRmzjwsDRYoto</place_id> </result></GeocodeResponse>

Page 23: Read, store and create xml and json

Read, Store and Create XML and JSON23 05/03/2023

XMLSchema

begin dbms_xmlschema.registerschema( schemaurl=>'/nsroot/demo/note/' , schemadoc=>'<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"><xs:element name="note"> <xs:complexType> <xs:sequence> <xs:element name="to" type="xs:string"/> <xs:element name="from" type="xs:string"/> <xs:element name="heading" type="xs:string"/> <xs:element name="body" type="xs:string"/> </xs:sequence> </xs:complexType></xs:element></xs:schema>' , local=>true , gentypes=>true , genbean=>false , gentables=>false );end;/

Schema defines structure of XML – schema is registered under URL “path” in repository

Page 24: Read, store and create xml and json

Read, Store and Create XML and JSON24 05/03/2023

XMLSchema

create table notes of xmltype xmltype store as object relational xmlschema "/nsroot/demo/note" element "note";

-- Raises error: ORA-30937: No schema definition for 'something' (namespace '') in parent '/'insert into notes values ( xmltype('<something>Not valid schema</something>'));

-- Works, because XML fits schema definitioninsert into notes values ( xmltype('<note><to>Jack</to><from>Jill</from><heading>Be my Valentine?</heading><body>Let us meet at Luigis Restaurant</body></note>') );

XMLTYPE table stored as object relational, not binary XMLXMLSCHEMA keyword may be used for binary XML too and enforce XML structure

Page 25: Read, store and create xml and json

Read, Store and Create XML and JSON25 05/03/2023

XMLSchema stored as object

select sys_nc_rowinfo$ from notes;

XML re-assembled from object relational dataWhitespace between elements no longer as original

<note> <to>Jack</to> <from>Jill</from> <heading>Be my Valentine?</heading> <body>Let us meet at Luigis Restaurant</body></note>

Page 26: Read, store and create xml and json

Read, Store and Create XML and JSON26 05/03/2023

XMLSchema stored as object

select dbms_metadata.get_ddl('TYPE', 'note928_T') ddl from dual;

-- Output:

CREATE OR REPLACE EDITIONABLE TYPE "SCOTT"."note928_T" AS OBJECT ( "SYS_XDBPD$" "XDB"."XDB$RAW_LIST_T" , "to" VARCHAR2(32767 CHAR) , "from" VARCHAR2(32767 CHAR) , "heading" VARCHAR2(32767 CHAR) , "body" VARCHAR2(32767 CHAR)) FINAL INSTANTIABLE;

CREATE TABLE autocreated object type named <xml name><sequence>_T

Page 27: Read, store and create xml and json

Read, Store and Create XML and JSON27 05/03/2023

XMLSchema stored as object

select sys_nc00008$, sys_nc00009$, sys_nc00010$, sys_nc00011$ from notes;

SYS_NC00008$ SYS_NC00009$ SYS_NC00010$ SYS_NC00011$--------------- --------------- -------------------- -----------------------------------Jack Jill Be my Valentine? Let us meet at Luigis Restaurant

Object type table contains hidden columns with relational data

Page 28: Read, store and create xml and json

Read, Store and Create XML and JSON28 05/03/2023

XMLSchema with annotations

dbms_xmlschema.registerschema( schemaurl=>'/nsroot/demo/note/' , schemadoc=>'<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xdb="http://xmlns.oracle.com/xdb"> <xs:element name="note" type="NoteType" xdb:defaultTable="NOTES"/> <xs:complexType name="NoteType" xdb:SQLType="NOTE_T"> <xs:sequence> <xs:element name="to" type="HeaderType" xdb:SQLName="TO"/> <xs:element name="from" type="HeaderType" xdb:SQLName="FROM"/> <xs:element name="heading" type="HeaderType" xdb:SQLName="HEADING"/> <xs:element name="body" type="BodyType" xdb:SQLName="BODY"/> </xs:sequence> </xs:complexType> <xs:simpleType name="HeaderType"> <xs:restriction base="xs:string"><xs:minLength value="0"/><xs:maxLength value="30"/></xs:restriction> </xs:simpleType> <xs:simpleType name="BodyType"> <xs:restriction base="xs:string"><xs:minLength value="0"/><xs:maxLength value="4000"/></xs:restriction> </xs:simpleType></xs:schema>' , local=>true , gentypes=>true , genbean=>false , gentables=>true );

Put xdb:*** annotations in XML schema along with length restrictionsObject type and table generating will use the annotated names

Page 29: Read, store and create xml and json

Read, Store and Create XML and JSON29 05/03/2023

XMLSchema with annotations

insert into notes values ( xmltype('<note><to>Jack</to><from>Jill</from><heading>Be my Valentine?</heading><body>Let us meet at Luigis Restaurant</body></note>') );

select sys_nc_rowinfo$ from notes;

<note> <to>Jack</to> <from>Jill</from> <heading>Be my Valentine?</heading> <body>Let us meet at Luigis Restaurant</body></note>

NOTES table here created by “gentables=>true”Inserting and selecting data same result as before

Page 30: Read, store and create xml and json

Read, Store and Create XML and JSON30 05/03/2023

XMLSchema with annotations

select dbms_metadata.get_ddl('TYPE', 'NOTE_T') ddl from dual;

-- Output:

CREATE OR REPLACE EDITIONABLE TYPE "SCOTT"."NOTE_T" AS OBJECT ( "SYS_XDBPD$" "XDB"."XDB$RAW_LIST_T" , "TO" VARCHAR2(30 CHAR) , "FROM" VARCHAR2(30 CHAR) , "HEADING" VARCHAR2(30 CHAR) , "BODY" VARCHAR2(4000 CHAR)) NOT FINAL INSTANTIABLE;

Register schema autocreated object type named as specified in annotationsTable still contains invisible SYS named columns, but now with better datatypes

Page 31: Read, store and create xml and json

Read, Store and Create XML and JSON31 05/03/2023

Query

Page 32: Read, store and create xml and json

Read, Store and Create XML and JSON32 05/03/2023

XMLQUERY

select xmlquery( '/GeocodeResponse/result/formatted_address' passing a.geocoded returning content ) formatted from addresses a;

FORMATTED--------------------------------------------------------------------------------<formatted_address>Endelavevej 55, 5500 Middelfart, Denmark</formatted_address>

XMLQUERY returns XML snippet

Page 33: Read, store and create xml and json

Read, Store and Create XML and JSON33 05/03/2023

XMLCAST

select xmlcast( xmlquery( '/GeocodeResponse/result/formatted_address' passing a.geocoded returning content ) as varchar2(50) ) formatted from addresses a;

FORMATTED-----------------------------------------------------Endelavevej 55, 5500 Middelfart, Denmark

XMLCAST is one way to turn the snippet into only the content

Page 34: Read, store and create xml and json

Read, Store and Create XML and JSON34 05/03/2023

XMLTABLE

select geo.* from addresses a , xmltable( '*' passing a.geocoded columns status varchar2(20) path '/GeocodeResponse/status' , lat number path '/GeocodeResponse/result/geometry/location/lat' , lng number path '/GeocodeResponse/result/geometry/location/lng' , formatted_address varchar2(50) path '/GeocodeResponse/result/formatted_address' ) geo;

STATUS LAT LNG FORMATTED_ADDRESS-------------------- ---------- ---------- --------------------------------------------------OK 55.4892307 9.7519265 Endelavevej 55, 5500 Middelfart, Denmark

Pass XMLTABLE function some XML and define columns with XPath expressions

Page 35: Read, store and create xml and json

Read, Store and Create XML and JSON35 05/03/2023

XMLTABLE

select geo.* from addresses a , xmltable( '/GeocodeResponse/result' passing a.geocoded columns lat number path 'geometry/location/lat' , lng number path 'geometry/location/lng' , formatted_address varchar2(50) path 'formatted_address' ) geo;

LAT LNG FORMATTED_ADDRESS---------- ---------- --------------------------------------------------55.4892307 9.7519265 Endelavevej 55, 5500 Middelfart, Denmark

Can tell XMLTABLE to operate only on a sub-node

Page 36: Read, store and create xml and json

Read, Store and Create XML and JSON36 05/03/2023

XMLTABLE

select geo.* from addresses a , xmltable( '/GeocodeResponse/result' passing a.geocoded columns formatted_address varchar2(50) path 'formatted_address' , street_number_name varchar2(10) path 'address_component/long_name' ) geo;

ERROR at line 3:ORA-19279: XPTY0004 - XQuery dynamic type mismatch: expected singleton sequence - got multi-item sequence

Multiple elements “address_component/long_name” in XML => error

Page 37: Read, store and create xml and json

Read, Store and Create XML and JSON37 05/03/2023

XMLTABLE

select geo.* from addresses a , xmltable( '/GeocodeResponse/result' passing a.geocoded columns adr_components xmltype path 'address_component' ) geo;

Column can be XMLTYPE to allow us to inspect why the error

<address_component> <long_name>55</long_name> <short_name>55</short_name> <type>street_number</type></address_component><address_component> <long_name>Endelavevej</long_name> <short_name>Endelavevej</short_name> <type>route</type></address_component><address_component> <long_name>Middelfart</long_name> <short_name>Middelfart</short_name> <type>locality</type> <type>political</type></address_component><address_component> <long_name>Middelfart Municipality</long_name> <short_name>Middelfart Municipality</short_name> <type>administrative_area_level_2</type> <type>political</type>..

Page 38: Read, store and create xml and json

Read, Store and Create XML and JSON38 05/03/2023

XMLTABLE

select geo.formatted_address , com.* from addresses a , xmltable( '/GeocodeResponse/result' passing a.geocoded columns formatted_address varchar2(50) path 'formatted_address' , adr_components xmltype path 'address_component' ) geo , xmltable( '/address_component' passing geo.adr_components columns type varchar2(30) path 'type' , long_name varchar2(30) path 'long_name' ) com;

ORA-19279: XPTY0004 - XQuery dynamic type mismatch: expected singleton sequence - got multi-item sequence

Chain two XMLTABLE calls – except “type” still has too many

Page 39: Read, store and create xml and json

Read, Store and Create XML and JSON39 05/03/2023

XMLTABLE

select geo.formatted_address , com.* from addresses a , xmltable( '/GeocodeResponse/result' passing a.geocoded columns formatted_address varchar2(50) path 'formatted_address' , adr_components xmltype path 'address_component' ) geo , xmltable( '/address_component' passing geo.adr_components columns type varchar2(30) path 'type[1]' , long_name varchar2(30) path 'long_name' ) com;

type[1] allows us to specify we just want the first if there are multiple

Page 40: Read, store and create xml and json

Read, Store and Create XML and JSON40 05/03/2023

XMLTABLE

FORMATTED_ADDRESS TYPE LONG_NAME------------------------------------------ ------------------------------ -------------------------Endelavevej 55, 5500 Middelfart, Denmark street_number 55Endelavevej 55, 5500 Middelfart, Denmark route EndelavevejEndelavevej 55, 5500 Middelfart, Denmark locality MiddelfartEndelavevej 55, 5500 Middelfart, Denmark administrative_area_level_2 Middelfart MunicipalityEndelavevej 55, 5500 Middelfart, Denmark country DenmarkEndelavevej 55, 5500 Middelfart, Denmark postal_code 5500

Output of previous slide

Page 41: Read, store and create xml and json

Read, Store and Create XML and JSON41 05/03/2023

XMLTABLE

select geo.* from addresses a , xmltable( '/GeocodeResponse/result' passing a.geocoded columns street_number_name varchar2(10) path 'address_component[type="street_number"]/long_name' , street_name varchar2(20) path 'address_component[type="route"]/long_name' , city_name varchar2(20) path 'address_component[type="locality"]/long_name' , zip_name varchar2(10) path 'address_component[type="postal_code"]/long_name' , country_name varchar2(20) path 'address_component[type="country"]/long_name' ) geo;

STREET_NUM STREET_NAME CITY_NAME ZIP_NAME COUNTRY_NAME---------- -------------------- -------------------- ---------- --------------------55 Endelavevej Middelfart 5500 Denmark

[ ] in XPath expressions also allows syntax to query for specific values

Page 42: Read, store and create xml and json

Read, Store and Create XML and JSON42 05/03/2023

DIRECTIONS EXAMPLE - 1select route.routename , step.instructions , to_char(to_date(to_char(step.seconds,'TM9'), 'SSSSS'), 'HH24:MI:SS') steptime , step.meters/1000 stepkmfrom xmltable( '/DirectionsResponse' passing httpuritype( 'maps.googleapis.com/maps/api/directions/xml' || '?'||'origin=' || utl_url.escape(convert( 'Endelavevej 55, DK-5500 Middelfart' , 'UTF8' )) || '&'||'destination=' || utl_url.escape(convert( 'Rue Marterey 5, CH-1005 Lausanne' , 'UTF8' )) || '&'||'mode=driving'||'&'||'alternatives=true'||'&'||'units=metric' || '&'||'region=eu'||'&'||'language=en'||'&'||'sensor=false' ).getxml() columns response xmltype path '/') directions,...

Page 43: Read, store and create xml and json

Read, Store and Create XML and JSON43 05/03/2023

DIRECTIONS EXAMPLE - 2...xmltable( 'if (fn:empty(/DirectionsResponse/route)) then <route><leg></leg></route> else /DirectionsResponse/route' passing directions.response columns routenum for ordinality , routename varchar2(100) path 'summary' , routexml xmltype path '/') route, xmltable( 'for $l in /route/leg return $l' passing route.routexml columns legnum for ordinality , seconds number path 'duration/value' , meters number path 'distance/value' , startaddr varchar2(100) path 'start_address' , endaddr varchar2(100) path 'end_address' , legxml xmltype path '/') leg,...

Page 44: Read, store and create xml and json

Read, Store and Create XML and JSON44 05/03/2023

DIRECTIONS EXAMPLE - 3...xmltable( 'for $s in /leg/step return $s' passing leg.legxml columns stepnum for ordinality , seconds number path 'duration/value' , meters number path 'distance/value' , instructions varchar2(400) path 'html_instructions') steporder by route.routenum , leg.legnum , step.stepnum;

Page 45: Read, store and create xml and json

Read, Store and Create XML and JSON45 05/03/2023

DIRECTIONS EXAMPLE - OutputROUTENAME INSTRUCTIONS STEPTIME STEPKM---------- ------------------------------------------------------------ -------- ----------A7 and A5 Head <b>northwest</b> on <b>Endelavevej</b> 00:01:05 .309A7 and A5 Turn <b>right</b> to stay on <b>Endelavevej</b> 00:00:27 .124A7 and A5 Turn <b>left</b> onto <b>Bornholmsvej</b> 00:00:42 .396A7 and A5 Turn <b>left</b> onto <b>Vandværksvej</b> 00:04:36 3.274A7 and A5 At the roundabout, take the <b>1st</b> exit onto <b>Jyllands 00:00:26 .242 vej</b>

A7 and A5 At the roundabout, take the <b>1st</b> exit and stay on <b>J 00:00:33 .35 yllandsvej</b>

A7 and A5 At the roundabout, take the <b>2nd</b> exit onto the <b>E20< 00:00:38 .546 /b> ramp

A7 and A5 Merge onto <b>E20</b> 00:04:10 7.229A7 and A5 Keep <b>left</b> at the fork to stay on <b>E20</b>, follow s 00:08:57 15.359 igns for <b>E45s</b>/<b>Flensborg</b>/<b>Esbjerg</b>/<b>Kold ing</b>

A7 and A5 Keep <b>left</b> at the fork to continue on <b>E45</b>, foll 00:47:31 83.159 ow signs for <b>Kolding</b><div style="font-size:0.9em">Ente ring Germany</div>

A7 and A5 Continue onto <b>A7</b>/<b>E45</b> 01:35:25 155.339A7 and A5 Keep <b>left</b> at the fork to stay on <b>A7</b>, follow si 00:09:33 15.067 gns for <b>HH. Othmarschen</b>

A7 and A5 Keep <b>left</b> at the fork to stay on <b>A7</b> 00:03:39 6.845...

Page 46: Read, store and create xml and json

Read, Store and Create XML and JSON46 05/03/2023

JSON_TABLE

select geo.* from addresses2 a , json_table( a.geocoded , '$' columns ( status varchar2(10) path '$.status' , nested path '$.results[*]' columns ( lat number path '$.geometry.location.lat' , lng number path '$.geometry.location.lng' , nested path '$.address_components[*]' columns ( long_name varchar2(30) path '$.long_name' , nested path '$.types[*]' columns ( component_type varchar2(30) path '$' ) ) ) ) ) geo;

Similar but slightly different syntax as XMLTABLESupports NESTED PATH as alternative to chaining XMLTABLE

Page 47: Read, store and create xml and json

Read, Store and Create XML and JSON47 05/03/2023

JSON_TABLE

STATUS LAT LNG LONG_NAME COMPONENT_TYPE---------- ---------- ---------- ------------------------- ------------------------------OK 55.4892307 9.7519265 55 street_numberOK 55.4892307 9.7519265 Endelavevej routeOK 55.4892307 9.7519265 Middelfart localityOK 55.4892307 9.7519265 Middelfart politicalOK 55.4892307 9.7519265 Middelfart Municipality administrative_area_level_2OK 55.4892307 9.7519265 Middelfart Municipality politicalOK 55.4892307 9.7519265 Denmark countryOK 55.4892307 9.7519265 Denmark politicalOK 55.4892307 9.7519265 5500 postal_code

Output of previous slide

Page 48: Read, store and create xml and json

Read, Store and Create XML and JSON48 05/03/2023

JSON short-cut dot-notation

select a.geocoded.status , a.geocoded.results.formatted_address , a.geocoded.results.address_components.long_name from addresses2 a;

STATUS RESULTS RESULTS------ -------------------------------------------------- --------------------------------------------------OK Endelavevej 55, 5500 Middelfart, Denmark ["55","Endelavevej","Middelfart","Middelfart Munic ipality","Denmark","5500"]

Requires table alias – Datatype will just be generic varchar2Can return JSON arrays for multiple elements – Column names quirky

Page 49: Read, store and create xml and json

Read, Store and Create XML and JSON49 05/03/2023

JSON short-cut dot-notation

select a.addr_id , a.geocoded.STATUS , a.geocoded.RESULTS.formatted_address from addresses2 a;

ADDR_ID STATUS RESULTS---------- ------ -------------------------------------------------- 2

Dot-notation is case sensitive – even though looks like regular SQL

Page 50: Read, store and create xml and json

Read, Store and Create XML and JSON50 05/03/2023

JSON short-cut dot-notation with JSON_TABLE

select a.geocoded.results.formatted_address as formatted , geo.* from addresses2 a , json_table( a.geocoded.results.address_components , '$[*]' columns ( long_name varchar2(30) path '$.long_name' , nested path '$.types[*]' columns ( component_type varchar2(30) path '$' ) ) ) geo;

FORMATTED LONG_NAME COMPONENT_TYPE------------------------------------------ ------------------------- ------------------------------Endelavevej 55, 5500 Middelfart, Denmark 55 street_numberEndelavevej 55, 5500 Middelfart, Denmark Endelavevej routeEndelavevej 55, 5500 Middelfart, Denmark Middelfart localityEndelavevej 55, 5500 Middelfart, Denmark Middelfart politicalEndelavevej 55, 5500 Middelfart, Denmark Middelfart Municipality administrative_area_level_2Endelavevej 55, 5500 Middelfart, Denmark Middelfart Municipality politicalEndelavevej 55, 5500 Middelfart, Denmark Denmark countryEndelavevej 55, 5500 Middelfart, Denmark Denmark politicalEndelavevej 55, 5500 Middelfart, Denmark 5500 postal_code

Combine JSON dot-notation and JSON_TABLE

Page 51: Read, store and create xml and json

Read, Store and Create XML and JSON51 05/03/2023

JSON_TABLE vs. XMLTABLE - Comparison of syntax

JSON_TABLE

With underscore

CLOB with IS JSON check

Arg 1: PASSING object

Arg 2: Path to data

Arg 3: Column defs/paths in ( )

Simple JSON dot path with $ = root

Support for NESTED JSON arrays

Cannot query paths dependent on values

XMLTABLE

Without underscore

XMLTYPE object type

Arg 1: Path / XQuery exp to data

Arg 2: PASSING object

Arg 3: Column defs/paths – no ( )

Full XQuery syntax with / = root

Need multiple successive XMLTABLE

XPath expressions allow query like address_component[type="country"]/...

Page 52: Read, store and create xml and json

Read, Store and Create XML and JSON52 05/03/2023

JSON_TABLE

select * from ( select geo.* from addresses2 a, json_table( a.geocoded, '$' columns ( nested path '$.results[*]' columns ( lat number path '$.geometry.location.lat' , lng number path '$.geometry.location.lng' , nested path '$.address_components[*]' columns ( long_name varchar2(15) path '$.long_name' , nested path '$.types[*]' columns ( component_type varchar2(15) path '$' ) ) ) ) ) geo) pivot ( max(long_name) name for component_type in ( 'street_number' as street_number , 'route' as street , 'locality' as city , 'postal_code' as zip , 'country' as country ) );

LAT LNG STREET_NUMBER_N STREET_NAME CITY_NAME ZIP_NAME COUNTRY_NAME---------- ---------- --------------- --------------- --------------- --------------- ---------------55.4892307 9.7519265 55 Endelavevej Middelfart 5500 Denmark

No support for “value lookup” – need SQL to handle that

Page 53: Read, store and create xml and json

Read, Store and Create XML and JSON53 05/03/2023

JSON_TABLE and APEX_JSON

select a.geocoded, apex_json.to_xmltype(a.geocoded) xmlgeo from addresses2 a;GEOCODED XMLGEO------------------------------------------------------------ ------------------------------------------------------------{ <?xml version="1.0" encoding="WINDOWS-1252"?> "results" : [ <json> { <results> "address_components" : [ <row> { <address_components> "long_name" : "55", <row> "short_name" : "55", <long_name>55</long_name> "types" : [ "street_number" ] <short_name>55</short_name> }, <types> { <row>street_number</row> "long_name" : "Endelavevej", </types> "short_name" : "Endelavevej", </row> "types" : [ "route" ] <row> }, <long_name>Endelavevej</long_name> { <short_name>Endelavevej</short_name> "long_name" : "Middelfart", <types> "short_name" : "Middelfart", <row>route</row>... ...

Alternative to PIVOT we can turn JSON into XML with APEX_JSON

Page 54: Read, store and create xml and json

Read, Store and Create XML and JSON54 05/03/2023

JSON_TABLE and APEX_JSON

select geo.* from addresses2 a , xmltable( '/json/results/row' passing apex_json.to_xmltype(a.geocoded) columns street_number_name varchar2(10) path 'address_components/row[types/row="street_number"]/long_name' , street_name varchar2(20) path 'address_components/row[types/row="route"]/long_name' , city_name varchar2(20) path 'address_components/row[types/row="locality"]/long_name' , zip_name varchar2(10) path 'address_components/row[types/row="postal_code"]/long_name' , country_name varchar2(20) path 'address_components/row[types/row="country"]/long_name' ) geo;

STREET_NUM STREET_NAME CITY_NAME ZIP_NAME COUNTRY_NAME---------- -------------------- -------------------- ---------- --------------------55 Endelavevej Middelfart 5500 Denmark

Then we can use XMLTABLE with greater syntax on the converted JSON

Page 55: Read, store and create xml and json

Read, Store and Create XML and JSON55 05/03/2023

Creation

Page 56: Read, store and create xml and json

Read, Store and Create XML and JSON56 05/03/2023

XMLROOT, XMLELEMENT

select xmlroot( xmlelement("DeptName", d.dname) , version '1.0' ) department from scott.dept d where d.deptno = 30;

DEPARTMENT--------------------------------------------------------------------------------<?xml version="1.0"?><DeptName>SALES</DeptName>

XMLROOT creates XML header with version infoXMLELEMENT creates an element with start & end tag and content between

Page 57: Read, store and create xml and json

Read, Store and Create XML and JSON57 05/03/2023

XMLELEMENT

select xmlroot( xmlelement( "Department" , xmlelement("DeptNo", d.deptno) , xmlelement("DeptName", d.dname) ) , version '1.0' ) department from scott.dept d where d.deptno = 30;

Nesting XMLELEMENT – multiple XMLELEMENT within one XMLELEMENT

DEPARTMENT-------------------------------<?xml version="1.0"?><Department> <DeptNo>30</DeptNo> <DeptName>SALES</DeptName></Department>

Page 58: Read, store and create xml and json

Read, Store and Create XML and JSON58 05/03/2023

XMLFOREST

select xmlroot( xmlelement( "Department" , xmlforest( d.deptno as "DeptNo" , d.dname as "DeptName" ) ) , version '1.0' ) department from scott.dept d where d.deptno = 30;

Shortcut for multiple XMLELEMENT

DEPARTMENT---------------------------------------<?xml version="1.0"?><Department> <DeptNo>30</DeptNo> <DeptName>SALES</DeptName></Department>

Page 59: Read, store and create xml and json

Read, Store and Create XML and JSON59 05/03/2023

Multiple rows

select xmlroot( xmlelement( "Department" , xmlforest( d.deptno as "DeptNo" , d.dname as "DeptName" ) ) , version '1.0' ) department from scott.dept d;

Here we get one XML object for each department – one in each row of output

DEPARTMENT-------------------------------------<?xml version="1.0"?><Department> <DeptNo>10</DeptNo> <DeptName>ACCOUNTING</DeptName></Department>

<?xml version="1.0"?><Department> <DeptNo>20</DeptNo> <DeptName>RESEARCH</DeptName></Department>

<?xml version="1.0"?><Department> <DeptNo>30</DeptNo> <DeptName>SALES</DeptName></Department>

<?xml version="1.0"?><Department> <DeptNo>40</DeptNo> <DeptName>OPERATIONS</DeptName></Department>

Page 60: Read, store and create xml and json

Read, Store and Create XML and JSON60 05/03/2023

XMLAGG

select xmlroot( xmlelement( "Departments" , xmlagg( xmlelement( "Department" , xmlforest( d.deptno as "DeptNo" , d.dname as "DeptName" ) ) order by d.deptno ) ) , version '1.0' ) department from scott.dept d;

XMLAGG aggregates “Department” elements within “Departments” element

DEPARTMENT--------------------------------------<?xml version="1.0"?><Departments> <Department> <DeptNo>10</DeptNo> <DeptName>ACCOUNTING</DeptName> </Department> <Department> <DeptNo>20</DeptNo> <DeptName>RESEARCH</DeptName> </Department> <Department> <DeptNo>30</DeptNo> <DeptName>SALES</DeptName> </Department> <Department> <DeptNo>40</DeptNo> <DeptName>OPERATIONS</DeptName> </Department></Departments>

Page 61: Read, store and create xml and json

Read, Store and Create XML and JSON61 05/03/2023

Nested XMLAGG

select xmlroot( xmlelement( "Departments" , xmlagg( xmlelement( "Department" , xmlforest( d.deptno as "DeptNo" , d.dname as "DeptName" , ( select xmlagg( xmlelement( "Employee" , xmlforest( e.empno as "EmpNo“ , e.ename as "EmpName" ) ) order by e.empno ) from scott.emp e where e.deptno = d.deptno ) as "Employees" ) ) order by d.deptno ) ) , version '1.0' ) department from scott.dept d where d.deptno = 10;

XMLAGG nested as subquery within XMLAGG

<?xml version="1.0"?><Departments> <Department> <DeptNo>10</DeptNo> <DeptName>ACCOUNTING</DeptName> <Employees> <Employee> <EmpNo>7782</EmpNo> <EmpName>CLARK</EmpName> </Employee> <Employee> <EmpNo>7839</EmpNo> <EmpName>KING</EmpName> </Employee> <Employee> <EmpNo>7934</EmpNo> <EmpName>MILLER</EmpName> </Employee> </Employees> </Department></Departments>

Page 62: Read, store and create xml and json

Read, Store and Create XML and JSON62 05/03/2023

Nested XMLAGG

select xmlroot( xmlelement( "Departments" , xmlagg( xmlelement( "Department" , xmlforest( d.deptno as "DeptNo" , max(d.dname) as "DeptName" , xmlagg( xmlelement( "Employee" , xmlforest( e.empno as "EmpNo" , e.ename as "EmpName" ) ) order by e.empno ) as "Employees" ) ) order by d.deptno ) ) , version '1.0' ) department from scott.dept d join scott.emp e on e.deptno = d.deptno where d.deptno = 10 group by d.deptno;

Join and GROUP BY – Inner XMLAGG is “group” aggregate – Outer XMLAGG is “total”

<?xml version="1.0"?><Departments> <Department> <DeptNo>10</DeptNo> <DeptName>ACCOUNTING</DeptName> <Employees> <Employee> <EmpNo>7782</EmpNo> <EmpName>CLARK</EmpName> </Employee> <Employee> <EmpNo>7839</EmpNo> <EmpName>KING</EmpName> </Employee> <Employee> <EmpNo>7934</EmpNo> <EmpName>MILLER</EmpName> </Employee> </Employees> </Department></Departments>

Page 63: Read, store and create xml and json

Read, Store and Create XML and JSON63 05/03/2023

XMLATTRIBUTES

select xmlroot( xmlelement( "Departments" , xmlagg( xmlelement( "Department" , xmlattributes(d.deptno as "DeptNo") , xmlforest( max(d.dname) as "DeptName" , xmlagg( xmlelement( "Employee" , xmlattributes(e.empno as "EmpNo") , xmlelement("EmpName", e.ename) ) order by e.empno ) as "Employees" ) ) order by d.deptno ) ) , version '1.0' ) department from scott.dept d join scott.emp e on e.deptno = d.deptno where d.deptno = 10 group by d.deptno;

Typically some elements are turned into attributes – makes more “terse” XML

<?xml version="1.0"?><Departments> <Department DeptNo="10"> <DeptName>ACCOUNTING</DeptName> <Employees> <Employee EmpNo="7782"> <EmpName>CLARK</EmpName> </Employee> <Employee EmpNo="7839"> <EmpName>KING</EmpName> </Employee> <Employee EmpNo="7934"> <EmpName>MILLER</EmpName> </Employee> </Employees> </Department></Departments>

Page 64: Read, store and create xml and json

Read, Store and Create XML and JSON64 05/03/2023

Object types

create type emp_t as object (empno number, empname varchar2(10));

create type emp_tt as table of emp_t;

create type dept_t as object ( deptno number , deptname varchar2(15) , employees emp_tt);

create type dept_tt as table of dept_t;

create type depts_t as object (departments dept_tt);

Created object types can be basis for XML

Page 65: Read, store and create xml and json

Read, Store and Create XML and JSON65 05/03/2023

XMLTYPE Constructor for Object Types

select xmltype( depts_t( cast( collect( dept_t( d.deptno , max(d.dname) , cast( collect( emp_t(e.empno, e.ename) ) as emp_tt ) ) ) as dept_tt ) ) ) department from scott.dept d join scott.emp e on e.deptno = d.deptno where d.deptno = 10 group by d.deptno;

Object types can be passed as argument to XMLTYPE constructor

<DEPTS_T> <DEPARTMENTS> <DEPT_T> <DEPTNO>10</DEPTNO> <DEPTNAME>ACCOUNTING</DEPTNAME> <EMPLOYEES> <EMP_T> <EMPNO>7782</EMPNO> <EMPNAME>CLARK</EMPNAME> </EMP_T> <EMP_T> <EMPNO>7934</EMPNO> <EMPNAME>MILLER</EMPNAME> </EMP_T> <EMP_T> <EMPNO>7839</EMPNO> <EMPNAME>KING</EMPNAME> </EMP_T> </EMPLOYEES> </DEPT_T> </DEPARTMENTS></DEPTS_T>

Page 66: Read, store and create xml and json

Read, Store and Create XML and JSON66 05/03/2023

XMLTYPE Constructor for REF CURSOR

select xmltype( cursor( select d.deptno "DeptNo" , d.dname "DeptName" from scott.dept d where d.deptno = 10 )) department from dual;

Cursor variables can be passed to XMLTYPE constructor

<?xml version="1.0"?><ROWSET> <ROW> <DeptNo>10</DeptNo> <DeptName>ACCOUNTING</DeptName> </ROW></ROWSET>

Page 67: Read, store and create xml and json

Read, Store and Create XML and JSON67 05/03/2023

Nested REF CURSOR

select xmltype( cursor( select d.deptno "DeptNo" , d.dname "DeptName" , cursor( select e.empno "EmpNo" , e.ename "EmpName" from scott.emp e where e.deptno = d.deptno ) "Employees" from scott.dept d where d.deptno = 10 )) department from dual;

Cursor variables can contain nested cursor variables

<?xml version="1.0"?><ROWSET> <ROW> <DeptNo>10</DeptNo> <DeptName>ACCOUNTING</DeptName> <Employees> <Employees_ROW> <EmpNo>7782</EmpNo> <EmpName>CLARK</EmpName> </Employees_ROW> <Employees_ROW> <EmpNo>7839</EmpNo> <EmpName>KING</EmpName> </Employees_ROW> <Employees_ROW> <EmpNo>7934</EmpNo> <EmpName>MILLER</EmpName> </Employees_ROW> </Employees> </ROW></ROWSET>

Page 68: Read, store and create xml and json

Read, Store and Create XML and JSON68 05/03/2023

DbUriType

select dburitype( '/SCOTT/DEPT' ).getxml() departments from dual;

DbUriType accesses schema/table via XMLDB

<?xml version="1.0"?><DEPT> <ROW> <DEPTNO>10</DEPTNO> <DNAME>ACCOUNTING</DNAME> <LOC>NEW YORK</LOC> </ROW> <ROW> <DEPTNO>20</DEPTNO> <DNAME>RESEARCH</DNAME> <LOC>DALLAS</LOC> </ROW> <ROW> <DEPTNO>30</DEPTNO> <DNAME>SALES</DNAME> <LOC>CHICAGO</LOC> </ROW> <ROW> <DEPTNO>40</DEPTNO> <DNAME>OPERATIONS</DNAME> <LOC>BOSTON</LOC> </ROW></DEPT>

Page 69: Read, store and create xml and json

Read, Store and Create XML and JSON69 05/03/2023

DbUriType

select dburitype( '/SCOTT/EMP/ROW[ENAME="KING"]' ).getxml() employees from dual;

Data can be queried using XPath expressions

<?xml version="1.0"?><ROW> <EMPNO>7839</EMPNO> <ENAME>KING</ENAME> <JOB>PRESIDENT</JOB> <HIREDATE>17-NOV-81</HIREDATE> <SAL>5000</SAL> <DEPTNO>10</DEPTNO></ROW>

Page 70: Read, store and create xml and json

Read, Store and Create XML and JSON70 05/03/2023

APEX_JSON

begin apex_json.initialize_clob_output; apex_json.open_array('Departments'); for d in (select deptno, dname from scott.dept where deptno = 10) loop apex_json.open_object('Department'); apex_json.write('DeptNo', d.deptno); apex_json.write('DeptName', d.dname); apex_json.open_array('Employees'); for e in (select empno, ename from scott.emp e where e.deptno = d.deptno) loop apex_json.open_object('Employee'); apex_json.write('EmpNo', e.empno); apex_json.write('EmpName', e.ename); apex_json.close_object; end loop; apex_json.close_array; apex_json.close_object; end loop; apex_json.close_array; dbms_output.put_line(apex_json.get_clob_output); apex_json.free_output;end;/

Page 71: Read, store and create xml and json

Read, Store and Create XML and JSON71 05/03/2023

APEX_JSON

"Departments":["Department":{"DeptNo":10,"DeptName":"ACCOUNTING","Employees":["Employee":{"EmpNo":7782,"EmpName":"CLARK"},"Employee":{"EmpNo":7839,"EmpName":"KING"},"Employee":{"EmpNo":7934,"EmpName":"MILLER"}]}]

Output of previous slide

Page 72: Read, store and create xml and json

Read, Store and Create XML and JSON72 05/03/2023

APEX_JSON

declare c sys_refcursor;begin open c for select d.deptno "DeptNo" , d.dname "DeptName" , cursor( select e.empno "EmpNo" , e.ename "EmpName" from scott.emp e where e.deptno = d.deptno ) "Employees" from scott.dept d where d.deptno = 10; apex_json.initialize_clob_output; apex_json.open_object; apex_json.write('Departments', c); apex_json.close_object; dbms_output.put_line(apex_json.get_clob_output); apex_json.free_output;end;

Besides building manually, APEX_JSON also supports cursor variable

Page 73: Read, store and create xml and json

Read, Store and Create XML and JSON73 05/03/2023

APEX_JSON

{"Departments":[{"DeptNo":10,"DeptName":"ACCOUNTING","Employees":[{"EmpNo":7782,"EmpName":"CLARK"},{"EmpNo":7839,"EmpName":"KING"},{"EmpNo":7934,"EmpName":"MILLER"}]}]}

This time output of ref cursor in a single line

Page 74: Read, store and create xml and json

Read, Store and Create XML and JSON74 05/03/2023

The end

Page 75: Read, store and create xml and json

Read, Store and Create XML and JSON75 05/03/2023

Links

This presentation PowerPoint http://bit.ly/kibeha_xmljson_pptx

Script with all examples from this presentation http://bit.ly/kibeha_xmljson_sql

Page 76: Read, store and create xml and json

Questions & AnswersKim Berg HansenSenior Consultant

[email protected]

05/03/2023 Read, Store and Create XML and JSON76

http://bit.ly/kibeha_xmljson_pptxhttp://bit.ly/kibeha_xmljson_sql