Wednesday, March 02, 2005
xmllint --shell in Python
After looking at xmllint tool in linux and giving a small introductory talk on it I came to decision to start of its implementation in python that can serve as basic introduction to xml handling in python. For this I used minidom module of python's xml.dom library which is pretty simple to understand for the starters. The program I have desgined will implement very few option of xmllint --shell. This version of python implementation targets python programmer who is unfamiliar with the minidom module of python.
xmlsh.py code follows:
View xmlsh.pyHide xmlsh.py
""" A basic implementation of (xmllint --shell)
Author: Prasad.A
"""
import sys
from xml.dom import minidom
from readline import *
class xmlsh(object):
"""The base class which holds the xml document."""
def __init__(self,xmlfile):
self.filename=xmlfile
self.__loadFile()
def __loadFile(self):
self.xmlDoc = minidom.parse(self.filename)
# Get the element from the dom (currentElement)
def __getElement(self,elemname,currentElement,index=0):
if(elemname==""): return (currentElement,1)
elementList = currentElement.getElementsByTagName(elemname)
return (elementList[index],len(elementList))
# Handler for cat command
def __catHandler(self,path,currentElement):
if(path[0]=="/"): #absolute path is used
element=self.xmlDoc
path=path[1:]
else: # relative path is used
element=currentElement
parentElement = None
count=-1
pathSplit = path.split("/")
if(len(pathSplit)>1):
for elemname in pathSplit[:len(pathSplit)]:
parentElement = element
(element,count) = self.__getElement(elemname,element)
else:
(element,count) = self.__getElement(pathSplit[-1],element)
if(count != -1 and count > 1):
for index in range(count):
(element,count) = self.__getElement(pathSplit[-1],parentElement,index)
print element.toxml()
# Display the help
def __printHelp(self):
print """
The following commands are supported:
cd [xpath]: Change to the given node.
cat [xpath]: See the content.
pwd : Current position in the document.
help : Displays this help.
This implementation will support only very basic xpath.
"""
# Wrapper for displaying help
def help(self):
self.__printHelp()
# Main loop to run the program
def run(self):
print "Type bye or quit to terminate."
stop = False
prompt = "/"
self.currentElement = self.xmlDoc
while(stop!=True):
try:
# Accept the input
inputLine = raw_input("%s%s " % (prompt,">"))
# If the input is empty or newline do nothing
if(inputLine == "" or inputLine == "\n"): continue
# Split the input
inputSplit = inputLine.split()
# Assume the first element of split is command
command = inputSplit[0]
# Adjust the arguments passed
arguments=None
if(len(inputSplit) > 1): arguments = "".join(inputSplit[1:])
# Command is not still handled
commandHandled =False
# Handle "bye" or "quit" command
if(command=="bye" or command=="quit"):
commandHandled=True
stop=True
continue
# Handle "cd" command
if(command=="cd"):
commandHandled=True
inputArg=arguments
if(arguments[0]=="/"):
arguments=arguments[1:]
self.currentElement=self.xmlDoc
element=self.currentElement
parentElement=None
count = -1
pathSplit=arguments.split("/")
if(len(pathSplit) > 1):
for elemname in pathSplit[:len(pathSplit)-1]:
parentElement=element
(element,count)=self.__getElement(elemname,element)
parentElement=element
(element,count)=self.__getElement(pathSplit[-1],element)
whichOne=-1
if(count!=-1 and count>1):
print count, " elements of ", pathSplit[-1]," is present."
whichOne = raw_input("Specify the index to select: ")
if whichOne != " ":
whichOne = int(whichOne)
(element,count) = self.__getElement(pathSplit[-1],parentElement,whichOne-1)
else:
element=parentElement
self.currentElement=element
separator="/"
if(inputArg[0]=="/"):
prompt=""
separator=""
elif(prompt=="/"):
prompt=""
separator="/"
if(whichOne==-1): prompt="%s%s%s" % (prompt,separator,inputArg)
else: prompt="%s%s%s[%d]" % (prompt,separator,inputArg,whichOne)
if(self.currentElement==None):
stop=True
continue
# Handle "cat" command
if(command=="cat"):
commandHandled = True
if(arguments != None): self.__catHandler(arguments,self.currentElement)
else: print self.currentElement.toxml()
# Handle "pwd" command
if(command=="pwd"):
commandHandled = True
print prompt
# Handle "help" command
if(command=="help"):
commandHandled = True
self.__printHelp()
if(commandHandled==False):
print "Unknown Command:"
print self.__printHelp()
except Exception, ex:
print "Exception: ",ex
# Start the shell
if(len(sys.argv)>1):
ob=xmlsh(sys.argv[1])
print "Object created...function run() will be invoked..."
ob.help()
ob.run()
else:
print "Usage: python", sys.argv[0], "xmlfilename"
A small example follows that will explain the usage of this tool.
View UsageHide Usage
XML File: xmlsh.xml
<?xml version="1.0"?>
<root>
<element>
<item>
<title>Title of item1</title>
<description>Description of item1</description>
</item>
<item>
<title>Title of item2</title>
<description>Description of item2</description>
</item>
<item>
<title>Title of item3</title>
<description>Description of item3</description>
</item>
<item>
<title>Title of item4</title>
<description>Description of item4</description>
</item>
</element>
</root>
Usage: python xmlsh.py xmlsh.xml
/> cat
/> cd root
/root> cd /root/element
/root/element> cat
/root/element> cd item
[Specify the index: 1]
/root/element/item[1]> cat
/root/element/item[1]> cd /root/element
/root/element> pwd
/root/element> cd item
[Specify the index: 2]
/root/element/item[2]> cd /
/> bye
# posted by Prasad.A : 10:59 PM