Initializing help system before first use

Using XML-format files as databases


Type: Programming
Rating: 3 (intermediate)
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:
     <personnelList> 
       <employee id=""> 
         <startDate>
         <name>
         <address> 
         <language>
       </employee>
     </personnelList> 
   
  (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

© 2001-2019 Fair Isaac Corporation. All rights reserved. This documentation is the property of Fair Isaac Corporation (“FICO”). Receipt or possession of this documentation does not convey rights to disclose, reproduce, make derivative works, use, or allow others to use it except solely for internal evaluation purposes to determine whether to purchase a license to the software described in this documentation, or as otherwise set forth in a written software license agreement between you and FICO (or a FICO affiliate). Use of this documentation and the software described in it must conform strictly to the foregoing permitted uses, and no other use is permitted.