ProjectPythonSourceForge
Welcome
Introduction
Suitability
Future Plans
Setup
Downloading XMLObject
Installing XMLObject
XMLObjApp
The XMLObjApp Application
Classes
Special Attributes
XML Attributes
Child Tags
File Menu
Miscellaneous Operation Notes
Unicode and ASCII Strings
Manually Editing Your Parser
Outputting XML
XMLObject
XMLObject -- XML to Object Conversion
Stack -- Tracks the Document Hierarchy
All Docs on One Page

Outputting XML

Throughout this document, I've been talking about parsing XML documents into Python objects. I have yet to mention using Python objects to output XML.

The reason for this rather glaring omission is that neither XMLObject nor XMLObjApp contribute to the process. I've tried to figure out a way to automate code generation to output XML, but it is much harder to come up with a generic solution than you might suppose.

So instead of creating some code destined to be eternally buggy, I've decided to reserve this portion of the documentation to illustrate how you can write your own code members to output XML.

Let's parse our earlier addressbook example with a simpler parser.

Example 4.3. Addressbook and Simpler Parser

<AddressBook>
    <User ID="1">
        <Nickname>Gre7g</Nickname>
        <Email>gre7g@wolfhome.com</Email>
        <Address>2235 West Sunnyside Dr.</Address>
        <City>Cedar City</City>
        <State>MT</State>
        <Zip>74720</Zip>
    </User>
    <User ID="2">
        <Nickname>Jimbo</Nickname>
        <BestFriend ID="1" />
        <Email>jimbo@hotmail.com</Email>
        <Address>115 North Main</Address>
        <Address>Apartment #309</Address>
        <City>Columbia</City>
        <State>MO</State>
        <Zip>65201</Zip>
    </User>
</AddressBook>
# vvv  Generated code, do not modify  vvv
import XMLObject
# ^^^  Generated code, do not modify  ^^^

# vvv  Generated code, do not modify  vvv
class Text:
    ChildSpec = XMLObject.ChildClass({"#PCDATA": XMLObject.PCDATAChild("Strip",
         "Text")}, "#PCDATA")
    def __init__(self, XMLStack=XMLObject.Stack()):
        self.Text = ""
# ^^^  Generated code, do not modify  ^^^

# vvv  Generated code, do not modify  vvv
class BestFriend:
    ChildSpec = XMLObject.ChildClass({}, "")
    def __init__(self, ID, XMLStack=XMLObject.Stack()):
        self.ID = XMLStack.ReferenceID(ID, XMLStack)
# ^^^  Generated code, do not modify  ^^^

# vvv  Generated code, do not modify  vvv
class User:
    ChildSpec = XMLObject.ChildClass({"Nickname": XMLObject.StdChild(Text,
        "Nickname", "Single", Reduce="Text"), "Email": XMLObject.StdChild(
        Text, "Email", "Single", Reduce="Text"), "Address": XMLObject.StdChild(
        Text, "Address", "List", Reduce="Text"), "City": XMLObject.StdChild(
        Text, "City", "Single", Reduce="Text"), "State": XMLObject.StdChild(
        Text, "State", "Single", Reduce="Text"), "Zip": XMLObject.StdChild(
        Text, "Zip", "Single", Reduce="Text"), "BestFriend": XMLObject.StdChild
        (BestFriend, "BestFriend", "Single", Reduce="ID")},
        "(<Nickname>)?(<BestFriend>)?(<Email>)?(<Address>)*(<City>)?(<State>)?(<Zip>)?"
        )
    def __init__(self, ID, XMLStack=XMLObject.Stack()):
        self.ID = XMLStack.UniqueID("User", ID, self, XMLStack)
        self.Nickname = ""
        self.Email = ""
        self.Address = []
        self.City = ""
        self.State = ""
        self.Zip = ""
        self.BestFriend = ""
# ^^^  Generated code, do not modify  ^^^

# vvv  Generated code, do not modify  vvv
class AddressBook:
    ChildSpec = XMLObject.ChildClass({"User": XMLObject.StdChild(User, "User",
        "Dict", Key="ID")}, "(<User>)*")
    def __init__(self, XMLStack=XMLObject.Stack()):
        self.User = {}
# ^^^  Generated code, do not modify  ^^^

