Notifications
Clear all

[Closed] XML using samples

I want to start a new thread where everyone free to post good samples of XML using. and of course everyone free to ask and answer questions.

here is my first sample… how to store and load nodes list. i store all scene dummies, their name, parent name, position and box size. reading a file i restore whole data…


  fn saveDummyFile filename: = 
  (
  	if filename == unsupplied do filename = getSaveFilename caption:"Save Dummy List File" types:"Dummy List (.xml)|*.xml"
  		
  	if filename != undefined do
  	if iskindof (doc = dotnetobject "System.Xml.XmlDocument") dotnetobject do
  	(
  		if getfilenametype filename == "" do filename += ".xml"
  		nodes = for d in (getclassinstances dummy) collect (refs.dependentnodes d firstonly:on)
  		
  		doc.AppendChild (doc.CreateComment "Dummy List. Version 1.0")
  		doc.AppendChild (doc.CreateComment ("File: " + maxfilepath + maxfilename))
  		doc.AppendChild (doc.CreateComment ("Creation Date: " + localtime))
  		doc.AppendChild (doc.CreateWhitespace "
")
  
  		doc.AppendChild (xnodes = doc.CreateElement "nodes")
  		xnodes.SetAttribute "count" (nodes.count as string)
  		for node in nodes do
  		(
  			xnodes.AppendChild (xnode = doc.CreateElement "node")
  			xnode.SetAttribute "node" node.name
  			xnode.SetAttribute "parent" (if node.parent == undefined then "" else node.parent.name)
  			xnode.SetAttribute "pos" (node.pos as string)
  			xnode.SetAttribute "boxsize" (node.boxsize as string)
  		)
  		doc.Save filename
  		-- edit filename
  		filename
  	)
  )
  fn loadDummyFile filename: = 
  (
  	if filename == unsupplied do filename = getOpenFilename caption:"Load Dummy List File" types:"Dummy List (.xml)|*.xml"
  		
  	if iskindof filename string and doesfileexist filename do
  	if iskindof (doc = dotnetobject "System.Xml.XmlDocument") dotnetobject do
  	(
  		doc.Load filename
  		local xnodes = doc.selectnodes "//node"
  		local nodes = for k=0 to xnodes.count-1 collect
  		(
  			xnode = xnodes.item[k]
  			name = xnode.getattribute "node"
  			parent = xnode.getattribute "parent"
  			pos = execute (xnode.getattribute "pos")
  			boxsize = execute (xnode.getattribute "boxsize")
  			d = dummy name:name pos:pos boxsize:boxsize
  			#(d, parent)
  		)
  		for n in nodes do if (p = getnodebyname n[2]) != undefined do n[1].parent = p
  	)
  )
  
  -- create test scene:
  (
  	delete objects
  	nodes = #()
  	for k=1 to 200 do
  	(
  		d = dummy pos:(random [-40,-40,-40] [40,40,40]) boxsize:(random [1,1,1] [10,10,10])
  		if (i = random 0 nodes.count) > 1 do d.parent = nodes[i] 
  		
  		append nodes d
  	)	
  )
  -- save scene
  _dummyfile = saveDummyFile()
  
  -- reset scene
  resetmaxfile #noPrompt 
  -- load nodes
  loadDummyFile filename:_dummyfile
  

as you see i also save some extra data with file: data type, scene filename, and date of creation. these can help me later in any case.

with save and load functions i provide two methods to define filename. you can supply it as optional parameter, or manually set using file browser.

if you are new to XML data try to understand how this sample works first. later i will show the problems of this method. and everyone free to point me on any found problems and shortcomings.

7 Replies

Very nice and simple example.
I post from previous thread my snippet for storing some script settings


  (
  local okToShow = true
  dotnet.loadAssembly "system.xml" 
  struct sr_Settings_struct (lvDataArr, locX, locY, ms, mse, mcr, mxsArr, mxsENArr, mxsFav)
  struct sr_XML_struct
  (
 	 xmlFile,
 	 sioDir = dotNetClass "System.IO.Directory",
 	 sioFile = dotNetClass "System.IO.File",
 	 sysStr = dotNetClass "System.String",
 	 fn compareFNames arr str ignoreCase:true multi:true = 
 	 (
 		 if multi then (for p in 1 to arr.count where (sysStr.Compare arr[p][2] str ignoreCase) == 0 collect p).count
 		 else (for p in 1 to arr.count where (sysStr.Compare arr[p] str ignoreCase) == 0 collect p).count
 	 ),
 	 fn isValidXML file =
 	 (
 		 try ((dotNetObject "System.Xml.XmlDocument").Load file == undefined)
 		 catch (okToShow = false ; ((trimleft ((s=filterstring (getCurrentException()) ":")[s.count]) " ")+" Do you want to edit 'srSettings.xml' ?"))
 	 ),
 	 fn xmlCreator dnXML: prtNode: tagName: innerTxt: attArr: make:#xmlElement =
 	 (
 		 local tag = if make != #xmlComment then (dnXML.createElement tagName) else (dnXML.createComment tagName)
 		 prtNode.AppendChild tag
 		 if innerTxt != unsupplied do tag.InnerText = innerTxt
 		 if attArr != unsupplied do (for i = 1 to attArr.count do tag.SetAttribute attArr[i][1] attArr[i][2]) ; tag
 	 ),
 	 fn getXMLvalue dnXML: tagName: type: =
 	 (
 		 local val = (dnXML.selectNodes tagName).ItemOf[0].InnerText
 		 if type != unsupplied then val as type else val
 	 ),
 	 fn saveXML xmlFile pX: pY: msExt: mseExt: mcrExt: dirArr: favArr: =
 	 (
 		 xmldoc = dotNetObject "System.Xml.XmlDocument"
 		 sRun = xmlCreator dnXML:xmldoc prtNode:xmldoc tagName:"ScriptRun" \
 		 attArr:#(#("version","1.1a"), #("author","Branko Zivkovic"), #("email","barigazy@hotmail.com"))
 		 sPaths = xmlCreator dnXML:xmldoc prtNode:sRun tagName:"FolderPaths"
 		 cmt_sPaths = xmlCreator dnXML:xmldoc prtNode:sPaths tagName:"Child elements of the *FolderPaths* element tags (<fp_0 ... />, <fp_1 .../> etc.)" make:#xmlComment
 		 for i = 1 to dirArr.count do
 		 (
 			 fpe = xmlCreator dnXML:xmldoc prtNode:sPaths tagName:("fp_" + ((i-1) as String)) \
 			 attArr:#(#("path", dirArr[i][2]), #("use_subfolders", (dirArr[i][1] as String)))
 		 )
 		 sSett = xmlCreator dnXML:xmldoc prtNode:sRun tagName:"ScriptSettings"
 		 sLocX = xmlCreator dnXML:xmldoc prtNode:sSett tagName:"location_x" innerTxt:(pX as String)
 		 sLocY = xmlCreator dnXML:xmldoc prtNode:sSett tagName:"location_y" innerTxt:(pY as String)
 		 sMS = xmlCreator dnXML:xmldoc prtNode:sSett tagName:"use_ms" innerTxt:(msExt as String)
 		 sMSE = xmlCreator dnXML:xmldoc prtNode:sSett tagName:"use_mse" innerTxt:(mseExt as String)
 		 sMCR = xmlCreator dnXML:xmldoc prtNode:sSett tagName:"use_mcr" innerTxt:(mcrExt as String)
 		 sFav = xmlCreator dnXML:xmldoc prtNode:sRun tagName:"FavoriteScripts"
 		 cmt_sFav = xmlCreator dnXML:xmldoc prtNode:sFav tagName:"Child elements of the *FavoriteScripts* element tags (<fs_0 ... </fs_0>, <fs_1 ... </fs_1> etc.)" make:#xmlComment
 		 if favArr.count != 0 do
 		 (
 			 favArr = for s in favArr where sioFile.Exists s collect s
 			 if favArr.count != 0 do (for i = 1 to favArr.count do xmlCreator dnXML:xmldoc prtNode:sFav tagName:("fs_" + ((i-1) as String)) innerTxt:(favArr[i]))
 		 )
 		 xmldoc.Save xmlFile
 	 ),
 	 fn loadXML xmlFile = if (v=isValidXML xmlFile) != true then (if queryBox v title:"srSettings.xml Error Message" beep:false do edit xmlFile) else 
 	 (
 		 local lvItms = #(), xpos, ypos, useMS, useMSE, useMCR, mxsFiles = #(), mxsFilesEN = #(), mxsFavorites = #()
 		 xmldoc = dotNetObject "System.Xml.XmlDocument"
 		 sioSOpt = dotNetClass "System.IO.SearchOption"
 		 xmldoc.Load xmlFile
 		 rootEle = xmldoc.DocumentElement
 		 fp = rootEle.Item["FolderPaths"]
 		 ss = rootEle.Item["ScriptSettings"]
 		 fs = rootEle.Item["FavoriteScripts"]
 		 if fp.ChildNodes.count == 0 then lvItms = #(#(false, (getDir #scripts))) else
 		 (
 			 for i = 1 to fp.ChildNodes.count-1 do
 			 (
 				 usf = fp.ChildNodes.ItemOf[i].Attributes.ItemOf["use_subfolders"].value as BooleanClass
 				 dir = fp.ChildNodes.ItemOf[i].Attributes.ItemOf["path"].value
 				 if sioDir.Exists dir do append lvItms #(usf,dir)
 			 )
 		 )
 		 xpos = (ss.Item["location_x"].InnerText) as Integer
 		 ypos = (ss.Item["location_y"].InnerText) as Integer
 		 useMS = (ss.Item["use_ms"].InnerText) as BooleanClass
 		 useMSE = (ss.Item["use_mse"].InnerText) as BooleanClass
 		 useMCR = (ss.Item["use_mcr"].InnerText) as BooleanClass
 		 if lvItms.count != 0 do
 		 (
 			 stateArr = #(useMS, useMSE, useMCR)
 			 extArr = #("*.ms", "*.mse", "*.mcr")
 			 for i = 1 to lvItms.count do
 			 (
 				 filtOpt = if lvItms[i][1] then sioSOpt.AllDirectories else sioSOpt.TopDirectoryOnly
 				 for s = 1 to 3 where stateArr[s] do join mxsFiles (sioDir.GetFiles lvItms[i][2] extArr[s] filtOpt)
 			 )
 			 mxsFiles = makeUniqueArray mxsFiles
 			 mxsFilesEN = for f in mxsFiles collect #(getFilenameFile f, toLower (trimleft (getFilenameType f) "."))
 			 if fs.ChildNodes.count > 1 do
 			 (
 				 for i = 1 to fs.ChildNodes.count-1 where sioFile.Exists (fs.Item[("fs_" + (i-1) as string)].InnerText) do append mxsFavorites (fs.Item[("fs_" + (i-1) as string)].InnerText)
 				 /*(
 					 fsc = getXMLvalue dnXML:xmldoc tagName:("//fs_" + i as String)
 					 if mxsFavorites.count == 0 then (if sioFile.Exists fsc do append mxsFavorites fsc)
 					 else (if sioFile.Exists fsc and (compareFNames mxsFavorites fsc multi:false) != 1 do append mxsFavorites fsc)					
 				 )*/
 			 )
 			 srSETT = sr_Settings_struct lvDataArr:lvItms locX:xpos locY:ypos ms:useMS mse:useMSE mcr:useMCR mxsArr:mxsFiles mxsENArr:mxsFilesEN mxsFav:mxsFavorites
 		 )
 	 ),
 	 on create do
 	 (
 		 xmlFile = getdir #expression + "\\srSettings.xml"
 		 if sioFile.Exists xmlFile then loadXML xmlFile else
 		 (
 			 local posX = ((dotNetClass "Screen").PrimaryScreen.WorkingArea.Width/2) - 120
 			 local posY = ((dotNetClass "Screen").PrimaryScreen.WorkingArea.Height/2) - 11
 			 saveXML xmlFile pX:posX pY:posY msExt:true mseExt:true mcrExt:false dirArr:#(#(false, (getDir #scripts))) favArr:#()
 			 loadXML xmlFile
 		 )
 	 )
  )
  )
 

Now questions:
#1 Can you explain Normalize method for XML Document object?
#2 What’s good or bad in my method?
#3 As thexmlMtlExporter is not exposed can you shows as some workaround for storing ei
export-import material to XML format? I know that some maps properties are not exposed also but I think that the XMLMaterial isbetter way for soring mats then MaterialLibrary (I can’t open *.mat in previous version of max).
#4 XPath methods or xmlDocument methods which one is better?

By the way thank you for triggered this topic.

in my sample it doesn’t make sense. i’ve made the snippet using some my other code. so it’s useless thing in our case.

denis, why do you create a System.Xml.XmlDocument and then immediatly compare it to a dotnetobject ?? seems redundant to me?

1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

it’s from old code… it was a time when not all versions of max (.net) supported System.Xml.XmlDocumen… and (dotnetobject “System.Xml.XmlDocumen”) returned undefined. you are right. today this check is obsolete.

 MZ1

Is it better to use structure for storing object data?

 MZ1

Here is my codes for converting data between Treeview and XML :

	fn RecurseTVToXML XmlDoc TVNd XmlNd  =
	(
		NewXmlNd = XmlDoc.createElement TVNd.Name
		XmlNd.appendChild NewXmlNd
		for i=0 to TvNd.Nodes.count-1 do RecurseTVToXML XmlDoc TvNd.Nodes.Item[i] NewXmlNd 
	)
	
	
	fn TVToXML TheTV XmlFile = 
	(
		if TheTV!= undefined then
		(
			XmlDoc=dotNetObject "system.xml.xmlDocument"
			RecurseTVToXML XmlDoc TheTV XmlDoc 
			XmlDoc.save XmlFile
		)
	)
	

	fn RecurseXMLToTV XmlNd TVNd  = 
	(
		NewTVNd = (dotNetObject "System.Windows.Forms.TreeNode" (XmlNd.Name)) 
		NewTVNd.name = (XmlNd.Name)
		TVNd.nodes.add NewTVNd 
		for i=0 to XmlNd.childnodes.count-1 do RecurseXMLToTV XmlNd.childnodes.itemof[i] NewTVNd  
	)
	
	
	fn XMLToTV XmlFile TheTV  =
	(		
		if XmlFile!= undefined and TheTV!= undefined and doesFileExist XmlFile then
		(
			XmlDoc=dotNetObject "system.xml.xmlDocument"
			XmlDoc.load XmlFile
			docEle=XmlDoc.documentElement
			for i=0 to docEle.childnodes.count-1 do RecurseXMLToTV docEle.childnodes.itemof[i] TheTV 
		)
	)

As we can’t use LINQ to XML to read xml files, one alternative is to use Xpath. Here’s a sample to get the max command panel height from the cui config file, which would be a ball ache to get otherwise.

fn getCommandPanelHeight =
(
xmlDoc = dotNetObject "system.xml.xmlDocument"
xmlDoc.load (cui.getConfigFile())
CmdNode = xmlDoc.selectNodes "//Window[@name='Command Panel']/DRect/@bottom|//Window[@name='Command Panel']/DRect/@top"
if cmdNode != undefined and cmdNode.count == 2 then
	(CmdNode.itemof[1].value as integer) - (CmdNode.itemof[0].value as integer) 
else undefined
)

there’s some other examples on KlaasNienhuis’s blog

as well as a great intro here
http://www.w3schools.com/xpath/xpath_syntax.asp