View Full Version : xml.dom.minidom module not found

03-30-2012, 05:01 PM
I wrote a script to cleanup the Collada files generated by Lightwave. It removes all the <extra> nodes and the extra translate and rotate nodes. The import xml.dom.minidom gives a module not found error. To get it to work I had to go into the python27.zip and extract the "pyexpat.pyd" file into the bin folder. The entire source code is below but the error comes from the import statement at the beginning.

Is there a way I can make this work without extracting the file?

#! /usr/bin/env python
# -*- Mode: Python -*-
# -*- coding: ascii -*-

This is a LightWave Generic plug-in that cleans a collada export

import sys
import lwsdk
import xml.dom.minidom
import os
import tempfile
import re

__author__ = "Clinton Reese"
__date__ = "Mar 25 2012"
__copyright__ = "Clinton's 3D Creations"
__version__ = "1.0"
__maintainer__ = "Clinton Reese"
__email__ = "[email protected]"
__status__ = "Example"
__lwver__ = "11"

#had to copy pyexpat.pyd from inside python27.zip to bin and restart LW
#otherwise get module not found error
class fix_collada(lwsdk.IGeneric):
def __init__(self, context):
super(fix_collada, self).__init__()
self._filepath = ""
self._savepath = ""
self._removeExtras = True
self._removeExtraRotations = True
self._removeExtraTranslations = True

# LWGeneric -------------------------------------------
def process(self, ga):
# panels
# /LightWave11.0/sdk/lwsdk11.0/html/globals/panel.html
# /LightWave11.0/sdk/lwsdk11.0/include/lwpanel.h
ui = lwsdk.LWPanels()
panel = ui.create('Collada Fixer')

controlWidth = 128
c1 = panel.load_ctl('Select File',controlWidth)
c2 = panel.save_ctl('Save As',controlWidth)
#c = BOOL_CTL( pf, pan, label
c3 = panel.bool_ctl('Remove <extra> nodes')
c4 = panel.bool_ctl('Remove extra rotation nodes')
c5 = panel.bool_ctl('Remove extra translation nodes')

panel.align_controls_vertical([c1, c2, c3, c4, c5])

c3.set_int(1 if self._removeExtras else 0)
c4.set_int(1 if self._removeExtraRotations else 0)
c5.set_int(1 if self._removeExtraTranslations else 0)

if panel.open(lwsdk.PANF_BLOCKING | lwsdk.PANF_CANCEL) == 0:
return lwsdk.AFUNC_OK

self._filepath = c1.get_str()
self._savepath = c2.get_str()
self._removeExtras = (c3.get_int() == 1)
self._removeExtraRotations = (c4.get_int() == 1)
self._removeExtraTranslations = (c5.get_int() == 1)

if not(self._removeExtras or self._removeExtraRotations or self._removeExtraTranslations):
print >>sys.stderr,'At least one removal option must be selected.'
return lwsdk.AFUNC_OK

if self._filepath == '':
print >>sys.stderr,'Select a Collada file that is to be cleaned.'
return lwsdk.AFUNC_OK

if not os.path.exists(self._filepath):
print >>sys.stderr,'Input file does not exist.'
return lwsdk.AFUNC_OK

if self._savepath == '':
print >>sys.stderr,'Need a destination file.'
return lwsdk.AFUNC_OK

print self._filepath
print self._savepath

doc = xml.dom.minidom.parse(self._filepath)

#remove <extra>
if self._removeExtras:
extras = doc.getElementsByTagName('extra')
for extra in extras:
parentNode = extra.parentNode

#remove meaniningless <translate>
if self._removeExtraTranslations:
translates = doc.getElementsByTagName('translate')
for translate in translates:
sid = translate.getAttribute('sid')
#print translate.toxml()
if sid != 'translate':
val = translate.childNodes[0].data
if val == '0 0 0':
parentNode = translate.parentNode

#remove meaningless <rotate>
if self._removeExtraRotations:
rotates = doc.getElementsByTagName('rotate')
for rotate in rotates:
sid = rotate.getAttribute('sid')
if sid != 'rotateX' and sid !='rotateY' and sid !='rotateZ':
val = rotate.childNodes[0].data
valsplit = val.split()
if valsplit[3] == '0':
parentNode = rotate.parentNode

#create a temporary file to receive the changes
f_temp, temppath = tempfile.mkstemp(suffix='.txt', text=True)
f_temp = open(temppath,'w+')

#write the xml to the temp file
#go to start of the file for reading
f_temp.seek(0, os.SEEK_SET)
#new collada file
f = open(self._savepath,'w')
#regular expression line starts with one or more spaces followed by a newline
blankLine = re.compile('^ +\n')
firstLine = True
for fileline in f_temp:
#xml.dom.mini loses the original structure of the first 2 lines
if firstLine:
f.write('<?xml version="1.0" encoding="UTF-8"?>\n')
f.write('<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1">\n')
firstLine = False
#don't write the blank lines
if blankLine.search(fileline): continue


#delete the temp file

return lwsdk.AFUNC_OK

ServerTagInfo = [
( "Python Fix Collada", lwsdk.SRVTAG_USERNAME | lwsdk.LANGID_USENGLISH ),
( "Fix Collada", lwsdk.SRVTAG_BUTTONNAME | lwsdk.LANGID_USENGLISH ),
( "Utilities/Python", lwsdk.SRVTAG_MENU | lwsdk.LANGID_USENGLISH )

ServerRecord = { lwsdk.GenericFactory("LW_PyFixCollada", fix_collada) : ServerTagInfo }

04-10-2012, 11:03 AM
It does exist in the distribution. Here's an example of its usage:


However, it requires a shared library module ("pyexpat.pyd") in order to function.

Since Python 2.7.2 cannot load shared libraries from a Zip file, you must extract the Python library files found in "bin/python27.zip" to a folder called "bin/Lib". Once extracted, delete or rename "python27.zip", run LightWave, and Python should be able to locate and use all the shared libraries bundled within the "Lib/" folder (including "bin/Lib/pyexpat.pyd").

04-10-2012, 11:40 AM
Good tip, thank you!