To output XML, we will need to add a member function to both the AddressBook and User classes. There isn't much point in adding code to either the BestFriend or Text classes because all instances of these classes will be reduced. There will not actually be any instances of these classes in the final, parsed object hierarchy.

You can use most any member function name to output XML, but I prefer __repr__:

Example 4.4. AddressBook Parser with __repr__ Additions

# vvv  Generated code, do not modify  vvv
import XMLObject
# ^^^  Generated code, do not modify  ^^^

# vvv  Generated code, do not modify  vvv
class Text:
    ChildSpec = XMLObject.ChildClass({"#PCDATA": XMLObject.PCDATAChild("Strip",
         "Text")}, "#PCDATA")
    def __init__(self, XMLStack=XMLObject.Stack()):
        self.Text = ""
# ^^^  Generated code, do not modify  ^^^

# vvv  Generated code, do not modify  vvv
class BestFriend:
    ChildSpec = XMLObject.ChildClass({}, "")
    def __init__(self, ID, XMLStack=XMLObject.Stack()):
        self.ID = XMLStack.ReferenceID(ID, XMLStack)
# ^^^  Generated code, do not modify  ^^^

# vvv  Generated code, do not modify  vvv
class User:
    ChildSpec = XMLObject.ChildClass({"Nickname": XMLObject.StdChild(Text,
        "Nickname", "Single", Reduce="Text"), "Email": XMLObject.StdChild(
        Text, "Email", "Single", Reduce="Text"), "Address": XMLObject.StdChild(
        Text, "Address", "List", Reduce="Text"), "City": XMLObject.StdChild(
        Text, "City", "Single", Reduce="Text"), "State": XMLObject.StdChild(
        Text, "State", "Single", Reduce="Text"), "Zip": XMLObject.StdChild(
        Text, "Zip", "Single", Reduce="Text"), "BestFriend": XMLObject.StdChild
        (BestFriend, "BestFriend", "Single", Reduce="ID")},
        "(<Nickname>)?(<BestFriend>)?(<Email>)?(<Address>)*(<City>)?(<State>)?(<Zip>)?"
        )
    def __init__(self, ID, XMLStack=XMLObject.Stack()):
        self.ID = XMLStack.UniqueID("User", ID, self, XMLStack)
        self.Nickname = ""
        self.Email = ""
        self.Address = []
        self.City = ""
        self.State = ""
        self.Zip = ""
        self.BestFriend = ""
# ^^^  Generated code, do not modify  ^^^

    def __repr__(self):
        RetVal = '<User ID="%s">' % self.ID
        if self.Nickname:   RetVal += "<Nickname>%s</Nickname>" % self.Nickname
        if self.BestFriend: RetVal += '<BestFriend ID="%s" />' % self.Nickname
        if self.Email:      RetVal += "<Email>%s</Email>" % self.Email
        for Address in self.Address:
                            RetVal += "<Address>%s</Address>" % Address
        if self.City:       RetVal += "<City>%s</City>" % self.City
        if self.State:      RetVal += "<State>%s</State>" % self.State
        if self.Zip:        RetVal += "<Zip>%s</Zip>" % self.Zip
        return RetVal + "</User>"

# vvv  Generated code, do not modify  vvv
class AddressBook:
    ChildSpec = XMLObject.ChildClass({"User": XMLObject.StdChild(User, "User",
        "Dict", Key="ID")}, "(<User>)*")
    def __init__(self, XMLStack=XMLObject.Stack()):
        self.User = {}
# ^^^  Generated code, do not modify  ^^^

    def __repr__(self):
        RetVal = "<AddressBook>"
        for User in self.User.values():
            RetVal += repr(User)
        return RetVal + "</AddressBook>"
>>> import XMLObject, AddressBook2
>>> Book = XMLObject.Parse("AddressBook.xml", "AddressBook",
...     AddressBook2.AddressBook)
>>> repr(Book)
'<AddressBook><User ID="1"><Nickname>Gre7g</Nickname><Email>gre7g@wolfhome.com<
/Email><Address>2235 West Sunnyside Dr.</Address><City>Cedar City</City><State>
MT</State><Zip>74720</Zip></User><User ID="2"><Nickname>Jimbo</Nickname><BestFr
iend ID="Jimbo" /><Email>jimbo@hotmail.com</Email><Address>115 North Main</Addr
ess><Address>Apartment #309</Address><City>Columbia</City><State>MO</State><Zip
>65201</Zip></User></AddressBook>'