Being that I only use XML on occasion for some very basic features, I find myself having to re-learn the appropriate syntax every time. After doing this for the n-th time, I finally decided to wrap this syntax in something that's much more intuitive (to me, at least). The main goal is to make this as simple an API as possible, at the cost of some features.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | from xml.dom import minidom
class XmlNode:
"""An XML node represents a single field in an XML document."""
def __init__(self, domElement):
"""Construct an XML node from a DOM element."""
self.elem = domElement
@classmethod
def makeRoot(cls, xmlFileName):
return cls(minidom.parse(xmlFileName))
def getData(self):
"""Extract data from a DOM node."""
for child in self.elem.childNodes:
if child.nodeType == child.TEXT_NODE:
return str(child.data)
return None
def getAttributeValue(self, name):
"""Returns the value of the attribute having the specified name."""
return str(self.elem.attributes[name].value)
def getChild(self, tag):
"""Returns the first child node having the specified tag."""
return XmlNode(self.elem.getElementsByTagName(tag)[0])
def getChildren(self, tag):
"""Returns a list of child nodes having the specified tag."""
return [XmlNode(x) for x in self.elem.getElementsByTagName(tag)]
|
For the purpose of clarity, the following terminology is used:
<RootNode>
<ChildNode1 Attribute="AttributeValue">Data</ChildNode1>
<ChildNode2 Attribute="AttributeValue">Data</ChildNode2>
</RootNode>
The assumption is that Joe Programmer knows what the XML schema looks like and is only interested in a mechanism by which he can retrieve the following items:
- Data
- Attribute's value
- Children nodes (which can then perform #1 and #2 again)
These assumptions allow us to keep things simple and clean by returning all values as strings and forwarding all exceptions directly from the minidom module.
The basic idea here is that an XmlNode
is an object that represents a node (or "field") in the XML tree. Once the root node is attained via makeRoot
, the tree can be traversed by having each node return sub-nodes as needed. For example:
root = XmlNode.makeRoot(my_schema.xml)
sender = root.getChild('from')
recipients = root.getChildren('to')
print 'From:', sender.getData()
print 'To:'
for recipient in recipients:
print '..', recipient.getData()
You can probably appreciate the spirit of this interface and how it can be extended to accommodate other features provided by xml.dom. I stuck this code in a file called ezxml.py, which I then include into my various projects.