Initializing help system before first use

Using XML-format files as databases


Type: Programming
Rating: 3
Description:
  • Using xpath search expressions to retrieve (lists of) nodes
  • Editing an XML file: adding, copying, deleting nodes
  • Configuring the appearance (e.g. spacing) of XML output files
The example 'booksearch.mos' works with a database file documenting the example models from the book 'Applications of optimizaion with Xpress-MP'.
The example 'xmlrefexpl.mos' works with a personnel database, retrieving and modifying some of its entries.
File(s): booksearch.mos, xmlrefexpl.mos
Data file(s): bookexamples.xml, refexample.xml


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

   file booksearch.mos
   ```````````````````
   Retrieving information from an XML database file.
   
  (c) 2010 Fair Isaac Corporation
      author: S.Heipcke, July 2010, rev. Sep 2012
*******************************************************!)

model "Search book examples"
 uses "mmxml"
 
 declarations
   ExampleDB: xmldoc
   Chapters, Models, Models3, Ratings, Files: list of integer 
 end-declarations

! Read in the XML file
 load(ExampleDB, "bookexamples.xml")          


! **** Get all chapters 
 getnodes(ExampleDB, "/examples/chapter", Chapters)
 writeln("Chapter titles:\n  ", 
         union(c in Chapters) {getattr(ExampleDB, c, "title")})


! **** Search for all difficult examples (difficulty rating 4 or larger)
 writeln("Difficult examples:")
 getnodes(ExampleDB, "/examples/chapter/model/modRating[number()>=4]", Ratings)
 forall(r in Ratings) do
   m:=getparent(ExampleDB, r)
   t:=getnode(ExampleDB, m, "modTitle")
   writeln("  Example: ", getattr(ExampleDB, m, "id"), " ",
           getvalue(ExampleDB, t), " (rating: ",
           getvalue(ExampleDB, r), ")")
 end-do

(! Alternatively: 
 getnodes(ExampleDB, "//model/modRating[number()>=4]/..", Models)
 forall(e in Models) do
   t:=getnode(ExampleDB, e, "modTitle")
   writeln("  Example: ", getattr(ExampleDB, e, "id"), " ",
           getvalue(ExampleDB, t), " (rating: ",
           getvalue(ExampleDB, getnode(ExampleDB, e, "modRating")), ")")
 end-do
!)


! **** Search for all model files where "SOS" is mentioned under among features
 writeln("Models using SOS:")
 forall(c in Chapters) do
   getnodes(ExampleDB, c,
            "model/modFeatures[contains(string(),'SOS')]/../modFile", Files)
   forall(f in Files)
      writeln("  File: ", getattr(ExampleDB, c, "directory"), "/",
              getvalue(ExampleDB, f))
 end-do


! **** Search for all examples with several model files
 writeln("Examples with several model files:")
 getnodes(ExampleDB, 
          "/examples/chapter/model/modFile[position()=2]/..", Models)
 forall(e in Models) do
   getnodes(ExampleDB, e, "modFile[position()>2]", Files)
   writeln("  Example: ", getattr(ExampleDB, e, "id"), " (",
           2+Files.size, " files)")
 end-do
 
end-model 

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

   file xmlrefexpl.mos
   ```````````````````
   Example for mmxml ref man.

   Working with a personnel database of the format:
      
        
         
         
         
