S.Prasanna,
sprasanna199@gmail.com
Here I will discuss my experience with PyXML and Jython. I tried to make the best use of Jython with the latest PyXML module. While working with PyXML is a fairly easy task in Python, making things things to work with the latest PyXML in Jython is bit tricky.
Below is a simple code, which gets the servlets and their mappings from the Web.xml file in Tomcat.
Listing 1: XMLParse.py
1 #XMLParse.py
2 from xml.dom import minidom
3
4
#Open the
parser
5 doc = minidom.parse(open("Web.xml" , "r"))
6
7 mapping = doc.getElementsByTagName('servlet-mapping')
8
servlet = doc.getElementsByTagName('servlet')
9
10 #Get the tag
11 dictservlet = {}
12 dictmapping = {}
13 #Get all
servlet names
and associated class
14 for a in servlet:
15 b = a.getElementsByTagName
('servlet-name')
16 c = a.getElementsByTagName
('servlet-class')
17 for k in b:
18 for h in c:
19 dictservlet [k.firstChild.data] = h.firstChild.data
20
21 #Get all servlet names and associated URL
patterns
22 for a in mapping:
23 b =
a.getElementsByTagName('servlet-name')
24 c = a.getElementsByTagName
('url-pattern')
25 for k in b:
26 for h in c:
27
dictmapping [h.firstChild.data] = k.firstChild.data
28
29 print "\n\n The dynamic servlet mappings are "
30 print "\n\nServlets are "
31 for i in dictservlet.keys(): print i ," = ",
dictservlet[i]
32 print "\n\nServlet mappings are "
33 for i in dictmapping.keys(): print i ," = ",
dictmapping[i]
When executing this code in jython (without PyXML), an exception was reported as shown below.
C:\>Jython XMLParse.py
Traceback (innermost last):
File "XMLParse.py", line 4, in ?
File "C:\jython-2.1\Lib\xml\dom\minidom.py", line 908, in parse
File "C:\jython-2.1\Lib\xml\dom\minidom.py", line 900, in _doparse
File "C:\jython-2.1\Lib\xml\dom\pulldom.py", line 251, in getEvent
AttributeError: feed
The exception thrown is due to the module pulldom.py. In this case the pulldom.py module from the latest stable Python version (2.3) is replaced in the Jython library module and then executed. (i.e replace the < PYTHON_HOME>/lib/xml/dom/pulldom.py in <JYTHON_HOME>/lib/xml/dom/pulldom.py) . This solved the problem and the above code worked.
The other thing which I experimented is to make the latest PyXML module to work with Jython in executing the above code. To do this, download the PyXML source and from the PyXML source copy the contents of the xml directory and replace it with that of the Jython 2.1 xml module.
C:\>jython xmlparse.py
Traceback (innermost last):
File "xmlparse.py", line 4, in ?
File
"C:\jython-2.1\Lib\xml\dom\minidom.py",
line 1907, in parse
ImportError:
cannot import name expatbuilder
Since expat parser is not available in jython, the line, which throws the
exception in minidom.py, the code in that line in minidom.py should be changed.
def parse(file,
parser=None, bufsize=None):
"""Parse a file into a DOM by filename or file
object."""
if parser is None
and not bufsize:
from
xml.dom
import expatbuilder
return
expatbuilder.parse(file)
else:
from xml.dom import pulldom
return
_do_pulldom_parse(pulldom.parse, (file,),
{'parser': parser, 'bufsize': bufsize})
def parseString(string,parser=None):
"""Parse a file into a DOM from a
string."""
if parser is
None:
from
xml.dom import expatbuilder
return
expatbuilder.parseString(string)
else:
from
xml.dom
import pulldom
return
_do_pulldom_parse(pulldom.parseString, (string,),
{'parser': parser})
Change it to
def parse(file,
parser=None, bufsize=None):
"""Parse a file into a DOM by filename or file
object."""
if parser is None
and not bufsize:
from
xml.dom
import pulldom
return
_do_pulldom_parse(pulldom.parse, (file,),
{'parser':
parser, 'bufsize': bufsize})
After making this modification, the subsequent exception thrown was
C:\>jython xmlparse.py
Traceback (innermost
last):
File
"xmlparse.py", line 4, in ?
File
"C:\jython-2.1\Lib\xml\dom\minidom.py", line 1908, in parse
File
"C:\jython-2.1\Lib\xml\dom\minidom.py", line 1898, in
_do_pulldom_parse
File
"C:\jython-2.1\Lib\xml\dom\pulldom.py", line 338, in parse
File
"C:\jython-2.1\Lib\xml\sax\sax2exts.py", line 37, in make_parser
File
"C:\jython-2.1\Lib\xml\sax\saxexts.py", line 69, in make_parser
File
"C:\jython-2.1\Lib\xml\sax\saxexts.py", line 37, in _create_parser
File
"C:\jython-2.1\Lib\xml\sax\drivers2\drv_xmlproc.py", line 9, in ?
ImportError: cannot import name xmlproc
After a careful analysis of the PyXML module and the python module it uses, it was found that the cause of the exception was due to the absence of some python (2.3) modules in jython.
Now I used the python 2.3 modules
Urlib2.py
Dis.py
Inspect.py
Opcode.py
In the Jython library and finally the code executed in Jython!
Note:
While replacing the inspect.py module from Python 2.3 to Jython, make sure
that you replace the // operator in inspect.py module since jython 2.1 does not
support // operator. Instead modify that operator in inspect.py as follows.
start = lineno - 1 - context//2
to
start = line - 1 - int(math.floor(context/2))
In short, many python libraries can be made to work with Jython with little tweaking, to take the full advantage
of Java Implementation of python.