Initializing help system before first use

Parsing XML and JSON documents


Type: Programming
Rating: 4 (medium-difficult)
Description: The parsing routines 'xmlparse' and 'jsonparse' expect tables of (optional) functions implemented by the Mosel model in order to return detailed information about each node of the document without any prior knowledge of the document structure.
Within Mosel, JSON documents are represented as XML trees.
File(s): xparse.mos, jparse.mos
Data file(s): refexample.xml


xparse.mos
(!******************************************************
   Mosel Example Problems
   ======================

   file xparse.mos
   ```````````````
   A simple example of the use of the SAX parser in mmxml
   
   (c) 2014 Fair Isaac Corporation
       author: Y. Colombani, October 2014
*******************************************************!)

model xparse
uses 'mmxml'

declarations
 d:xmldoc
end-declarations

forward public procedure myload(d:xmldoc,fname:text)

myload(d,"refexample.xml")
save(d,"")

!------------------------------------------------------

! The following structure will be used to store the state of the parser
declarations
 public s_ctx=
    record
	doc:xmldoc
	curnode:integer
    end-record
end-declarations

!------------------------------------------------------

! **** Callback function: Beginning of an element ****
public function start_elt(c:s_ctx,name:text,nba:integer):integer
 declarations
  att,val:text
 end-declarations

 c.curnode:=addnode(c.doc,c.curnode,XML_ELT,name)
 ! 'xmlattr' is used to retrieve attributes associated to current node
 ! 'xmlattr(att,val)' can also be used to retrieve the value of attribute 'att'
 forall(i in 1..nba) do
  xmlattr(i,att,val)
  setattr(c.doc,c.curnode,string(att),val)
 end-do
 xmlattr("name",val)
end-function

! **** Callback function: Mark the end of a an element ****
public function end_elt(c:s_ctx):integer
 c.curnode:=getparent(c.doc,c.curnode)
end-function

! **** Callback function: Store a text object 
!     'type' indicates the XML node type (e.g. TEXT, CDATA...) ****
public function txthdl(c:s_ctx,type:integer,data:text):integer
 n:=addnode(c.doc,c.curnode,type,data)
end-function

! **** Callback function: Record document declaration details ****
public function xdecl(c:s_ctx,vers:text,encoding:text,std:integer):integer
 setencoding(c.doc,string(encoding))
 setstandalone(c.doc,std)
 setxmlversion(c.doc,string(vers))
end-function

! **** Callback function: Store a processing instruction ****
public function pinst(c:s_ctx,target:text,data:text):integer
 n:=addnode(c.doc,c.curnode,XML_PINST,string(target),data)
end-function

!------------------------------------------------------

! **** An implementation of 'load(xmldoc,text)' using the SAX parser ****
public procedure myload(d:xmldoc,fname:text)
 declarations
  afct:array(range) of string
  ctx:s_ctx
 end-declarations

 afct(XML_FCT_DECL):="xdecl"         ! Declaration (XML version, encoding)
 afct(XML_FCT_TXT):="txthdl"         ! Text
 afct(XML_FCT_CDATA):="txthdl"       ! Cdata
 afct(XML_FCT_COM):="txthdl"         ! Comment
 afct(XML_FCT_DATA):="txthdl"        ! Data (non qualifiee)
 afct(XML_FCT_PINST):="pinst"        ! Processing instruction
 afct(XML_FCT_OPEN_ELT):="start_elt" ! Start of an element
 afct(XML_FCT_CLOSE_ELT):="end_elt"  ! End of an element

 ctx.curnode:=0;
 fopen(fname,F_INPUT)
 ! 'xmlparse' expects a table of functions (all are optional)
 ! the option indicates whether spaces should be kept (0: keep spaces;
 ! 1: skip spaces)
 ! the last argument will be passed to all functions
 rts:=xmlparse(afct,1,ctx)
 fclose(F_INPUT)
 d:=ctx.doc
end-procedure

end-model

jparse.mos
(!******************************************************
   Mosel Example Problems
   ======================

   file xparse.mos
   ```````````````
   A simple example of the use of the JSON parser in mmxml
   
   (c) 2014 Fair Isaac Corporation
       author: Y. Colombani, October 2014
*******************************************************!)

model jparse

uses 'mmxml'

