modules/xmpp/simplexml.py
author Mikael Berthe <mikael@lilotux.net>
Tue, 01 May 2007 12:26:35 +0200
changeset 0 93b25987d3e5
permissions -rw-r--r--
Initial Mercurial repository Imported from Neutron' svn, with a few changes
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
0
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
     1
##   simplexml.py based on Mattew Allum's xmlstream.py
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
     2
##
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
     3
##   Copyright (C) 2003-2005 Alexey "Snake" Nezhdanov
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
     4
##
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
     5
##   This program is free software; you can redistribute it and/or modify
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
     6
##   it under the terms of the GNU General Public License as published by
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
     7
##   the Free Software Foundation; either version 2, or (at your option)
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
     8
##   any later version.
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
     9
##
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    10
##   This program is distributed in the hope that it will be useful,
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    11
##   but WITHOUT ANY WARRANTY; without even the implied warranty of
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    12
##   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    13
##   GNU General Public License for more details.
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    14
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    15
# $Id: simplexml.py,v 1.30 2006/06/03 12:22:34 normanr Exp $
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    16
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    17
"""Simplexml module provides xmpppy library with all needed tools to handle XML nodes and XML streams.
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    18
I'm personally using it in many other separate projects. It is designed to be as standalone as possible."""
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    19
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    20
import xml.parsers.expat
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    21
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    22
def XMLescape(txt):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    23
    """Returns provided string with symbols & < > " replaced by their respective XML entities."""
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    24
    return txt.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;").replace('"', "&quot;")
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    25
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    26
ENCODING='utf-8'
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    27
def ustr(what):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    28
    """Converts object "what" to unicode string using it's own __str__ method if accessible or unicode method otherwise."""
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    29
    if type(what) == type(u''): return what
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    30
    try: r=what.__str__()
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    31
    except AttributeError: r=str(what)
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    32
    if type(r)<>type(u''): return unicode(r,ENCODING)
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    33
    return r
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    34
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    35
class Node:
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    36
    """ Node class describes syntax of separate XML Node. It have a constructor that permits node creation
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    37
        from set of "namespace name", attributes and payload of text strings and other nodes.
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    38
        It does not natively support building node from text string and uses NodeBuilder class for that purpose.
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    39
        After creation node can be mangled in many ways so it can be completely changed.
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    40
        Also node can be serialised into string in one of two modes: default (where the textual representation
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    41
        of node describes it exactly) and "fancy" - with whitespace added to make indentation and thus make
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    42
        result more readable by human.
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    43
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    44
        Node class have attribute FORCE_NODE_RECREATION that is defaults to False thus enabling fast node
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    45
        replication from the some other node. The drawback of the fast way is that new node shares some
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    46
        info with the "original" node that is changing the one node may influence the other. Though it is
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    47
        rarely needed (in xmpppy it is never needed at all since I'm usually never using original node after
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    48
        replication (and using replication only to move upwards on the classes tree).
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    49
    """
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    50
    FORCE_NODE_RECREATION=0
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    51
    def __init__(self, tag=None, attrs={}, payload=[], parent=None, node=None):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    52
        """ Takes "tag" argument as the name of node (prepended by namespace, if needed and separated from it
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    53
            by a space), attrs dictionary as the set of arguments, payload list as the set of textual strings
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    54
            and child nodes that this node carries within itself and "parent" argument that is another node
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    55
            that this one will be the child of. Also the __init__ can be provided with "node" argument that is 
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    56
            either a text string containing exactly one node or another Node instance to begin with. If both
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    57
            "node" and other arguments is provided then the node initially created as replica of "node"
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    58
            provided and then modified to be compliant with other arguments."""
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    59
        if node:
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    60
            if self.FORCE_NODE_RECREATION and type(node)==type(self): node=str(node)
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    61
            if type(node)<>type(self): node=NodeBuilder(node,self)
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    62
            else:
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    63
                self.name,self.namespace,self.attrs,self.data,self.kids,self.parent = node.name,node.namespace,{},[],[],node.parent
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    64
                for key  in node.attrs.keys(): self.attrs[key]=node.attrs[key]
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    65
                for data in node.data: self.data.append(data)
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    66
                for kid  in node.kids: self.kids.append(kid)
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    67
        else: self.name,self.namespace,self.attrs,self.data,self.kids,self.parent = 'tag','',{},[],[],None
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    68
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    69
        if tag: self.namespace, self.name = ([self.namespace]+tag.split())[-2:]
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    70
        if parent: self.parent = parent
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    71
        if self.parent and not self.namespace: self.namespace=self.parent.namespace
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    72
        for attr in attrs.keys():
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    73
            self.attrs[attr]=attrs[attr]
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    74
        if type(payload) in (type(''),type(u'')): payload=[payload]
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    75
        for i in payload:
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    76
            if type(i)==type(self): self.addChild(node=i)
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    77
            else: self.data.append(ustr(i))
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    78
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    79
    def __str__(self,fancy=0):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    80
        """ Method used to dump node into textual representation.
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    81
            if "fancy" argument is set to True produces indented output for readability."""
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    82
        s = (fancy-1) * 2 * ' ' + "<" + self.name
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    83
        if self.namespace:
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    84
            if not self.parent or self.parent.namespace!=self.namespace:
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    85
                s = s + ' xmlns="%s"'%self.namespace
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    86
        for key in self.attrs.keys():
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    87
            val = ustr(self.attrs[key])
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    88
            s = s + ' %s="%s"' % ( key, XMLescape(val) )
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    89
        s = s + ">"
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    90
        cnt = 0 
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    91
        if self.kids:
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    92
            if fancy: s = s + "\n"
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    93
            for a in self.kids:
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    94
                if not fancy and (len(self.data)-1)>=cnt: s=s+XMLescape(self.data[cnt])
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    95
                elif (len(self.data)-1)>=cnt: s=s+XMLescape(self.data[cnt].strip())
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    96
                s = s + a.__str__(fancy and fancy+1)
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    97
                cnt=cnt+1
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    98
        if not fancy and (len(self.data)-1) >= cnt: s = s + XMLescape(self.data[cnt])
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
    99
        elif (len(self.data)-1) >= cnt: s = s + XMLescape(self.data[cnt].strip())
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   100
        if not self.kids and s[-1:]=='>':
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   101
            s=s[:-1]+' />'
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   102
            if fancy: s = s + "\n"
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   103
        else:
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   104
            if fancy and not self.data: s = s + (fancy-1) * 2 * ' '
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   105
            s = s + "</" + self.name + ">"
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   106
            if fancy: s = s + "\n"
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   107
        return s
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   108
    def getCDATA(self):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   109
        """ Serialise node, dropping all tags and leaving CDATA intact.
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   110
            That is effectively kills all formatiing, leaving only text were contained in XML.
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   111
        """
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   112
        s =""
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   113
        cnt = 0
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   114
        if self.kids:
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   115
            for a in self.kids:
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   116
                s=s+self.data[cnt]
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   117
                s = s + mystr(a)
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   118
                cnt=cnt+1
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   119
        if (len(self.data)-1) >= cnt: s = s + self.data[cnt]
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   120
        return s
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   121
    def addChild(self, name=None, attrs={}, payload=[], namespace=None, node=None):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   122
        """ If "node" argument is provided, adds it as child node. Else creates new node from
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   123
            the other arguments' values and adds it as well."""
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   124
        if attrs.has_key('xmlns'):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   125
            raise AttributeError("Use namespace=x instead of attrs={'xmlns':x}")
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   126
        if namespace: name=namespace+' '+name
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   127
        if node:
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   128
            newnode=node
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   129
            node.parent = self
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   130
        else: newnode=Node(tag=name, parent=self, attrs=attrs, payload=payload)
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   131
        self.kids.append(newnode)
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   132
        return newnode
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   133
    def addData(self, data):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   134
        """ Adds some CDATA to node. """
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   135
        self.data.append(ustr(data))
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   136
    def clearData(self):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   137
        """ Removes all CDATA from the node. """
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   138
        self.data=[]
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   139
    def delAttr(self, key):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   140
        """ Deletes an attribute "key" """
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   141
        del self.attrs[key]
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   142
    def delChild(self, node, attrs={}):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   143
        """ Deletes the "node" from the node's childs list, if "node" is an instance.
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   144
            Else deletes the first node that have specified name and (optionally) attributes. """
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   145
        if type(node)<>type(self): node=self.getTag(node,attrs)
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   146
        self.kids.remove(node)
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   147
        return node
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   148
    def getAttrs(self):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   149
        """ Returns all node's attributes as dictionary. """
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   150
        return self.attrs
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   151
    def getAttr(self, key):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   152
        """ Returns value of specified attribute. """
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   153
        try: return self.attrs[key]
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   154
        except: return None
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   155
    def getChildren(self):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   156
        """ Returns all node's child nodes as list. """
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   157
        return self.kids
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   158
    def getData(self):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   159
        """ Returns all node CDATA as string (concatenated). """
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   160
        return ''.join(self.data)
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   161
    def getName(self):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   162
        """ Returns the name of node """
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   163
        return self.name
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   164
    def getNamespace(self):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   165
        """ Returns the namespace of node """
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   166
        return self.namespace
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   167
    def getParent(self):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   168
        """ Returns the parent of node (if present). """
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   169
        return self.parent
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   170
    def getPayload(self):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   171
        """ Return the payload of node i.e. list of child nodes and CDATA entries.
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   172
            F.e. for "<node>text1<nodea/><nodeb/> text2</node>" will be returned list:
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   173
            ['text1', <nodea instance>, <nodeb instance>, ' text2']. """
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   174
        ret=[]
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   175
        for i in range(len(self.kids)+len(self.data)+1):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   176
            try:
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   177
                if self.data[i]: ret.append(self.data[i])
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   178
            except IndexError: pass
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   179
            try: ret.append(self.kids[i])
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   180
            except IndexError: pass
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   181
        return ret
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   182
    def getTag(self, name, attrs={}, namespace=None): 
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   183
        """ Filters all child nodes using specified arguments as filter.
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   184
            Returns the first found or None if not found. """
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   185
        return self.getTags(name, attrs, namespace, one=1)
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   186
    def getTagAttr(self,tag,attr):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   187
        """ Returns attribute value of the child with specified name (or None if no such attribute)."""
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   188
        try: return self.getTag(tag).attrs[attr]
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   189
        except: return None
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   190
    def getTagData(self,tag):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   191
        """ Returns cocatenated CDATA of the child with specified name."""
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   192
        try: return self.getTag(tag).getData()
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   193
        except: return None
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   194
    def getTags(self, name, attrs={}, namespace=None, one=0):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   195
        """ Filters all child nodes using specified arguments as filter.
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   196
            Returns the list of nodes found. """
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   197
        nodes=[]
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   198
        for node in self.kids:
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   199
            if namespace and namespace<>node.getNamespace(): continue
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   200
            if node.getName() == name:
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   201
                for key in attrs.keys():
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   202
                   if not node.attrs.has_key(key) or node.attrs[key]<>attrs[key]: break
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   203
                else: nodes.append(node)
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   204
            if one and nodes: return nodes[0]
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   205
        if not one: return nodes
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   206
    def setAttr(self, key, val):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   207
        """ Sets attribute "key" with the value "val". """
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   208
        self.attrs[key]=val
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   209
    def setData(self, data):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   210
        """ Sets node's CDATA to provided string. Resets all previous CDATA!"""
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   211
        self.data=[ustr(data)]
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   212
    def setName(self,val):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   213
        """ Changes the node name. """
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   214
        self.name = val
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   215
    def setNamespace(self, namespace):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   216
        """ Changes the node namespace. """
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   217
        self.namespace=namespace
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   218
    def setParent(self, node): 
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   219
        """ Sets node's parent to "node". WARNING: do not checks if the parent already present 
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   220
            and not removes the node from the list of childs of previous parent. """
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   221
        self.parent = node
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   222
    def setPayload(self,payload,add=0):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   223
        """ Sets node payload according to the list specified. WARNING: completely replaces all node's
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   224
            previous content. If you wish just to add child or CDATA - use addData or addChild methods. """
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   225
        if type(payload) in (type(''),type(u'')): payload=[payload]
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   226
        if add: self.kids+=payload
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   227
        else: self.kids=payload
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   228
    def setTag(self, name, attrs={}, namespace=None):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   229
        """ Same as getTag but if the node with specified namespace/attributes not found, creates such
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   230
            node and returns it. """
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   231
        node=self.getTags(name, attrs, namespace=namespace, one=1)
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   232
        if node: return node
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   233
        else: return self.addChild(name, attrs, namespace=namespace)
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   234
    def setTagAttr(self,tag,attr,val):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   235
        """ Creates new node (if not already present) with name "tag"
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   236
            and sets it's attribute "attr" to value "val". """
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   237
        try: self.getTag(tag).attrs[attr]=val
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   238
        except: self.addChild(tag,attrs={attr:val})
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   239
    def setTagData(self,tag,val,attrs={}):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   240
        """ Creates new node (if not already present) with name "tag" and (optionally) attributes "attrs"
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   241
            and sets it's CDATA to string "val". """
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   242
        try: self.getTag(tag,attrs).setData(ustr(val))
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   243
        except: self.addChild(tag,attrs,payload=[ustr(val)])
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   244
    def has_attr(self,key):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   245
        """ Checks if node have attribute "key"."""
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   246
        return self.attrs.has_key(key)
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   247
    def __getitem__(self,item):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   248
        """ Returns node's attribute "item" value. """
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   249
        return self.getAttr(item)
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   250
    def __setitem__(self,item,val):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   251
        """ Sets node's attribute "item" value. """
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   252
        return self.setAttr(item,val)
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   253
    def __delitem__(self,item):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   254
        """ Deletes node's attribute "item". """
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   255
        return self.delAttr(item,val)
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   256
    def __getattr__(self,attr):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   257
        """ Reduce memory usage caused by T/NT classes - use memory only when needed. """
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   258
        if attr=='T':
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   259
            self.T=T(self)
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   260
            return self.T
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   261
        if attr=='NT':
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   262
            self.NT=NT(self)
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   263
            return self.NT
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   264
        raise AttributeError
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   265
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   266
class T:
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   267
    """ Auxiliary class used to quick access to node's child nodes. """
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   268
    def __init__(self,node): self.__dict__['node']=node
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   269
    def __getattr__(self,attr): return self.node.getTag(attr)
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   270
    def __setattr__(self,attr,val):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   271
        if isinstance(val,Node): Node.__init__(self.node.setTag(attr),node=val)
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   272
        else: return self.node.setTagData(attr,val)
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   273
    def __delattr__(self,attr): return self.node.delChild(attr)
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   274
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   275
class NT(T):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   276
    """ Auxiliary class used to quick create node's child nodes. """
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   277
    def __getattr__(self,attr): return self.node.addChild(attr)
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   278
    def __setattr__(self,attr,val):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   279
        if isinstance(val,Node): self.node.addChild(attr,node=val)
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   280
        else: return self.node.addChild(attr,payload=[val])
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   281
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   282
DBG_NODEBUILDER = 'nodebuilder'
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   283
class NodeBuilder:
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   284
    """ Builds a Node class minidom from data parsed to it. This class used for two purposes:
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   285
        1. Creation an XML Node from a textual representation. F.e. reading a config file. See an XML2Node method.
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   286
        2. Handling an incoming XML stream. This is done by mangling 
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   287
           the __dispatch_depth parameter and redefining the dispatch method.
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   288
        You do not need to use this class directly if you do not designing your own XML handler."""
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   289
    def __init__(self,data=None,initial_node=None):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   290
        """ Takes two optional parameters: "data" and "initial_node".
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   291
            By default class initialised with empty Node class instance.
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   292
            Though, if "initial_node" is provided it used as "starting point".
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   293
            You can think about it as of "node upgrade".
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   294
            "data" (if provided) feeded to parser immidiatedly after instance init.
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   295
            """
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   296
        self.DEBUG(DBG_NODEBUILDER, "Preparing to handle incoming XML stream.", 'start')
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   297
        self._parser = xml.parsers.expat.ParserCreate(namespace_separator=' ')
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   298
        self._parser.StartElementHandler       = self.starttag
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   299
        self._parser.EndElementHandler         = self.endtag
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   300
        self._parser.CharacterDataHandler      = self.handle_data
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   301
        self._parser.StartNamespaceDeclHandler = self.handle_namespace_start
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   302
        self.Parse = self._parser.Parse
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   303
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   304
        self.__depth = 0
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   305
        self._dispatch_depth = 1
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   306
        self._document_attrs = None
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   307
        self._mini_dom=initial_node
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   308
        self.last_is_data = 1
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   309
        self._ptr=None
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   310
        self.namespaces={"http://www.w3.org/XML/1998/namespace":'xml:'}
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   311
        self.xmlns="http://www.w3.org/XML/1998/namespace"
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   312
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   313
        if data: self._parser.Parse(data,1)
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   314
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   315
    def destroy(self):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   316
        """ Method used to allow class instance to be garbage-collected. """
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   317
        self._parser.StartElementHandler       = None
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   318
        self._parser.EndElementHandler         = None
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   319
        self._parser.CharacterDataHandler      = None
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   320
        self._parser.StartNamespaceDeclHandler = None
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   321
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   322
    def starttag(self, tag, attrs):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   323
        """XML Parser callback. Used internally"""
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   324
        attlist=attrs.keys()       #
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   325
        for attr in attlist:       # FIXME: Crude hack. And it also slows down the whole library considerably.
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   326
            sp=attr.rfind(" ")     #
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   327
            if sp==-1: continue    #
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   328
            ns=attr[:sp]           #
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   329
            attrs[self.namespaces[ns]+attr[sp+1:]]=attrs[attr]
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   330
            del attrs[attr]        #
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   331
        self.__depth += 1
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   332
        self.DEBUG(DBG_NODEBUILDER, "DEPTH -> %i , tag -> %s, attrs -> %s" % (self.__depth, tag, `attrs`), 'down')
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   333
        if self.__depth == self._dispatch_depth:
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   334
            if not self._mini_dom : self._mini_dom = Node(tag=tag, attrs=attrs)
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   335
            else: Node.__init__(self._mini_dom,tag=tag, attrs=attrs)
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   336
            self._ptr = self._mini_dom
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   337
        elif self.__depth > self._dispatch_depth:
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   338
            self._ptr.kids.append(Node(tag=tag,parent=self._ptr,attrs=attrs))
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   339
            self._ptr = self._ptr.kids[-1]
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   340
        if self.__depth == 1:
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   341
            self._document_attrs = attrs
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   342
            ns, name = (['']+tag.split())[-2:]
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   343
            self.stream_header_received(ns, name, attrs)
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   344
        if not self.last_is_data and self._ptr.parent: self._ptr.parent.data.append('')
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   345
        self.last_is_data = 0
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   346
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   347
    def endtag(self, tag ):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   348
        """XML Parser callback. Used internally"""
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   349
        self.DEBUG(DBG_NODEBUILDER, "DEPTH -> %i , tag -> %s" % (self.__depth, tag), 'up')
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   350
        if self.__depth == self._dispatch_depth:
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   351
            self.dispatch(self._mini_dom)
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   352
        elif self.__depth > self._dispatch_depth:
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   353
            self._ptr = self._ptr.parent
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   354
        else:
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   355
            self.DEBUG(DBG_NODEBUILDER, "Got higher than dispatch level. Stream terminated?", 'stop')
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   356
        self.__depth -= 1
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   357
        self.last_is_data = 0
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   358
        if self.__depth == 0: self.stream_footer_received()
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   359
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   360
    def handle_data(self, data):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   361
        """XML Parser callback. Used internally"""
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   362
        self.DEBUG(DBG_NODEBUILDER, data, 'data')
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   363
        if not self._ptr: return
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   364
        if self.last_is_data:
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   365
            self._ptr.data[-1] += data
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   366
        else:
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   367
            self._ptr.data.append(data)
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   368
            self.last_is_data = 1
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   369
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   370
    def handle_namespace_start(self, prefix, uri):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   371
        """XML Parser callback. Used internally"""
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   372
        if prefix: self.namespaces[uri]=prefix+':'
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   373
        else: self.xmlns=uri
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   374
    def DEBUG(self, level, text, comment=None):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   375
        """ Gets all NodeBuilder walking events. Can be used for debugging if redefined."""
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   376
    def getDom(self):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   377
        """ Returns just built Node. """
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   378
        return self._mini_dom
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   379
    def dispatch(self,stanza):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   380
        """ Gets called when the NodeBuilder reaches some level of depth on it's way up with the built
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   381
            node as argument. Can be redefined to convert incoming XML stanzas to program events. """
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   382
    def stream_header_received(self,ns,tag,attrs):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   383
        """ Method called when stream just opened. """
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   384
    def stream_footer_received(self):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   385
        """ Method called when stream just closed. """
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   386
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   387
def XML2Node(xml):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   388
    """ Converts supplied textual string into XML node. Handy f.e. for reading configuration file.
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   389
        Raises xml.parser.expat.parsererror if provided string is not well-formed XML. """
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   390
    return NodeBuilder(xml).getDom()
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   391
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   392
def BadXML2Node(xml):
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   393
    """ Converts supplied textual string into XML node. Survives if xml data is cutted half way round.
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   394
        I.e. "<html>some text <br>some more text". Will raise xml.parser.expat.parsererror on misplaced
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   395
        tags though. F.e. "<b>some text <br>some more text</b>" will not work."""
93b25987d3e5 Initial Mercurial repository
Mikael Berthe <mikael@lilotux.net>
parents:
diff changeset
   396
    return NodeBuilder(xml).getDom()