Alternative text data file formats
In the previous section we have introduced the I/O driver mmsheet.csv that reads and writes text files in CSV format. With only minimal changes to the previous model we now switch to a different text data format, namely the diskdata file format that is accessed via the diskdata I/O driver.
model Burglar2dd ... initializations from "mmetc.diskdata:sparse;noq" [VALUE,WEIGHT] as "burglardd.dat" end-initializations ... initializations to "mmetc.diskdata:append,sparse" SOLTAKE as "burglarout.txt" end-initializations end-model
This will result in exactly the same behaviour as when using the procedure diskdata of the module mmetc instead of the initializations blocks.
model Burglar2ddb uses "mmetc", "mmxprs" ... ! Reading data from file diskdata(ETC_SPARSE+ETC_NOQ, "burglardd.dat", [VALUE,WEIGHT]) ... ! Solution output diskdata(ETC_OUT+ETC_APPEND+ETC_SPARSE, "burglarout.txt", SOLTAKE) end-model
The data file burglardd.dat used in both cases has the following contents.
! Data file for `burglar2dd.mos' camera, 15, 2 necklace, 100, 20 vase, 90, 20 picture, 60, 30 tv, 40, 40 video, 15, 30 chest, 10, 60 brick, 1, 10
The result file burglarout.txt is now formatted as shown here.
"camera",1 "necklace",1 "vase",1 "picture",1 "tv",0 "video",1 "chest",0 "brick",0
The diskdata I/O driver and the procedure diskdata are documented in the section `mmetc' in the `Mosel Language Reference Manual'.
XML and JSON format files
The data for our example problem could also be provided in the form of the following XML file burglar.xml.
<!-- Data file for `burglar2x.mos' --> <BurgData> <Item name="camera"> <Value> 15</Value> <Weight> 2</Weight> </Item> <Item name="necklace"> <Value>100</Value> <Weight>20</Weight> </Item> <Item name="vase"> <Value> 90</Value> <Weight>20</Weight> </Item> <Item name="picture"> <Value> 60</Value> <Weight>30</Weight> </Item> <Item name="tv"> <Value> 40</Value> <Weight>40</Weight> </Item> <Item name="video"> <Value> 15</Value> <Weight>30</Weight> </Item> <Item name="chest"> <Value> 10</Value> <Weight>60</Weight> </Item> <Item name="brick"> <Value> 1</Value> <Weight>10</Weight> </Item> </BurgData>
Given that XML files do not use any fixed format that would make it possible to define a suitable I/O driver, we cannot read or write XML files through initializations blocks. XML files need to be parsed or queried for their contents using the routines of the mmxml module. The data file burglar.xml is read into our Mosel data structures using the following code:
declarations ITEMS: set of string ! Index set for items VALUE: array(ITEMS) of real ! Value of items WEIGHT: array(ITEMS) of real ! Weight of items BurgData, ResData: xmldoc ! XML document Root, Node: integer ! XML nodes NodeList: list of integer end-declarations ! Reading data from an XML file load(BurgData, "burglar.xml") ! Retrieve all 'Item' nodes getnodes(BurgData, "BurgData/Item", NodeList) ! Retrieve 'Value' and 'Weight' information forall(i in NodeList) do VALUE(getstrattr(BurgData,i,"name")):= getrealvalue(BurgData, getnode(BurgData, i, "Value") ) WEIGHT(getstrattr(BurgData,i,"name")):= getrealvalue(BurgData, getnode(BurgData, i, "Weight") ) end-do
For generating solution output in XML format we need to build up an XML document following standard XML design rules (all elements are forming a tree under a single root element).
! Create solution representation in XML format Root:=addnode(ResData, 0, XML_ELT, "SolTake") ! Create root node "SolTake" setattr(ResData, Root, "objective", getobjval) ! ... with attr. "objective" forall(i in ITEMS) do Node:=addnode(ResData, Root, XML_ELT, "Item") ! Add a node to "SolTake" setattr(ResData, Node, "name", i) ! ... with attribute "name" setvalue(ResData, Node, SOLTAKE(i)) ! ... and solution value end-do save(ResData, "burglarout.xml") ! Save solution to XML format file
This Mosel code will result in the following output (the appearance can be influenced via different controls and settings of mmxml, see the corresponding chapter of the `Mosel Language Reference Manual'):
<?xml version="1.0" encoding="iso-8859-1"?> <SolTake objective="280"> <Item name="camera">1</Item> <Item name="necklace">1</Item> <Item name="vase">1</Item> <Item name="picture">1</Item> <Item name="tv">0</Item> <Item name="video">1</Item> <Item name="chest">0</Item> <Item name="brick">0</Item> </SolTake>
The module mmxml also provides routines for reading and writing text files in JSON format, transforming them internally to an XML-based representation where JSON 'values' are encoded as jsv elements. The value of the attribute 'jst' indicates the object type ( 'num'—number, 'boo'—boolean, 'str'—string, 'nul'—null, 'obj'—object, or 'arr'—array). Elements representing object members have the name of the member (instead of jsv).
Data from the following JSON file
{ "Item": [ {"Name":"camera", "Value": 15, "Weight": 2}, {"Name":"necklace", "Value":100, "Weight":20}, {"Name":"vase", "Value": 90, "Weight":20}, {"Name":"picture", "Value": 60, "Weight":30}, {"Name":"tv", "Value": 40, "Weight":40}, {"Name":"video", "Value": 15, "Weight":30}, {"Name":"chest", "Value": 10, "Weight":60}, {"Name":"brick", "Value": 1, "Weight":10} ] }
can be read with this Mosel code (all declarations remain the same as in the previous model version reading XML format data):
! Reading data from a JSON file jsonload(BurgData, "burglar.json") ! Retrieve all 'Item' nodes getnodes(BurgData, "jsv/Item/jsv", NodeList) ! Retrieve 'Value' and 'Weight' information forall(i in NodeList) do VALUE(getstrvalue(BurgData, getnode(BurgData,i,"Name"))):= getrealvalue(BurgData, getnode(BurgData, i, "Value") ) WEIGHT(getstrvalue(BurgData, getnode(BurgData,i,"Name"))):= getrealvalue(BurgData, getnode(BurgData, i, "Weight") ) end-do
After loading the contents of a JSON file, it may be helpful to display the resulting XML representation on screen since we parse this representation to retrieve the input data:
save(BurgData, "") ! Display the XML representation on screen
The results output in JSON format is constructed using XML routines:
! Create solution representation in JSON format Root:=addnode(ResData, 0, XML_ELT, "jsv") ! Create root node "jsv" Node:=addnode(ResData, Root, "Objective", getobjval) ! Add a node to "jsv" Node:=addnode(ResData, Root, XML_ELT, "Items") ! Add a node to "jsv" forall(i in ITEMS) n:=addnode(ResData, Node, i, SOLTAKE(i)) ! Add a node to "Items" jsonsave(ResData, "burglarout.json") ! Save solution to JSON format file
This results in the following output in file burglarout.json:
{ "Objective":280, "Items":{ "camera":1, "necklace":1, "vase":1, "picture":1, "tv":0, "video":1, "chest":0, "brick":0 } }
Free format files
If none of the provided text file access methods fits a particular data file format, you can always use read/readln in combination with fopen and fclose. For example, a data file of the form
! Data file for `burglar2ff.mos' camera [v=15, w=2] necklace [v=100, w=20] ...
can be read by the following Mosel code (model file burglar2ff.mos)
fopen("burglarff.dat", F_INPUT) ! Open file for reading while (not iseof) do ! Read up to end-of-file fskipline("!") ! Skip lines starting with '!' readln(j, " [v=", VALUE(j), ", w=", WEIGHT(j), "]") if getparam("nbread") < 6 then writeln("Error reading data for index '", j, "'") end-if end-do fclose(F_INPUT) ! Close the input file
And similarly, for redirecting output to a file instead of displaying it on the default output (screen) we simply surround it by fopen and fclose, this time selecting the output stream in fopen:
fopen("burglarsol.txt", F_OUTPUT) writeln("Solution:\n Objective: ", getobjval) forall(i in ITEMS) writeln(" take(", i, "): ", getsol(take(i))) fclose(F_OUTPUT)
Multiline text or string
It is also possible to include data in the form of text blocks directly in a model. A multiline text (or string) must be surrounded by backquotes and an optional marker text. For example, the text data file read by the initial version of our model can be included and read thus (model version burglar2t.mos):
public declarations default_data: text ! Data input values end-declarations default_data:= `--------------- Input data ---------------- ! Item Value Weight BurgData: [(camera) [ 15 2] (necklace) [100 20] (vase) [ 90 20] (picture) [ 60 30] (tv) [ 40 40] (video) [ 15 30] (chest) [ 10 60] (brick) [ 1 10]] --------------- Input data ----------------` initializations from "text:default_data" [VALUE,WEIGHT] as "BurgData" end-initializations
And similarly, for redirecting output in Mosel's text format to a text block instead of writing it to a physical file we can use the following Mosel code:
public declarations burglarout: text ! Solution output end-declarations initializations to "text:burglarout" SOLTAKE end-initializations ! Display contents of output file writeln("Solution file:\n", burglarout)
© 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.