declarations
 d:xmldoc
 public src=`
[
 {
  "name": "bob",
  "age": 25,
  "student": true,
  "phone":
  [
   { "type": "home", "number": "1234567900" },
   { "type": "work", "number": "6789012345" }
  ],
  "empty":null
  }
]
`
end-declarations

forward public procedure myjsonload(d:xmldoc,fname:text)

myjsonload(d,"text:src")
save(d,"")

!------------------------------------------------------

! The following structure will be used to store the state of the parser
declarations
 public s_ctx=
    record
	doc:xmldoc
	jtype:array(0..3) of string
	curnode:integer
    end-record
end-declarations

!------------------------------------------------------

! **** Callback function: Start an object ****
public function open_obj(c:s_ctx,name:text):integer
 c.curnode:=addnode(c.doc,c.curnode,XML_ELT,if(name="","jsv",string(name)))
 setattr(c.doc,c.curnode,"jst","obj")
end-function

! **** Callback function: End an object ****
public function close_obj(c:s_ctx):integer
 c.curnode:=getparent(c.doc,c.curnode)
end-function

! **** Callback function: Start an array ****
public function open_arr(c:s_ctx,name:text):integer
 c.curnode:=addnode(c.doc,c.curnode,XML_ELT,if(name="","jsv",string(name)))
 setattr(c.doc,c.curnode,"jst","arr")
end-function

! **** Callback function: End an array ****
public function close_arr(c:s_ctx):integer
 c.curnode:=getparent(c.doc,c.curnode)
end-function

! **** Callback function: Store a value ****
public function setvalue_all(c:s_ctx,name:text,type:integer,val:text):integer
 n:=addnode(c.doc,c.curnode,XML_ELT,if(name="","jsv",string(name)),val)
 setattr(c.doc,n,"jst",c.jtype(type))
end-function

! **** Callback function: Store a numerical value 
!      ('JSON_FCT_TEXT' is used if this one is not defined) ****
public function setvalue_num(c:s_ctx,name:text,val:real):integer
 n:=addnode(c.doc,c.curnode,XML_ELT,if(name="","jsv",string(name)),text(val))
 setattr(c.doc,n,"jst","num")
end-function

! **** Callback function: Store a Boolean value 
!      ('JSON_FCT_TEXT' is used if this one is not defined) ****
public function setvalue_bool(c:s_ctx,name:text,val:boolean):integer
 n:=addnode(c.doc,c.curnode,XML_ELT,if(name="","jsv",string(name)),text(val))
 setattr(c.doc,n,"jst","boo")
end-function

! **** Callback function: Store the null value 
!      ('JSON_FCT_TEXT' is used if this one is not defined) ****
public function setvalue_null(c:s_ctx,name:text):integer
 n:=addnode(c.doc,c.curnode,XML_ELT,if(name="","jsv",string(name)),"null")
 setattr(c.doc,n,"jst","nul")
end-function

!------------------------------------------------------

! **** An implementation of 'jsonload(xmldoc,text)' using the JSON parser ****
public procedure myjsonload(d:xmldoc,fname:text)
 declarations
  afct:array(range) of string
  ctx:s_ctx
 end-declarations

 afct(JSON_FCT_OPEN_OBJ):="open_obj"      ! Start an object
 afct(JSON_FCT_CLOSE_OBJ):="close_obj"    ! End an object
 afct(JSON_FCT_OPEN_ARR):="open_arr"      ! Start an array
 afct(JSON_FCT_CLOSE_ARR):="close_arr"    ! End an array
 afct(JSON_FCT_TEXT):="setvalue_all"      ! A value as a text
 afct(JSON_FCT_NUM):="setvalue_num"       ! A numerical value
 afct(JSON_FCT_BOOL):="setvalue_bool"     ! A Boolean value
 afct(JSON_FCT_NULL):="setvalue_null"     ! The "null" value

 fopen(fname,F_INPUT)
 ctx.curnode:=0;
 ctx.jtype::([0,1,2,3])["nul","str","num","boo"]
 ! 'jsonparse' expects a table of functions (all are optional)
 ! the last argument will be passed to all functions
 rts:=jsonparse(afct,ctx)
 fclose(F_INPUT)
 d:=ctx.doc
end-procedure

end-model