[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.
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?
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.
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