XML (XSISDK)


XML is a standard which defines how data can be represented in memory and inside text files. It is versatile and can be used to represent any data.

XSI uses XML files for some of its persistence, so it is possible to read and write these files using XML APIs, which are freely available. By using XML a lot of the picky details of parsing files are hidden, making development fast and simple.

XML files used by XSI include Toolbars and Views.

XSI (starting with v5.0) includes some scripting code that generates XML files, including a toolbar wizard and the CreateXMLDoc class. These are intended for use internally and are not part of the official SDK, but they can provide useful starting points for quickly generating XML content within your script. For reading XML it is recommended you use an existing DOM implementation rather than trying to implement it yourself.

For example of reading a simple XML file within JScript check out loadAddonDetails inside <XSIINSTALLATION>\Plugins\Addons\sdkui\Application\Plugins\AddonDoc.js


The Collada (http:\\www.collada.org) interchange format is also based on XML.

See File System Access and "Writing Toolbar files with Scripting".

Using XML in Scripting (tutorial by Andy Nicholas) (http://www.andynicholas.com/thezone/index.php?area=showitem&fromarea=programming&page=0&order=0&sort=date&article=4)

Table of contents

jscript XML Primer (Using DOM with XSI)

by Bradley Gabe

Introduction

The DOM object has many many properties and methods, and thus can be overwhelming to the XML neophyte. To further matters, most of the online examples center around building html and other web-related functions. The purpose of the follwing section is to provide enough of a subset of DOM functionality to get an XSI scripter up and running with reading and writing XML using jscript.

For more info on all the DOM objects, interfaces, properties, and methods, check out the msdn docs here: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/xmlsdk/html/d051f7c5-e882-42e8-a5b6-d1ce67af275c.asp

Special thanks go out to Andy Buecker and Helge Mathee for inspiration on the possibilities of using XML in conjunction with scripting.

Building a simple XML tree

Step 1 in working with DOM is instantiating a new instance of the ActiveX object into your script.

// Instantiate the DOM object
var xmlDoc = new ActiveXObject("MSXML2.DOMDocument.3.0");

Each node you wish to add to your new DOM document object must go through two steps:

  1. Creation of the node, probably using the createElement() method
  2. Attachment to the tree structure using the appendChild() method

Here's a quick example that instantiates a new DOM document, adds a root node, some child nodes, and saves out the file:

// Instantiate the DOM object
var xmlDoc = new ActiveXObject("MSXML2.DOMDocument.3.0");

// Add the tree root node (notice 2 steps... create, then append)
var rootElem = xmlDoc.createElement('Root');
xmlDoc.appendChild(rootElem);

// Create two node elements
var fredElem = xmlDoc.createElement('Fred');
var barneyElem = xmlDoc.createElement('Barney');

// Append the node elements to the tree structure
rootElem.appendChild(fredElem);
rootElem.appendChild(barneyElem);

// Create two more node elements
var bamElem = xmlDoc.createElement('Bambam');
var pebElem = xmlDoc.createElement('Pebbles');

// Append the node elements to the tree structure
fredElem.appendChild(pebElem);
barneyElem.appendChild(bamElem);

// Save the file out
var xmlFileName = 'c:/foo1.xml';
xmlDoc.save(xmlFileName);

If you double click and open the new XML file at 'c:/foo1.xml' into an Internet Explorer or other XML viewer, you should have the following XML tree structure:

<Root>
    <Fred>
        <Pebbles /> 
    </Fred>
    <Barney>
        <Bambam /> 
    </Barney>
</Root>

Using DOM, you can create as many nodes as you like before connecting them into the tree. You can connect them based on logic structures, or you can build branches, then assemble the branches into a tree. You can also leave branches dangling by not connecting them, so be careful.

A tree of only nodes isn't very useful for us, since the only data that is being stored is hierarchy and the node names. You can also store attributes inside the tag, or wrapped between tags:

To

// Instantiate the DOM object
var xmlDoc = new ActiveXObject("MSXML2.DOMDocument.3.0");

// Add the tree root node (notice 2 steps... create, then append)
var rootElem = xmlDoc.createElement('Root');
xmlDoc.appendChild(rootElem);

// Create a node element
var fredElem = xmlDoc.createElement('Fred');
rootElem.appendChild(fredElem);

// Add attributes inside the node tag
fredElem.setAttribute('town', 'Bedrock');
fredElem.setAttribute('wife', 'Wilma');

// Create more nodes, attach to tree
var childElem = xmlDoc.createElement('Child');
var petElem = xmlDoc.createElement('Pet');
fredElem.appendChild(childElem);
fredElem.appendChild(petElem);

// Create text attributes to be wrapped by tags
var childAttr = xmlDoc.createTextNode('Pebbles');
var petAttr = xmlDoc.createTextNode('Dino');
childElem.appendChild(childAttr);
petElem.appendChild(petAttr);

// Save the file out
var xmlFileName = 'c:/foo2.xml';
xmlDoc.save(xmlFileName);

Check the new XML file generated by this script, it should resemble the following:

<Root>
    <Fred town="Bedrock" wife="Wilma">
        <Child>Pebbles</Child> 
        <Pet>Dino</Pet> 
    </Fred>
</Root>

Building an XML tree to store XSI scene data

We now know enough XML to build an external file to store data about our XSI scene. The following function stores a subset of scene information:

function WriteXML(xmlFileName)
{
	// Instantiate the DOM object for ActiveX XML
	var xmlDoc = new ActiveXObject("MSXML2.DOMDocument.3.0");
		
	// Create the tree root, append it to the XML object
	var rootElem = xmlDoc.createElement('Scene_Root');
	xmlDoc.appendChild(rootElem);	
	
	// Get all the X3D nodes in the scene
	var X3DColl = ActiveSceneRoot.FindChildren();
	
	// For each X3D object in the scene, add a node to the XML tree
	for(var e = new Enumerator(X3DColl); !e.atEnd(); e.moveNext()){	
		var obj = e.item();
               
        // Create XML node with obj name
		var objElem = xmlDoc.createElement(obj.name);
		rootElem.appendChild(objElem);
		
		
		// Add type, Model Space, and parent info inside tag
		objElem.setAttribute('type', obj.type);
		objElem.setAttribute('model', obj.model);
		objElem.setAttribute('parent', obj.parent);
	
		// Get obj child info
		var childColl = new ActiveXObject('XSI.Collection');
		if(obj.children.count) childColl.AddItems(obj.children);
		var childList = childColl + '';

		// Store child info wrapped by tags
		var childElem = xmlDoc.createElement('children');
		var childAttrib = xmlDoc.createTextNode(childList);
		childElem.appendChild(childAttrib);
		objElem.appendChild(childElem);
		
		// Get visibility info
		var vis = Dictionary.GetObject(obj + '.Visibility.viewvis').value;
		var sel = Dictionary.GetObject(obj + '.Visibility.selectability').value;

		// Store visibility info inside node tag
		var visElem = xmlDoc.createElement('Visibility');
		visElem.setAttribute('vis', vis);
		visElem.setAttribute('sel', sel);
		objElem.appendChild(visElem);
	}
	
	// Save out the XML file	
	xmlDoc.save(xmlFileName);
	return(true);
}

Reading XML data

To read an XML file into an instance of the DOM object, start with the following code:

// Read in the xml file into a new DOM object
xmlFileName = 'c:/foo2.xml';
var xmlDoc = new ActiveXObject("MSXML2.DOMDocument.3.0");
xmlDoc.load(xmlFileName);
if(xmlDoc.parseError.errorCode != 0){
	var myErr = xmlDoc.parseError;
    LogMessage('XML Parse Error: ' + myErr.reason, 2);
}

Once an XML tree is fully loaded into the instance of the DOM object, we can navigate through the tree by hunting specific node tag names using the getElementsByTagName() method. This method can be called from the DOM object, or from any elements further in the tree, and it returns a collection of any element nodes with a matching name (The asterisk wildcard can also be used).

Once a specific element is found, any attributes can be read from inside the tag using the getAttribute() method.

// Read in the xml file into a new DOM object
xmlFileName = 'c:/foo2.xml';
var xmlDoc = new ActiveXObject("MSXML2.DOMDocument.3.0");
xmlDoc.load(xmlFileName);
if(xmlDoc.parseError.errorCode != 0){
	var myErr = xmlDoc.parseError;
    LogMessage('XML Parse Error: ' + myErr.reason, 2);
}
else{
    var fredColl = xmlDoc.getElementsByTagName('Fred');
    if(fredColl(0)){
    	var fredNode = fredColl(0);
    	var wife = fredNode.getAttribute('wife');
    	var town = fredNode.getAttribute('town');
    	
    	LogMessage(fredNode.nodeName + ':' + wife + ',' + town); 
    }
}

It is also possible to navigate through a tree by testing the hasChildNodes() method from a node, and enumerating through the childNodes property similar to enumerating through children collections in XSI.

To access text attributes wrapped by tags (not inside the tag) get a pointer to the attribute element, then use the nodeTypedValue property:

// Read in the xml file into a new DOM object
xmlFileName = 'c:/foo2.xml';
var xmlDoc = new ActiveXObject("MSXML2.DOMDocument.3.0");
xmlDoc.load(xmlFileName);
if(xmlDoc.parseError.errorCode != 0){
	var myErr = xmlDoc.parseError;
    LogMessage('XML Parse Error: ' + myErr.reason, 2);
}
else{
	
	// Navigate to Fred node
	var root = xmlDoc.childNodes(0);
	var fred = root.childNodes(0);
	LogMessage(fred.nodeName + ': ' + fred.childNodes.length);
	
	// Enumerate through Fred's child nodes
    if(root.hasChildNodes()){
        for(var e = new Enumerator(fred.childNodes); !e.atEnd(); e.moveNext()){
            var elem = e.item();
            
            var name = elem.nodeName;
			var val = elem.nodeTypedValue;
            
            LogMessage(name + ': ' + val);
        }
    }
}

Reading an XML file into an XSI scene

We now know enough to read the XML file created by the sample WriteXML() function above and use the data to affect an XSI scene. The following function will report the contents of the XML file to the command history:

function ReadXML(xmlFileName)
{
	// Read in the xml file into a new DOM object
	var xmlDoc = new ActiveXObject("MSXML2.DOMDocument.3.0");
	xmlDoc.load(xmlFileName);
	if(xmlDoc.parseError.errorCode != 0){
   		var myErr = xmlDoc.parseError;
		LogMessage('XML Parse Error: ' + myErr.reason, 2);
		return(false);
	}
	
	// Traverse xml nodes
	var sceneNodes = xmlDoc.documentElement.childNodes;
	for(var e = new Enumerator(sceneNodes); !e.atEnd(); e.moveNext()){
	
		var node = e.item();
		var objName = node.nodeName;
		
		// Get the type, model, and parent attributes
		var type = node.getAttribute('type');
		var modelName = node.getAttribute('model');
		var parName = node.getAttribute('parent');
				
		// Get the child data
		var childNode = node.childNodes(0);
		var childList = childNode.nodeTypedValue;
		var childArr = childList.split(',');
		
		if(!childList)
			childCount=0;
		else
			childCount = childArr.length;
	
	
		// Get visibility data
		var visNode = node.childNodes(1);
		var vis = visNode.getAttribute('vis') ==  true;
		var sel = visNode.getAttribute('sel') == false;
		
		// Report collected data
		LogMessage(objName + '(type=' + type + '), ' + 'parent=' + parName + ', childCount=' + childCount + ', vis=' + vis + ', sel=' + sel);
	}
}

This page was last modified 04:09, 2 Oct 2010.
This page has been accessed 184877 times.

© Copyright 2009 Autodesk Inc. All Rights Reserved. Privacy Policy | Legal Notices and Trademarks | Report Piracy