xmlobj: XML-based record object

Previous: xml: XMLAPI data structure ] [ Top:  ] [ Next: repository: the system ]

The xmlobj class builds on the xml class by defining a way to access named values within an XML structure. Note that the idea here is to be as DTD-agnostic as possible, which flies entirely in the face of all XML common wisdom I've read about. But the wftk should be able to work with XML documents generated by diverse tools, so I do things this way.

A field, as far as the xmlobj library is concerned, is either a field element with an "id" attribute of the name in question, or it can be an element named appropriately. Thus if I want the "address" value of a record, it may be stored as <field id="address">value</field> or as <address>value</address>. Later, this addressing scheme will include the ability to refer to multiple values for a single field name, allowing us to work with very general XML structures (and incidentally also allowing us a simple way to store and access LDAP data), but for the time being only a single value may be returned for a given name.

The xmlobj object overrides the handling of indexing from the xml object (which access attributes) and instead uses the record's named fields as value holders, which is not only very appropriate, it is extremely, utterly bowling me over and making me wonder where OO has been all my life. Oh, yeah, I was waiting for the right moment.

May 13, 2006: So here I am, actually doing something with all this. I'm adding a neat little stub implementation of a command-line parser here, in the hopes that I'll eventually move it into C and do a better job with it. The idea is that I give the cmdline parser a (string) command line, and it figures out quotes and such, and returns a nicely parsed action structure with proper parameters and such. That could be arbitrarily complex, of course, so to start with I'm just using a simple split and going from there.
 
class xmlobj(xml):
   """Implements a record object on top of the XML object.  Primarily this has to do with
      the organization of field values, which are normally <field]] attributes (but needn't be.)
   """
   def __init__ (self, defn=None, str=None, xml=None, cmd=None):
      """Create XML object from optional string input"""
      self._list = defn
      try:
         self._xml = xml._xml
      except:
         self._xml = xml

      if cmd:
         str = None
         self.parse_cmdline (cmd)

      if str:
         try:
            self.parse (str)
         except ParseError, message:
            raise ParseError, message

   # --------------------------------------------------------------
   # Getting and setting the value of the list definition.
   # --------------------------------------------------------------
   def define (self, list):
      self._list = list
   def defn (self):
      return self._list

   # --------------------------------------------------------------
   # Field reading.
   # --------------------------------------------------------------
   def __getitem__ (self, key):
      if self._xml == None: return ""
      return xmlapi.xmlobj_get (self._xml, self._list, key)
   def get (self, field):
      if self._xml == None: return ""
      return xmlapi.xmlobj_get (self._xml, self._list, key)
   def key (self):
      if self._xml == None: return ""
      return xmlapi.xmlobj_getkey (self._xml, self._list)

   # --------------------------------------------------------------
   # Field writing.  Note that we can choose element or field storage.
   # --------------------------------------------------------------
   def __setitem__ (self, key, value):
      if self._xml == None: self._xml = xmlapi.xml_create ("record")
      try:
         xmlapi.xmlobj_set (self._xml, self._list, key, value)
      except:
         xmlapi.xmlobj_set (self._xml, self._list, key, `value`)

   def set (self, key, value):
      if self._xml == None: self._xml = xmlapi.xml_create ("record")
      try:
         xmlapi.xmlobj_set (self._xml, self._list, key, value)
      except:
         xmlapi.xmlobj_set (self._xml, self._list, key, `value`)

   def set_elem (self, key, value):
      if self._xml == None: self._xml = xmlapi.xml_create ("record")
      xmlapi.xmlobj_set_elem (self._xml, self._list, key, value)

   # -------------------------------------------------------------
   # Formatting a record into a string using the square-bracket notation
   # -------------------------------------------------------------
   def format (self, format):
      if self._xml == None: self._xml = xmlapi.xml_create ("record")
      return xmlapi.xmlobj_format (self._xml, self._list, format)

   def parse_cmdline (self, str):    # TODO: move this into C!  And make it not suck!
      cmdlist = split(str)
      cmd = cmdlist[0]
      args = []
      curarg = ''
      for a in cmdlist[1:]:
         if curarg != '':
            curarg = curarg + ' ' + a
            if a[-1] == '"':
               args.append (curarg[:-1])
               curarg = ''
         else:
            if a[0] == '"':
               curarg = a[1:]
            else:
               args.append (a)
      if curarg != '': args.append (curarg)
               
      self.parse ('<action command="%s" parms="%d"/>' % (cmd, len(args)))
      for parm in args:
         p = xmlapi.xml_create('parm')
         xmlapi.xml_append(p, xmlapi.xml_createtext(parm))
         xmlapi.xml_append_pretty (self._xml, p)

Previous: xml: XMLAPI data structure ] [ Top:  ] [ Next: repository: the system ]


This code and documentation are released under the terms of the GNU license. They are additionally copyright (c) 2001, Vivtek. All rights reserved except those explicitly granted under the terms of the GNU license.