(c) 2012 Fair Isaac Corporation author: S.Heipcke, Sep. 2012 *******************************************************!) model "xmlref examples" uses "mmxml" declarations DB: xmldoc NodeList, Employees, AllEmployees: list of integer Root, Pers: integer NodeNames: set of string end-declarations ! Reading data from an XML file load(DB, "refexample.xml") ! Set indentation mode for XML output (default after load: MANUAL) setindentmode(DB, XML_AUTO) ! 'getnode' / 'getnodes' ! Get the first element that is not a comment or a processing instruction Root:= getnode(DB,"*") ! Same as: getnode(DB,0,"*") ! Get the name of the employee with attribute id="T345" writeln("**** id='T345': ", getvalue(DB, getnode(DB, "personnelList/region/employee[@id='T345']/name") )) ! Get the 'region' node with id=EMEA EMEA:= getnode(DB, "personnelList/region[@id='EMEA']") ! Check for employee record (node) for 'Sam' under 'EMEA' if getnode(DB, EMEA, "employee/name[string()='Sam']/..")<0 then writeln("No employee called 'Sam' in EMEA") end-if ! List all employees writeln("**** All employees:") getnodes(DB, "personnelList/region/employee", AllEmployees) forall(p in AllEmployees) writeln(textfmt(getvalue(DB, getnode(DB, p, "name")), -10), " (ID: ", getattr(DB,p,"id"), ") region: ", getattr(DB, getparent(DB, p), "id")) ! Get all employees in the Americas getnodes(DB, "personnelList/region[@id='AM']/employee", Employees) writeln("**** Americas employees:") forall(p in Employees) save(DB, p, "") ! All employees who started before 2005 getnodes(DB, "personnelList/region/employee/startDate[number()<2005]/..", Employees) writeln("**** Started before 2005:") forall(p in Employees) save(DB, p, "") ! All employees whose names start with "J" writeln("**** Names starting with 'J':") forall(n in AllEmployees) do getnodes(DB, n, "./name[starts-with(string(),'J')]/..", Employees) forall(p in Employees) save(DB, p, "") end-do ! Employees speaking at least 3 languages (=have a third "language" entry) getnodes(DB, "personnelList/region/employee/language[position()=3]/..", Employees) writeln("**** Speaking at least 3 languages:") forall(p in Employees) save(DB, p, "") ! 'testattr' / 'delattr' ! Switch part-time workers to full-time (delete attribute "parttime") getnodes(DB, "personnelList/region/employee[@parttime]", Employees) writeln("**** Number of part-time workers: ", Employees.size) forall(p in AllEmployees | testattr(DB, p, "parttime")) do writeln(getvalue(DB, getnode(DB, p, "name"))) delattr(DB, p, "parttime") end-do ! 'addnode' ! Add a node to the end of the APAC region personnel list APAC:= getnode(DB, "personnelList/region[@id='APAC']") ! Append a new node to 'APAC' and set its attribute 'id': NewPers:= addnode(DB, APAC, XML_LASTCHILD, XML_ELT, "employee") setattr(DB, NewPers, "id", "T432") ! Create a comment: n:= addnode(DB, NewPers, XML_COM, "This is a new employee") ! Add 2 nodes containing the specified text (nodes): n:= addnode(DB, NewPers, XML_ELT, "startDate", text(2012)) n:= addnode(DB, NewPers, XML_ELT, "name", "Tim") ! Add an empty node, then set its contents: n:= addnode(DB, NewPers, XML_ELT, "address") setvalue(DB, n, "Sydney") ! Add an empty node, then create its contents as a text node: n:= addnode(DB, NewPers, XML_ELT, "language") n:= addnode(DB, n, XML_TXT, "English") writeln("**** Newly added person:") save(DB, NewPers, "") ! save(DB, APAC, "") ! 'getfirstchild' / 'getlastchild' / 'getnext' writeln("**** APAC employees:") Pers:= getfirstchild(DB, APAC) LastPers:= getlastchild(DB, APAC) while(Pers>-1) do if getname(DB, Pers)="employee" then write(" ", getattr(DB,Pers,"id"), ":", getvalue(DB, getnode(DB, Pers, "name"))) end-if if Pers=LastPers then writeln; end-if Pers:= getnext(DB, Pers) end-do ! 'copy' / 'delnode' / 'setvalue' ! Employee Lisa moves to Delhi: ! Retrieve employee record (node) for 'Lisa' Pers:= getnode(DB, "personnelList/region/employee/name[string()='Lisa']/..") ! Copy node, then delete in original location NewPers:= copynode(DB, Pers, DB, APAC, XML_LASTCHILD) delnode(DB, Pers) ! Update the 'address' information setvalue(DB, getnode(DB, NewPers, "address"), "Delhi") writeln("**** After moving:") save(DB, NewPers, "") ! Spacing: * add line in between regions; ! * display three consecutive tags within 'employee' on a single line ! Originally read data has spacing information, newly defined entries all ! need to be set manually -> we redefine spaces for every tag ! New line without indentation for Root setvspace(DB, Root, 1) ! Add extra line in between regions, keeping original indentation getnodes(DB, "personnelList/region", NodeList) forall(r in NodeList) setvspace(DB, r, 2) ! Spacing/indentation for 'employee' tag getnodes(DB, "personnelList/region/employee", Employees) forall(p in Employees) do setvspace(DB, p, 1); sethspace(DB, p, 4) ! Within 'employee', display up to three consecutive tags on a single line getnodes(DB, p, "child::node()[position() mod 3=1]", NodeList) forall(r in NodeList) do setvspace(DB, r, 1); sethspace(DB, r, 6) end-do getnodes(DB, p, "child::node()[position() mod 3<>1]", NodeList) forall(r in NodeList) do setvspace(DB, r, 0); sethspace(DB, r, 1) end-do end-do ! First 'language' starts on a new line and others are printed on the same line getnodes(DB, "personnelList/region/employee/language[position()>=2]", NodeList) forall(r in NodeList) do setvspace(DB, r, 0); sethspace(DB, r, 1) end-do getnodes(DB, "personnelList/region/employee/language[position()=1]", NodeList) forall(r in NodeList) do setvspace(DB, r, 1); sethspace(DB, r, 6) end-do writeln("**** Manual formatting:") ! Set indentation mode to 'manual' to see our own formatting setindentmode(DB, XML_MANUAL) ! save(DB, NewPers, "") save(DB, "") ! 'getname' ! Collect the names of all element nodes occurring in a document: getnodes(DB, "/descendant-or-self::node()", NodeList) NodeNames:= union(r in NodeList | gettype(DB,r)=XML_ELT) {getname(DB,r)} writeln("**** Names of element nodes: ", NodeNames) end-model